PageRenderTime 69ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/erts/emulator/beam/beam_emu.c

http://github.com/mfoemmel/erlang-otp
C | 6118 lines | 4531 code | 655 blank | 932 comment | 860 complexity | 73fedbd6b1989946491589a2370cb943 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 1996-2009. All Rights Reserved.
  5. *
  6. * The contents of this file are subject to the Erlang Public License,
  7. * Version 1.1, (the "License"); you may not use this file except in
  8. * compliance with the License. You should have received a copy of the
  9. * Erlang Public License along with this software. If not, it can be
  10. * retrieved online at http://www.erlang.org/.
  11. *
  12. * Software distributed under the License is distributed on an "AS IS"
  13. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. * the License for the specific language governing rights and limitations
  15. * under the License.
  16. *
  17. * %CopyrightEnd%
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. # include "config.h"
  21. #endif
  22. #include <stddef.h> /* offsetof() */
  23. #include "sys.h"
  24. #include "erl_vm.h"
  25. #include "global.h"
  26. #include "erl_process.h"
  27. #include "erl_nmgc.h"
  28. #include "error.h"
  29. #include "bif.h"
  30. #include "big.h"
  31. #include "beam_load.h"
  32. #include "erl_binary.h"
  33. #include "erl_bits.h"
  34. #include "dist.h"
  35. #include "beam_bp.h"
  36. #include "beam_catches.h"
  37. #ifdef HIPE
  38. #include "hipe_mode_switch.h"
  39. #include "hipe_bif1.h"
  40. #endif
  41. /* #define HARDDEBUG 1 */
  42. #if defined(NO_JUMP_TABLE)
  43. # define OpCase(OpCode) case op_##OpCode: lb_##OpCode
  44. # define CountCase(OpCode) case op_count_##OpCode
  45. # define OpCode(OpCode) ((Uint*)op_##OpCode)
  46. # define Goto(Rel) {Go = (int)(Rel); goto emulator_loop;}
  47. # define LabelAddr(Addr) &&##Addr
  48. #else
  49. # define OpCase(OpCode) lb_##OpCode
  50. # define CountCase(OpCode) lb_count_##OpCode
  51. # define Goto(Rel) goto *(Rel)
  52. # define LabelAddr(Label) &&Label
  53. # define OpCode(OpCode) (&&lb_##OpCode)
  54. #endif
  55. #ifdef ERTS_ENABLE_LOCK_CHECK
  56. # ifdef ERTS_SMP
  57. # define PROCESS_MAIN_CHK_LOCKS(P) \
  58. do { \
  59. if ((P)) { \
  60. erts_pix_lock_t *pix_lock__ = ERTS_PIX2PIXLOCK(internal_pid_index((P)->id));\
  61. erts_proc_lc_chk_only_proc_main((P)); \
  62. erts_pix_lock(pix_lock__); \
  63. ASSERT(0 < (P)->lock.refc && (P)->lock.refc < erts_no_schedulers*5);\
  64. erts_pix_unlock(pix_lock__); \
  65. } \
  66. else \
  67. erts_lc_check_exact(NULL, 0); \
  68. ERTS_SMP_LC_ASSERT(!ERTS_LC_IS_BLOCKING); \
  69. } while (0)
  70. # define ERTS_SMP_REQ_PROC_MAIN_LOCK(P) \
  71. if ((P)) erts_proc_lc_require_lock((P), ERTS_PROC_LOCK_MAIN)
  72. # define ERTS_SMP_UNREQ_PROC_MAIN_LOCK(P) \
  73. if ((P)) erts_proc_lc_unrequire_lock((P), ERTS_PROC_LOCK_MAIN)
  74. # else
  75. # define ERTS_SMP_REQ_PROC_MAIN_LOCK(P)
  76. # define ERTS_SMP_UNREQ_PROC_MAIN_LOCK(P)
  77. # define PROCESS_MAIN_CHK_LOCKS(P) erts_lc_check_exact(NULL, 0)
  78. # endif
  79. #else
  80. # define PROCESS_MAIN_CHK_LOCKS(P)
  81. # define ERTS_SMP_REQ_PROC_MAIN_LOCK(P)
  82. # define ERTS_SMP_UNREQ_PROC_MAIN_LOCK(P)
  83. #endif
  84. /*
  85. * Define macros for deep checking of terms.
  86. */
  87. #if defined(HARDDEBUG)
  88. # define CHECK_TERM(T) size_object(T)
  89. # define CHECK_ARGS(PC) \
  90. do { \
  91. int i_; \
  92. int Arity_ = PC[-1]; \
  93. if (Arity_ > 0) { \
  94. CHECK_TERM(r(0)); \
  95. } \
  96. for (i_ = 1; i_ < Arity_; i_++) { \
  97. CHECK_TERM(x(i_)); \
  98. } \
  99. } while (0)
  100. #else
  101. # define CHECK_TERM(T) ASSERT(!is_CP(T))
  102. # define CHECK_ARGS(T)
  103. #endif
  104. #ifndef MAX
  105. #define MAX(x, y) (((x) > (y)) ? (x) : (y))
  106. #endif
  107. #define GET_BIF_ADDRESS(p) ((BifFunction) (((Export *) p)->code[4]))
  108. /*
  109. * We reuse some of fields in the save area in the process structure.
  110. * This is safe to do, since this space is only activly used when
  111. * the process is switched out.
  112. */
  113. #define REDS_IN(p) ((p)->def_arg_reg[5])
  114. /*
  115. * Add a byte offset to a pointer to Eterm. This is useful when the
  116. * the loader has precalculated a byte offset.
  117. */
  118. #define ADD_BYTE_OFFSET(ptr, offset) \
  119. ((Eterm *) (((unsigned char *)ptr) + (offset)))
  120. /* We don't check the range if an ordinary switch is used */
  121. #ifdef NO_JUMP_TABLE
  122. #define VALID_INSTR(IP) (0 <= (int)(IP) && ((int)(IP) < (NUMBER_OF_OPCODES*2+10)))
  123. #else
  124. #define VALID_INSTR(IP) \
  125. ((Sint)LabelAddr(emulator_loop) <= (Sint)(IP) && \
  126. (Sint)(IP) < (Sint)LabelAddr(end_emulator_loop))
  127. #endif /* NO_JUMP_TABLE */
  128. #define SET_CP(p, ip) \
  129. ASSERT(VALID_INSTR(*(ip))); \
  130. (p)->cp = (ip)
  131. #define SET_I(ip) \
  132. ASSERT(VALID_INSTR(* (Eterm *)(ip))); \
  133. I = (ip)
  134. #define FetchArgs(S1, S2) tmp_arg1 = (S1); tmp_arg2 = (S2)
  135. /*
  136. * Store a result into a register given a destination descriptor.
  137. */
  138. #define StoreResult(Result, DestDesc) \
  139. do { \
  140. Eterm stb_reg; \
  141. stb_reg = (DestDesc); \
  142. CHECK_TERM(Result); \
  143. switch (beam_reg_tag(stb_reg)) { \
  144. case R_REG_DEF: \
  145. r(0) = (Result); break; \
  146. case X_REG_DEF: \
  147. xb(x_reg_offset(stb_reg)) = (Result); break; \
  148. default: \
  149. yb(y_reg_offset(stb_reg)) = (Result); break; \
  150. } \
  151. } while (0)
  152. #define StoreSimpleDest(Src, Dest) Dest = (Src)
  153. /*
  154. * Store a result into a register and execute the next instruction.
  155. * Dst points to the word with a destination descriptor, which MUST
  156. * be just before the next instruction.
  157. */
  158. #define StoreBifResult(Dst, Result) \
  159. do { \
  160. Eterm* stb_next; \
  161. Eterm stb_reg; \
  162. stb_reg = Arg(Dst); \
  163. I += (Dst) + 2; \
  164. stb_next = (Eterm *) *I; \
  165. CHECK_TERM(Result); \
  166. switch (beam_reg_tag(stb_reg)) { \
  167. case R_REG_DEF: \
  168. r(0) = (Result); Goto(stb_next); \
  169. case X_REG_DEF: \
  170. xb(x_reg_offset(stb_reg)) = (Result); Goto(stb_next); \
  171. default: \
  172. yb(y_reg_offset(stb_reg)) = (Result); Goto(stb_next); \
  173. } \
  174. } while (0)
  175. #define ClauseFail() goto lb_jump_f
  176. #define SAVE_CP(X) \
  177. do { \
  178. *(X) = make_cp(c_p->cp); \
  179. c_p->cp = 0; \
  180. } while(0)
  181. #define RESTORE_CP(X) SET_CP(c_p, cp_val(*(X)))
  182. #define ISCATCHEND(instr) ((Eterm *) *(instr) == OpCode(catch_end_y))
  183. /*
  184. * Special Beam instructions.
  185. */
  186. Eterm beam_apply[2];
  187. Eterm beam_exit[1];
  188. Eterm beam_continue_exit[1];
  189. Eterm* em_call_error_handler;
  190. Eterm* em_apply_bif;
  191. Eterm* em_call_traced_function;
  192. /* NOTE These should be the only variables containing trace instructions.
  193. ** Sometimes tests are form the instruction value, and sometimes
  194. ** for the refering variable (one of these), and rouge references
  195. ** will most likely cause chaos.
  196. */
  197. Eterm beam_return_to_trace[1]; /* OpCode(i_return_to_trace) */
  198. Eterm beam_return_trace[1]; /* OpCode(i_return_trace) */
  199. Eterm beam_exception_trace[1]; /* UGLY also OpCode(i_return_trace) */
  200. /*
  201. * All Beam instructions in numerical order.
  202. */
  203. #ifndef NO_JUMP_TABLE
  204. void** beam_ops;
  205. #endif
  206. #ifndef ERTS_SMP /* Not supported with smp emulator */
  207. extern int count_instructions;
  208. #endif
  209. #if defined(HYBRID)
  210. #define SWAPIN \
  211. g_htop = global_htop; \
  212. g_hend = global_hend; \
  213. HTOP = HEAP_TOP(c_p); \
  214. E = c_p->stop
  215. #define SWAPOUT \
  216. global_htop = g_htop; \
  217. global_hend = g_hend; \
  218. HEAP_TOP(c_p) = HTOP; \
  219. c_p->stop = E
  220. #else
  221. #define SWAPIN \
  222. HTOP = HEAP_TOP(c_p); \
  223. E = c_p->stop
  224. #define SWAPOUT \
  225. HEAP_TOP(c_p) = HTOP; \
  226. c_p->stop = E
  227. /*
  228. * Use LIGHT_SWAPOUT when the called function
  229. * will call HeapOnlyAlloc() (and never HAlloc()).
  230. */
  231. #ifdef DEBUG
  232. # /* The stack pointer is used in an assertion. */
  233. # define LIGHT_SWAPOUT SWAPOUT
  234. #else
  235. # define LIGHT_SWAPOUT HEAP_TOP(c_p) = HTOP
  236. #endif
  237. /*
  238. * Use LIGHT_SWAPIN when we know that c_p->stop cannot
  239. * have been updated (i.e. if there cannot have been
  240. * a garbage-collection).
  241. */
  242. #define LIGHT_SWAPIN HTOP = HEAP_TOP(c_p)
  243. #endif
  244. #define PRE_BIF_SWAPOUT(P) \
  245. HEAP_TOP((P)) = HTOP; \
  246. (P)->stop = E; \
  247. PROCESS_MAIN_CHK_LOCKS((P)); \
  248. ERTS_SMP_UNREQ_PROC_MAIN_LOCK((P))
  249. #if defined(HYBRID)
  250. # define POST_BIF_GC_SWAPIN_0(_p, _res) \
  251. if ((_p)->mbuf) { \
  252. _res = erts_gc_after_bif_call((_p), (_res), NULL, 0); \
  253. } \
  254. SWAPIN
  255. # define POST_BIF_GC_SWAPIN(_p, _res, _regs, _arity) \
  256. if ((_p)->mbuf) { \
  257. _regs[0] = r(0); \
  258. _res = erts_gc_after_bif_call((_p), (_res), _regs, (_arity)); \
  259. r(0) = _regs[0]; \
  260. } \
  261. SWAPIN
  262. #else
  263. # define POST_BIF_GC_SWAPIN_0(_p, _res) \
  264. ERTS_SMP_REQ_PROC_MAIN_LOCK((_p)); \
  265. PROCESS_MAIN_CHK_LOCKS((_p)); \
  266. if ((_p)->mbuf) { \
  267. _res = erts_gc_after_bif_call((_p), (_res), NULL, 0); \
  268. E = (_p)->stop; \
  269. } \
  270. HTOP = HEAP_TOP((_p))
  271. # define POST_BIF_GC_SWAPIN(_p, _res, _regs, _arity) \
  272. ERTS_SMP_REQ_PROC_MAIN_LOCK((_p)); \
  273. PROCESS_MAIN_CHK_LOCKS((_p)); \
  274. if ((_p)->mbuf) { \
  275. _regs[0] = r(0); \
  276. _res = erts_gc_after_bif_call((_p), (_res), _regs, (_arity)); \
  277. r(0) = _regs[0]; \
  278. E = (_p)->stop; \
  279. } \
  280. HTOP = HEAP_TOP((_p))
  281. #endif
  282. #define db(N) (N)
  283. #define tb(N) (N)
  284. #define xb(N) (*(Eterm *) (((unsigned char *)reg) + (N)))
  285. #define yb(N) (*(Eterm *) (((unsigned char *)E) + (N)))
  286. #define fb(N) (*(double *) (((unsigned char *)&(freg[0].fd)) + (N)))
  287. #define x(N) reg[N]
  288. #define y(N) E[N]
  289. #define r(N) x##N
  290. /*
  291. * Makes sure that there are StackNeed + HeapNeed + 1 words available
  292. * on the combined heap/stack segment, then allocates StackNeed + 1
  293. * words on the stack and saves CP.
  294. *
  295. * M is number of live registers to preserve during garbage collection
  296. */
  297. #define AH(StackNeed, HeapNeed, M) \
  298. do { \
  299. int needed; \
  300. needed = (StackNeed) + 1; \
  301. if (E - HTOP < (needed + (HeapNeed))) { \
  302. SWAPOUT; \
  303. reg[0] = r(0); \
  304. PROCESS_MAIN_CHK_LOCKS(c_p); \
  305. FCALLS -= erts_garbage_collect(c_p, needed + (HeapNeed), reg, (M)); \
  306. PROCESS_MAIN_CHK_LOCKS(c_p); \
  307. r(0) = reg[0]; \
  308. SWAPIN; \
  309. } \
  310. E -= needed; \
  311. SAVE_CP(E); \
  312. } while (0)
  313. #define Allocate(Ns, Live) AH(Ns, 0, Live)
  314. #define AllocateZero(Ns, Live) \
  315. do { Eterm* ptr; \
  316. int i = (Ns); \
  317. AH(i, 0, Live); \
  318. for (ptr = E + i; ptr > E; ptr--) { \
  319. make_blank(*ptr); \
  320. } \
  321. } while (0)
  322. #define AllocateHeap(Ns, Nh, Live) AH(Ns, Nh, Live)
  323. #define AllocateHeapZero(Ns, Nh, Live) \
  324. do { Eterm* ptr; \
  325. int i = (Ns); \
  326. AH(i, Nh, Live); \
  327. for (ptr = E + i; ptr > E; ptr--) { \
  328. make_blank(*ptr); \
  329. } \
  330. } while (0)
  331. #define AllocateInit(Ns, Live, Y) \
  332. do { AH(Ns, 0, Live); make_blank(Y); } while (0)
  333. /*
  334. * Like the AH macro, but allocates no additional heap space.
  335. */
  336. #define A(StackNeed, M) AH(StackNeed, 0, M)
  337. #define D(N) \
  338. RESTORE_CP(E); \
  339. E += (N) + 1;
  340. /*
  341. * Check if Nh words of heap are available; if not, do a garbage collection.
  342. * Live is number of active argument registers to be preserved.
  343. */
  344. #define TestHeap(Nh, Live) \
  345. do { \
  346. unsigned need = (Nh); \
  347. if (E - HTOP < need) { \
  348. SWAPOUT; \
  349. reg[0] = r(0); \
  350. PROCESS_MAIN_CHK_LOCKS(c_p); \
  351. FCALLS -= erts_garbage_collect(c_p, need, reg, (Live)); \
  352. PROCESS_MAIN_CHK_LOCKS(c_p); \
  353. r(0) = reg[0]; \
  354. SWAPIN; \
  355. } \
  356. } while (0)
  357. /*
  358. * Check if Nh words of heap are available; if not, do a garbage collection.
  359. * Live is number of active argument registers to be preserved.
  360. * Takes special care to preserve Extra if a garbage collection occurs.
  361. */
  362. #define TestHeapPreserve(Nh, Live, Extra) \
  363. do { \
  364. unsigned need = (Nh); \
  365. if (E - HTOP < need) { \
  366. SWAPOUT; \
  367. reg[0] = r(0); \
  368. reg[Live] = Extra; \
  369. PROCESS_MAIN_CHK_LOCKS(c_p); \
  370. FCALLS -= erts_garbage_collect(c_p, need, reg, (Live)+1); \
  371. PROCESS_MAIN_CHK_LOCKS(c_p); \
  372. if (Live > 0) { \
  373. r(0) = reg[0]; \
  374. } \
  375. Extra = reg[Live]; \
  376. SWAPIN; \
  377. } \
  378. } while (0)
  379. #ifdef HYBRID
  380. #ifdef INCREMENTAL
  381. #define TestGlobalHeap(Nh, Live, hp) \
  382. do { \
  383. unsigned need = (Nh); \
  384. ASSERT(global_heap <= g_htop && g_htop <= global_hend); \
  385. SWAPOUT; \
  386. reg[0] = r(0); \
  387. FCALLS -= need; \
  388. (hp) = IncAlloc(c_p,need,reg,(Live)); \
  389. r(0) = reg[0]; \
  390. SWAPIN; \
  391. } while (0)
  392. #else
  393. #define TestGlobalHeap(Nh, Live, hp) \
  394. do { \
  395. unsigned need = (Nh); \
  396. ASSERT(global_heap <= g_htop && g_htop <= global_hend); \
  397. if (g_hend - g_htop < need) { \
  398. SWAPOUT; \
  399. reg[0] = r(0); \
  400. FCALLS -= erts_global_garbage_collect(c_p, need, reg, (Live)); \
  401. r(0) = reg[0]; \
  402. SWAPIN; \
  403. } \
  404. (hp) = global_htop; \
  405. } while (0)
  406. #endif
  407. #endif /* HYBRID */
  408. #define Init(N) make_blank(yb(N))
  409. #define Init2(Y1, Y2) do { make_blank(Y1); make_blank(Y2); } while (0)
  410. #define Init3(Y1, Y2, Y3) \
  411. do { make_blank(Y1); make_blank(Y2); make_blank(Y3); } while (0)
  412. #define MakeFun(FunP, NumFree) \
  413. do { \
  414. SWAPOUT; \
  415. reg[0] = r(0); \
  416. r(0) = new_fun(c_p, reg, (ErlFunEntry *) FunP, NumFree); \
  417. SWAPIN; \
  418. } while (0)
  419. /*
  420. * Check that we haven't used the reductions and jump to function pointed to by
  421. * the I register. If we are out of reductions, do a context switch.
  422. */
  423. #define DispatchMacro() \
  424. do { \
  425. Eterm* dis_next; \
  426. dis_next = (Eterm *) *I; \
  427. CHECK_ARGS(I); \
  428. if (FCALLS > 0 || FCALLS > neg_o_reds) { \
  429. FCALLS--; \
  430. Goto(dis_next); \
  431. } else { \
  432. goto context_switch; \
  433. } \
  434. } while (0)
  435. #define DispatchMacroFun() \
  436. do { \
  437. Eterm* dis_next; \
  438. dis_next = (Eterm *) *I; \
  439. CHECK_ARGS(I); \
  440. if (FCALLS > 0 || FCALLS > neg_o_reds) { \
  441. FCALLS--; \
  442. Goto(dis_next); \
  443. } else { \
  444. goto context_switch_fun; \
  445. } \
  446. } while (0)
  447. #define DispatchMacrox() \
  448. do { \
  449. if (FCALLS > 0) { \
  450. Eterm* dis_next; \
  451. SET_I(((Export *) Arg(0))->address); \
  452. dis_next = (Eterm *) *I; \
  453. FCALLS--; \
  454. CHECK_ARGS(I); \
  455. Goto(dis_next); \
  456. } else if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p) \
  457. && FCALLS > neg_o_reds) { \
  458. goto save_calls1; \
  459. } else { \
  460. SET_I(((Export *) Arg(0))->address); \
  461. CHECK_ARGS(I); \
  462. goto context_switch; \
  463. } \
  464. } while (0)
  465. #ifdef DEBUG
  466. /*
  467. * To simplify breakpoint setting, put the code in one place only and jump to it.
  468. */
  469. # define Dispatch() goto do_dispatch
  470. # define Dispatchx() goto do_dispatchx
  471. # define Dispatchfun() goto do_dispatchfun
  472. #else
  473. /*
  474. * Inline for speed.
  475. */
  476. # define Dispatch() DispatchMacro()
  477. # define Dispatchx() DispatchMacrox()
  478. # define Dispatchfun() DispatchMacroFun()
  479. #endif
  480. #define Self(R) R = c_p->id
  481. #define Node(R) R = erts_this_node->sysname
  482. #define Arg(N) I[(N)+1]
  483. #define Next(N) \
  484. I += (N) + 1; \
  485. ASSERT(VALID_INSTR(*I)); \
  486. Goto(*I)
  487. #define PreFetch(N, Dst) do { Dst = (Eterm *) *(I + N + 1); } while (0)
  488. #define NextPF(N, Dst) \
  489. I += N + 1; \
  490. ASSERT(VALID_INSTR(Dst)); \
  491. Goto(Dst)
  492. #define GetR(pos, tr) \
  493. do { \
  494. tr = Arg(pos); \
  495. switch (beam_reg_tag(tr)) { \
  496. case R_REG_DEF: tr = r(0); break; \
  497. case X_REG_DEF: tr = xb(x_reg_offset(tr)); break; \
  498. case Y_REG_DEF: ASSERT(y_reg_offset(tr) >= 1); tr = yb(y_reg_offset(tr)); break; \
  499. } \
  500. CHECK_TERM(tr); \
  501. } while (0)
  502. #define GetArg1(N, Dst) GetR((N), Dst)
  503. #define GetArg2(N, Dst1, Dst2) \
  504. do { \
  505. GetR(N, Dst1); \
  506. GetR((N)+1, Dst2); \
  507. } while (0)
  508. #define PutList(H, T, Dst, Store) \
  509. do { \
  510. HTOP[0] = (H); HTOP[1] = (T); \
  511. Store(make_list(HTOP), Dst); \
  512. HTOP += 2; \
  513. } while (0)
  514. #define Move(Src, Dst, Store) \
  515. do { \
  516. Eterm term = (Src); \
  517. Store(term, Dst); \
  518. } while (0)
  519. #define Move2(src1, dst1, src2, dst2) dst1 = (src1); dst2 = (src2)
  520. #define MoveGenDest(src, dstp) \
  521. if ((dstp) == NULL) { r(0) = (src); } else { *(dstp) = src; }
  522. #define MoveReturn(Src, Dest) \
  523. (Dest) = (Src); \
  524. I = c_p->cp; \
  525. ASSERT(VALID_INSTR(*c_p->cp)); \
  526. c_p->cp = 0; \
  527. CHECK_TERM(r(0)); \
  528. Goto(*I)
  529. #define DeallocateReturn(Deallocate) \
  530. do { \
  531. int words_to_pop = (Deallocate); \
  532. SET_I(cp_val(*E)); \
  533. E = ADD_BYTE_OFFSET(E, words_to_pop); \
  534. CHECK_TERM(r(0)); \
  535. Goto(*I); \
  536. } while (0)
  537. #define MoveDeallocateReturn(Src, Dest, Deallocate) \
  538. (Dest) = (Src); \
  539. DeallocateReturn(Deallocate)
  540. #define MoveCall(Src, Dest, CallDest, Size) \
  541. (Dest) = (Src); \
  542. SET_CP(c_p, I+Size+1); \
  543. SET_I((Eterm *) CallDest); \
  544. Dispatch();
  545. #define MoveCallLast(Src, Dest, CallDest, Deallocate) \
  546. (Dest) = (Src); \
  547. RESTORE_CP(E); \
  548. E = ADD_BYTE_OFFSET(E, (Deallocate)); \
  549. SET_I((Eterm *) CallDest); \
  550. Dispatch();
  551. #define MoveCallOnly(Src, Dest, CallDest) \
  552. (Dest) = (Src); \
  553. SET_I((Eterm *) CallDest); \
  554. Dispatch();
  555. #define GetList(Src, H, T) do { \
  556. Eterm* tmp_ptr = list_val(Src); \
  557. H = CAR(tmp_ptr); \
  558. T = CDR(tmp_ptr); } while (0)
  559. #define GetTupleElement(Src, Element, Dest) \
  560. do { \
  561. tmp_arg1 = (Eterm) (((unsigned char *) tuple_val(Src)) + (Element)); \
  562. (Dest) = (*(Eterm *)tmp_arg1); \
  563. } while (0)
  564. #define ExtractNextElement(Dest) \
  565. tmp_arg1 += sizeof(Eterm); \
  566. (Dest) = (* (Eterm *) (((unsigned char *) tmp_arg1)))
  567. #define ExtractNextElement2(Dest) \
  568. do { \
  569. Eterm* ene_dstp = &(Dest); \
  570. ene_dstp[0] = ((Eterm *) tmp_arg1)[1]; \
  571. ene_dstp[1] = ((Eterm *) tmp_arg1)[2]; \
  572. tmp_arg1 += sizeof(Eterm) + sizeof(Eterm); \
  573. } while (0)
  574. #define ExtractNextElement3(Dest) \
  575. do { \
  576. Eterm* ene_dstp = &(Dest); \
  577. ene_dstp[0] = ((Eterm *) tmp_arg1)[1]; \
  578. ene_dstp[1] = ((Eterm *) tmp_arg1)[2]; \
  579. ene_dstp[2] = ((Eterm *) tmp_arg1)[3]; \
  580. tmp_arg1 += 3*sizeof(Eterm); \
  581. } while (0)
  582. #define ExtractNextElement4(Dest) \
  583. do { \
  584. Eterm* ene_dstp = &(Dest); \
  585. ene_dstp[0] = ((Eterm *) tmp_arg1)[1]; \
  586. ene_dstp[1] = ((Eterm *) tmp_arg1)[2]; \
  587. ene_dstp[2] = ((Eterm *) tmp_arg1)[3]; \
  588. ene_dstp[3] = ((Eterm *) tmp_arg1)[4]; \
  589. tmp_arg1 += 4*sizeof(Eterm); \
  590. } while (0)
  591. #define ExtractElement(Element, Dest) \
  592. do { \
  593. tmp_arg1 += (Element); \
  594. (Dest) = (* (Eterm *) tmp_arg1); \
  595. } while (0)
  596. #define PutTuple(Arity, Src, Dest) \
  597. ASSERT(is_arity_value(Arity)); \
  598. Dest = make_tuple(HTOP); \
  599. HTOP[0] = (Arity); \
  600. HTOP[1] = (Src); \
  601. HTOP += 2
  602. #define Put(Word) *HTOP++ = (Word)
  603. #define EqualImmed(X, Y, Action) if (X != Y) { Action; }
  604. #define IsFloat(Src, Fail) if (is_not_float(Src)) { Fail; }
  605. #define IsInteger(Src, Fail) if (is_not_integer(Src)) { Fail; }
  606. #define IsNumber(X, Fail) if (is_not_integer(X) && is_not_float(X)) { Fail; }
  607. #define IsAtom(Src, Fail) if (is_not_atom(Src)) { Fail; }
  608. #define IsIntegerAllocate(Src, Need, Alive, Fail) \
  609. if (is_not_integer(Src)) { Fail; } \
  610. A(Need, Alive)
  611. #define IsNil(Src, Fail) if (is_not_nil(Src)) { Fail; }
  612. #define IsList(Src, Fail) if (is_not_list(Src) && is_not_nil(Src)) { Fail; }
  613. #define IsNonemptyList(Src, Fail) if (is_not_list(Src)) { Fail; }
  614. #define IsNonemptyListAllocate(Src, Need, Alive, Fail) \
  615. if (is_not_list(Src)) { Fail; } \
  616. A(Need, Alive)
  617. #define IsNonemptyListTestHeap(Src, Need, Alive, Fail) \
  618. if (is_not_list(Src)) { Fail; } \
  619. TestHeap(Need, Alive)
  620. #define IsTuple(X, Action) if (is_not_tuple(X)) Action
  621. #define IsArity(Pointer, Arity, Fail) \
  622. if (*(Eterm *)(tmp_arg1 = (Eterm)tuple_val(Pointer)) != (Arity)) { Fail; }
  623. #define IsFunction(X, Action) \
  624. do { \
  625. if ( !(is_any_fun(X)) ) { \
  626. Action; \
  627. } \
  628. } while (0)
  629. #define IsFunction2(F, A, Action) \
  630. do { \
  631. if (is_function_2(c_p, F, A) != am_true ) {\
  632. Action; \
  633. } \
  634. } while (0)
  635. #define IsTupleOfArity(Src, Arity, Fail) \
  636. do { \
  637. if (is_not_tuple(Src) || *(Eterm *)(tmp_arg1 = (Eterm) tuple_val(Src)) != Arity) { \
  638. Fail; \
  639. } \
  640. } while (0)
  641. #define IsBoolean(X, Fail) if ((X) != am_true && (X) != am_false) { Fail; }
  642. #define IsBinary(Src, Fail) \
  643. if (is_not_binary(Src) || binary_bitsize(Src) != 0) { Fail; }
  644. #define IsBitstring(Src, Fail) \
  645. if (is_not_binary(Src)) { Fail; }
  646. #ifdef ARCH_64
  647. #define BsSafeMul(A, B, Fail, Target) \
  648. do { Uint64 _res = (A) * (B); \
  649. if (_res / B != A) { Fail; } \
  650. Target = _res; \
  651. } while (0)
  652. #else
  653. #define BsSafeMul(A, B, Fail, Target) \
  654. do { Uint64 _res = (Uint64)(A) * (Uint64)(B); \
  655. if ((_res >> (8*sizeof(Uint))) != 0) { Fail; } \
  656. Target = _res; \
  657. } while (0)
  658. #endif
  659. #define BsGetFieldSize(Bits, Unit, Fail, Target) \
  660. do { \
  661. Sint _signed_size; Uint _uint_size; \
  662. if (is_small(Bits)) { \
  663. _signed_size = signed_val(Bits); \
  664. if (_signed_size < 0) { Fail; } \
  665. _uint_size = (Uint) _signed_size; \
  666. } else { \
  667. if (!term_to_Uint(Bits, &temp_bits)) { Fail; } \
  668. _uint_size = temp_bits; \
  669. } \
  670. BsSafeMul(_uint_size, Unit, Fail, Target); \
  671. } while (0)
  672. #define BsGetUncheckedFieldSize(Bits, Unit, Fail, Target) \
  673. do { \
  674. Sint _signed_size; Uint _uint_size; \
  675. if (is_small(Bits)) { \
  676. _signed_size = signed_val(Bits); \
  677. if (_signed_size < 0) { Fail; } \
  678. _uint_size = (Uint) _signed_size; \
  679. } else { \
  680. if (!term_to_Uint(Bits, &temp_bits)) { Fail; } \
  681. _uint_size = (Uint) temp_bits; \
  682. } \
  683. Target = _uint_size * Unit; \
  684. } while (0)
  685. #define BsGetFloat2(Ms, Live, Sz, Flags, Dst, Store, Fail) \
  686. do { \
  687. ErlBinMatchBuffer *_mb; \
  688. Eterm _result; Sint _size; \
  689. if (!is_small(Sz) || (_size = unsigned_val(Sz)) > 64) { Fail; } \
  690. _size *= ((Flags) >> 3); \
  691. TestHeap(FLOAT_SIZE_OBJECT, Live); \
  692. _mb = ms_matchbuffer(Ms); \
  693. LIGHT_SWAPOUT; \
  694. _result = erts_bs_get_float_2(c_p, _size, (Flags), _mb); \
  695. LIGHT_SWAPIN; \
  696. if (is_non_value(_result)) { Fail; } \
  697. else { Store(_result, Dst); } \
  698. } while (0)
  699. #define BsGetBinaryImm_2(Ms, Live, Sz, Flags, Dst, Store, Fail) \
  700. do { \
  701. ErlBinMatchBuffer *_mb; \
  702. Eterm _result; \
  703. TestHeap(heap_bin_size(ERL_ONHEAP_BIN_LIMIT), Live); \
  704. _mb = ms_matchbuffer(Ms); \
  705. LIGHT_SWAPOUT; \
  706. _result = erts_bs_get_binary_2(c_p, (Sz), (Flags), _mb); \
  707. LIGHT_SWAPIN; \
  708. if (is_non_value(_result)) { Fail; } \
  709. else { Store(_result, Dst); } \
  710. } while (0)
  711. #define BsGetBinary_2(Ms, Live, Sz, Flags, Dst, Store, Fail) \
  712. do { \
  713. ErlBinMatchBuffer *_mb; \
  714. Eterm _result; Uint _size; \
  715. BsGetFieldSize(Sz, ((Flags) >> 3), Fail, _size); \
  716. TestHeap(ERL_SUB_BIN_SIZE, Live); \
  717. _mb = ms_matchbuffer(Ms); \
  718. LIGHT_SWAPOUT; \
  719. _result = erts_bs_get_binary_2(c_p, _size, (Flags), _mb); \
  720. LIGHT_SWAPIN; \
  721. if (is_non_value(_result)) { Fail; } \
  722. else { Store(_result, Dst); } \
  723. } while (0)
  724. #define BsGetBinaryAll_2(Ms, Live, Unit, Dst, Store, Fail) \
  725. do { \
  726. ErlBinMatchBuffer *_mb; \
  727. Eterm _result; \
  728. TestHeap(ERL_SUB_BIN_SIZE, Live); \
  729. _mb = ms_matchbuffer(Ms); \
  730. if (((_mb->size - _mb->offset) % Unit) == 0) { \
  731. LIGHT_SWAPOUT; \
  732. _result = erts_bs_get_binary_all_2(c_p, _mb); \
  733. LIGHT_SWAPIN; \
  734. ASSERT(is_value(_result)); \
  735. Store(_result, Dst); \
  736. } else { Fail; } \
  737. } while (0)
  738. #define BsSkipBits2(Ms, Bits, Unit, Fail) \
  739. do { \
  740. ErlBinMatchBuffer *_mb; \
  741. size_t new_offset; \
  742. Uint _size; \
  743. _mb = ms_matchbuffer(Ms); \
  744. BsGetFieldSize(Bits, Unit, Fail, _size); \
  745. new_offset = _mb->offset + _size; \
  746. if (new_offset <= _mb->size) { _mb->offset = new_offset; } \
  747. else { Fail; } \
  748. } while (0)
  749. #define BsSkipBitsAll2(Ms, Unit, Fail) \
  750. do { \
  751. ErlBinMatchBuffer *_mb; \
  752. _mb = ms_matchbuffer(Ms); \
  753. if (((_mb->size - _mb->offset) % Unit) == 0) {_mb->offset = _mb->size; } \
  754. else { Fail; } \
  755. } while (0)
  756. #define BsSkipBitsImm2(Ms, Bits, Fail) \
  757. do { \
  758. ErlBinMatchBuffer *_mb; \
  759. size_t new_offset; \
  760. _mb = ms_matchbuffer(Ms); \
  761. new_offset = _mb->offset + (Bits); \
  762. if (new_offset <= _mb->size) { _mb->offset = new_offset; } \
  763. else { Fail; } \
  764. } while (0)
  765. #define NewBsPutIntegerImm(Sz, Flags, Src) \
  766. do { \
  767. if (!erts_new_bs_put_integer(ERL_BITS_ARGS_3((Src), (Sz), (Flags)))) { goto badarg; } \
  768. } while (0)
  769. #define NewBsPutInteger(Sz, Flags, Src) \
  770. do { \
  771. Sint _size; \
  772. BsGetUncheckedFieldSize(Sz, ((Flags) >> 3), goto badarg, _size); \
  773. if (!erts_new_bs_put_integer(ERL_BITS_ARGS_3((Src), _size, (Flags)))) \
  774. { goto badarg; } \
  775. } while (0)
  776. #define NewBsPutFloatImm(Sz, Flags, Src) \
  777. do { \
  778. if (!erts_new_bs_put_float(c_p, (Src), (Sz), (Flags))) { goto badarg; } \
  779. } while (0)
  780. #define NewBsPutFloat(Sz, Flags, Src) \
  781. do { \
  782. Sint _size; \
  783. BsGetUncheckedFieldSize(Sz, ((Flags) >> 3), goto badarg, _size); \
  784. if (!erts_new_bs_put_float(c_p, (Src), _size, (Flags))) { goto badarg; } \
  785. } while (0)
  786. #define NewBsPutBinary(Sz, Flags, Src) \
  787. do { \
  788. Sint _size; \
  789. BsGetUncheckedFieldSize(Sz, ((Flags) >> 3), goto badarg, _size); \
  790. if (!erts_new_bs_put_binary(ERL_BITS_ARGS_2((Src), _size))) { goto badarg; } \
  791. } while (0)
  792. #define NewBsPutBinaryImm(Sz, Src) \
  793. do { \
  794. if (!erts_new_bs_put_binary(ERL_BITS_ARGS_2((Src), (Sz)))) { goto badarg; } \
  795. } while (0)
  796. #define NewBsPutBinaryAll(Src, Unit) \
  797. do { \
  798. if (!erts_new_bs_put_binary_all(ERL_BITS_ARGS_2((Src), (Unit)))) { goto badarg; } \
  799. } while (0)
  800. #define IsPort(Src, Fail) if (is_not_port(Src)) { Fail; }
  801. #define IsPid(Src, Fail) if (is_not_pid(Src)) { Fail; }
  802. #define IsRef(Src, Fail) if (is_not_ref(Src)) { Fail; }
  803. static BifFunction translate_gc_bif(void* gcf);
  804. static Eterm* handle_error(Process* c_p, Eterm* pc, Eterm* reg, BifFunction bf);
  805. static Eterm* next_catch(Process* c_p, Eterm *reg);
  806. static void terminate_proc(Process* c_p, Eterm Value);
  807. static Eterm add_stacktrace(Process* c_p, Eterm Value, Eterm exc);
  808. static void save_stacktrace(Process* c_p, Eterm* pc, Eterm* reg,
  809. BifFunction bf, Eterm args);
  810. static struct StackTrace * get_trace_from_exc(Eterm exc);
  811. static Eterm make_arglist(Process* c_p, Eterm* reg, int a);
  812. static Eterm call_error_handler(Process* p, Eterm* ip, Eterm* reg);
  813. static Eterm call_breakpoint_handler(Process* p, Eterm* fi, Eterm* reg);
  814. static Uint* fixed_apply(Process* p, Eterm* reg, Uint arity);
  815. static Eterm* apply(Process* p, Eterm module, Eterm function,
  816. Eterm args, Eterm* reg);
  817. static int hibernate(Process* c_p, Eterm module, Eterm function,
  818. Eterm args, Eterm* reg);
  819. static Eterm* call_fun(Process* p, int arity, Eterm* reg, Eterm args);
  820. static Eterm* apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg);
  821. static Eterm new_fun(Process* p, Eterm* reg, ErlFunEntry* fe, int num_free);
  822. #if defined(_OSE_) || defined(VXWORKS)
  823. static int init_done;
  824. #endif
  825. void
  826. init_emulator(void)
  827. {
  828. #if defined(_OSE_) || defined(VXWORKS)
  829. init_done = 0;
  830. #endif
  831. process_main();
  832. }
  833. /*
  834. * On certain platforms, make sure that the main variables really are placed
  835. * in registers.
  836. */
  837. #if defined(__GNUC__) && defined(sparc) && !defined(DEBUG)
  838. # define REG_x0 asm("%l0")
  839. # define REG_xregs asm("%l1")
  840. # define REG_htop asm("%l2")
  841. # define REG_stop asm("%l3")
  842. # define REG_I asm("%l4")
  843. # define REG_fcalls asm("%l5")
  844. # define REG_tmp_arg1 asm("%l6")
  845. # define REG_tmp_arg2 asm("%l7")
  846. #else
  847. # define REG_x0
  848. # define REG_xregs
  849. # define REG_htop
  850. # define REG_stop
  851. # define REG_I
  852. # define REG_fcalls
  853. # define REG_tmp_arg1
  854. # define REG_tmp_arg2
  855. #endif
  856. /*
  857. * process_main() is called twice:
  858. * The first call performs some initialisation, including exporting
  859. * the instructions' C labels to the loader.
  860. * The second call starts execution of BEAM code. This call never returns.
  861. */
  862. void process_main(void)
  863. {
  864. #if !defined(_OSE_) && !defined(VXWORKS)
  865. static int init_done = 0;
  866. #endif
  867. Process* c_p = NULL;
  868. int reds_used;
  869. #ifdef DEBUG
  870. Eterm pid;
  871. #endif
  872. /*
  873. * X register zero; also called r(0)
  874. */
  875. register Eterm x0 REG_x0 = NIL;
  876. /* Pointer to X registers: x(1)..x(N); reg[0] is used when doing GC,
  877. * in all other cases x0 is used.
  878. */
  879. register Eterm* reg REG_xregs = NULL;
  880. /*
  881. * Top of heap (next free location); grows upwards.
  882. */
  883. register Eterm* HTOP REG_htop = NULL;
  884. #ifdef HYBRID
  885. Eterm *g_htop;
  886. Eterm *g_hend;
  887. #endif
  888. /* Stack pointer. Grows downwards; points
  889. * to last item pushed (normally a saved
  890. * continuation pointer).
  891. */
  892. register Eterm* E REG_stop = NULL;
  893. /*
  894. * Pointer to next threaded instruction.
  895. */
  896. register Eterm *I REG_I = NULL;
  897. /* Number of reductions left. This function
  898. * returns to the scheduler when FCALLS reaches zero.
  899. */
  900. register Sint FCALLS REG_fcalls = 0;
  901. /*
  902. * Temporaries used for picking up arguments for instructions.
  903. */
  904. register Eterm tmp_arg1 REG_tmp_arg1 = NIL;
  905. register Eterm tmp_arg2 REG_tmp_arg2 = NIL;
  906. Eterm tmp_big[2]; /* Temporary buffer for small bignums. */
  907. #ifndef ERTS_SMP
  908. static Eterm save_reg[ERTS_X_REGS_ALLOCATED];
  909. /* X registers -- not used directly, but
  910. * through 'reg', because using it directly
  911. * needs two instructions on a SPARC,
  912. * while using it through reg needs only
  913. * one.
  914. */
  915. /*
  916. * Floating point registers.
  917. */
  918. static FloatDef freg[MAX_REG];
  919. #else
  920. /* X regisers and floating point registers are located in
  921. * scheduler specific data.
  922. */
  923. register FloatDef *freg;
  924. #endif
  925. /*
  926. * For keeping the negative old value of 'reds' when call saving is active.
  927. */
  928. int neg_o_reds = 0;
  929. Eterm (*arith_func)(Process* p, Eterm* reg, Uint live);
  930. #ifndef NO_JUMP_TABLE
  931. static void* opcodes[] = { DEFINE_OPCODES };
  932. #ifdef ERTS_OPCODE_COUNTER_SUPPORT
  933. static void* counting_opcodes[] = { DEFINE_COUNTING_OPCODES };
  934. #endif
  935. #else
  936. int Go;
  937. #endif
  938. Uint temp_bits; /* Temporary used by BsSkipBits2 & BsGetInteger2 */
  939. ERL_BITS_DECLARE_STATEP; /* Has to be last declaration */
  940. /*
  941. * Note: In this function, we attempt to place rarely executed code towards
  942. * the end of the function, in the hope that the cache hit rate will be better.
  943. * The initialization code is only run once, so it is at the very end.
  944. *
  945. * Note: c_p->arity must be set to reflect the number of useful terms in
  946. * c_p->arg_reg before calling the scheduler.
  947. */
  948. if (!init_done) {
  949. init_done = 1;
  950. goto init_emulator;
  951. }
  952. #ifndef ERTS_SMP
  953. reg = save_reg; /* XXX: probably wastes a register on x86 */
  954. #endif
  955. c_p = NULL;
  956. reds_used = 0;
  957. goto do_schedule1;
  958. do_schedule:
  959. reds_used = REDS_IN(c_p) - FCALLS;
  960. do_schedule1:
  961. PROCESS_MAIN_CHK_LOCKS(c_p);
  962. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  963. c_p = schedule(c_p, reds_used);
  964. #ifdef DEBUG
  965. pid = c_p->id;
  966. #endif
  967. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  968. PROCESS_MAIN_CHK_LOCKS(c_p);
  969. #ifdef ERTS_SMP
  970. reg = c_p->scheduler_data->save_reg;
  971. freg = c_p->scheduler_data->freg;
  972. #endif
  973. ERL_BITS_RELOAD_STATEP(c_p);
  974. {
  975. int reds;
  976. Eterm* argp;
  977. Eterm* next;
  978. int i;
  979. argp = c_p->arg_reg;
  980. for (i = c_p->arity - 1; i > 0; i--) {
  981. reg[i] = argp[i];
  982. CHECK_TERM(reg[i]);
  983. }
  984. /*
  985. * We put the original reduction count in the process structure, to reduce
  986. * the code size (referencing a field in a struct through a pointer stored
  987. * in a register gives smaller code than referencing a global variable).
  988. */
  989. SET_I(c_p->i);
  990. reds = c_p->fcalls;
  991. if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)
  992. && (c_p->trace_flags & F_SENSITIVE) == 0) {
  993. neg_o_reds = -reds;
  994. FCALLS = REDS_IN(c_p) = 0;
  995. } else {
  996. neg_o_reds = 0;
  997. FCALLS = REDS_IN(c_p) = reds;
  998. }
  999. next = (Eterm *) *I;
  1000. r(0) = c_p->arg_reg[0];
  1001. #ifdef HARDDEBUG
  1002. if (c_p->arity > 0) {
  1003. CHECK_TERM(r(0));
  1004. }
  1005. #endif
  1006. SWAPIN;
  1007. ASSERT(VALID_INSTR(next));
  1008. Goto(next);
  1009. }
  1010. #if defined(DEBUG) || defined(NO_JUMP_TABLE)
  1011. emulator_loop:
  1012. #endif
  1013. #ifdef NO_JUMP_TABLE
  1014. switch (Go) {
  1015. #endif
  1016. #include "beam_hot.h"
  1017. #define STORE_ARITH_RESULT(res) StoreBifResult(2, (res));
  1018. #define ARITH_FUNC(name) erts_gc_##name
  1019. OpCase(i_plus_jId):
  1020. {
  1021. Eterm result;
  1022. if (is_both_small(tmp_arg1, tmp_arg2)) {
  1023. Sint i = signed_val(tmp_arg1) + signed_val(tmp_arg2);
  1024. ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i));
  1025. if (MY_IS_SSMALL(i)) {
  1026. result = make_small(i);
  1027. STORE_ARITH_RESULT(result);
  1028. }
  1029. }
  1030. arith_func = ARITH_FUNC(mixed_plus);
  1031. goto do_big_arith2;
  1032. }
  1033. OpCase(i_minus_jId):
  1034. {
  1035. Eterm result;
  1036. if (is_both_small(tmp_arg1, tmp_arg2)) {
  1037. Sint i = signed_val(tmp_arg1) - signed_val(tmp_arg2);
  1038. ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i));
  1039. if (MY_IS_SSMALL(i)) {
  1040. result = make_small(i);
  1041. STORE_ARITH_RESULT(result);
  1042. }
  1043. }
  1044. arith_func = ARITH_FUNC(mixed_minus);
  1045. goto do_big_arith2;
  1046. }
  1047. OpCase(i_is_lt_f):
  1048. if (CMP_GE(tmp_arg1, tmp_arg2)) {
  1049. ClauseFail();
  1050. }
  1051. Next(1);
  1052. OpCase(i_is_ge_f):
  1053. if (CMP_LT(tmp_arg1, tmp_arg2)) {
  1054. ClauseFail();
  1055. }
  1056. Next(1);
  1057. OpCase(i_is_eq_f):
  1058. if (CMP_NE(tmp_arg1, tmp_arg2)) {
  1059. ClauseFail();
  1060. }
  1061. Next(1);
  1062. OpCase(i_is_ne_f):
  1063. if (CMP_EQ(tmp_arg1, tmp_arg2)) {
  1064. ClauseFail();
  1065. }
  1066. Next(1);
  1067. OpCase(i_is_eq_exact_f):
  1068. if (!EQ(tmp_arg1, tmp_arg2)) {
  1069. ClauseFail();
  1070. }
  1071. Next(1);
  1072. OpCase(i_move_call_only_fcr): {
  1073. r(0) = Arg(1);
  1074. }
  1075. /* FALL THROUGH */
  1076. OpCase(i_call_only_f): {
  1077. SET_I((Eterm *) Arg(0));
  1078. Dispatch();
  1079. }
  1080. OpCase(i_move_call_last_fPcr): {
  1081. r(0) = Arg(2);
  1082. }
  1083. /* FALL THROUGH */
  1084. OpCase(i_call_last_fP): {
  1085. RESTORE_CP(E);
  1086. E = ADD_BYTE_OFFSET(E, Arg(1));
  1087. SET_I((Eterm *) Arg(0));
  1088. Dispatch();
  1089. }
  1090. OpCase(i_move_call_crf): {
  1091. r(0) = Arg(0);
  1092. I++;
  1093. }
  1094. /* FALL THROUGH */
  1095. OpCase(i_call_f): {
  1096. SET_CP(c_p, I+2);
  1097. SET_I((Eterm *) Arg(0));
  1098. Dispatch();
  1099. }
  1100. OpCase(i_move_call_ext_last_ePcr): {
  1101. r(0) = Arg(2);
  1102. }
  1103. /* FALL THROUGH */
  1104. OpCase(i_call_ext_last_eP):
  1105. RESTORE_CP(E);
  1106. E = ADD_BYTE_OFFSET(E, Arg(1));
  1107. /*
  1108. * Note: The pointer to the export entry is never NULL; if the module
  1109. * is not loaded, it points to code which will invoke the error handler
  1110. * (see lb_call_error_handler below).
  1111. */
  1112. Dispatchx();
  1113. OpCase(i_move_call_ext_cre): {
  1114. r(0) = Arg(0);
  1115. I++;
  1116. }
  1117. /* FALL THROUGH */
  1118. OpCase(i_call_ext_e):
  1119. SET_CP(c_p, I+2);
  1120. Dispatchx();
  1121. OpCase(i_move_call_ext_only_ecr): {
  1122. r(0) = Arg(1);
  1123. }
  1124. /* FALL THROUGH */
  1125. OpCase(i_call_ext_only_e):
  1126. Dispatchx();
  1127. OpCase(init_y): {
  1128. Eterm* next;
  1129. PreFetch(1, next);
  1130. make_blank(yb(Arg(0)));
  1131. NextPF(1, next);
  1132. }
  1133. OpCase(i_trim_I): {
  1134. Eterm* next;
  1135. Uint words;
  1136. Uint cp;
  1137. words = Arg(0);
  1138. cp = E[0];
  1139. PreFetch(1, next);
  1140. E += words;
  1141. E[0] = cp;
  1142. NextPF(1, next);
  1143. }
  1144. OpCase(return): {
  1145. SET_I(c_p->cp);
  1146. /*
  1147. * We must clear the CP to make sure that a stale value do not
  1148. * create a false module dependcy preventing code upgrading.
  1149. * It also means that we can use the CP in stack backtraces.
  1150. */
  1151. c_p->cp = 0;
  1152. CHECK_TERM(r(0));
  1153. Goto(*I);
  1154. }
  1155. OpCase(test_heap_1_put_list_Iy): {
  1156. Eterm* next;
  1157. PreFetch(2, next);
  1158. TestHeap(Arg(0), 1);
  1159. PutList(yb(Arg(1)), r(0), r(0), StoreSimpleDest);
  1160. CHECK_TERM(r(0));
  1161. NextPF(2, next);
  1162. }
  1163. OpCase(put_string_IId):
  1164. {
  1165. unsigned char* s;
  1166. int len;
  1167. Eterm result;
  1168. len = Arg(0); /* Length. */
  1169. result = NIL;
  1170. for (s = (unsigned char *) Arg(1); len > 0; s--, len--) {
  1171. PutList(make_small(*s), result, result, StoreSimpleDest);
  1172. }
  1173. StoreBifResult(2, result);
  1174. }
  1175. /*
  1176. * Send is almost a standard call-BIF with two arguments, except for:
  1177. * 1) It cannot be traced.
  1178. * 2) There is no pointer to the send_2 function stored in
  1179. * the instruction.
  1180. */
  1181. OpCase(send): {
  1182. Eterm* next;
  1183. Eterm result;
  1184. PRE_BIF_SWAPOUT(c_p);
  1185. c_p->fcalls = FCALLS - 1;
  1186. result = send_2(c_p, r(0), x(1));
  1187. PreFetch(0, next);
  1188. POST_BIF_GC_SWAPIN(c_p, result, reg, 2);
  1189. FCALLS = c_p->fcalls;
  1190. if (is_value(result)) {
  1191. r(0) = result;
  1192. CHECK_TERM(r(0));
  1193. NextPF(0, next);
  1194. } else if (c_p->freason == TRAP) {
  1195. SET_CP(c_p, I+1);
  1196. SET_I(((Export *)(c_p->def_arg_reg[3]))->address);
  1197. SWAPIN;
  1198. r(0) = c_p->def_arg_reg[0];
  1199. x(1) = c_p->def_arg_reg[1];
  1200. Dispatch();
  1201. }
  1202. goto find_func_info;
  1203. }
  1204. OpCase(i_element_jssd): {
  1205. Eterm index;
  1206. Eterm tuple;
  1207. /*
  1208. * Inlined version of element/2 for speed.
  1209. */
  1210. GetArg2(1, index, tuple);
  1211. if (is_small(index) && is_tuple(tuple)) {
  1212. Eterm* tp = tuple_val(tuple);
  1213. if ((signed_val(index) >= 1) &&
  1214. (signed_val(index) <= arityval(*tp))) {
  1215. Eterm result = tp[signed_val(index)];
  1216. StoreBifResult(3, result);
  1217. }
  1218. }
  1219. }
  1220. /* Fall through */
  1221. OpCase(badarg_j):
  1222. badarg:
  1223. c_p->freason = BADARG;
  1224. goto lb_Cl_error;
  1225. OpCase(i_fast_element_jIsd): {
  1226. Eterm tuple;
  1227. /*
  1228. * Inlined version of element/2 for even more speed.
  1229. * The first argument is an untagged integer >= 1.
  1230. * The second argument is guaranteed to be a register operand.
  1231. */
  1232. GetArg1(2, tuple);
  1233. if (is_tuple(tuple)) {
  1234. Eterm* tp = tuple_val(tuple);
  1235. tmp_arg2 = Arg(1);
  1236. if (tmp_arg2 <= arityval(*tp)) {
  1237. Eterm result = tp[tmp_arg2];
  1238. StoreBifResult(3, result);
  1239. }
  1240. }
  1241. goto badarg;
  1242. }
  1243. OpCase(catch_yf):
  1244. c_p->catches++;
  1245. yb(Arg(0)) = Arg(1);
  1246. Next(2);
  1247. OpCase(catch_end_y): {
  1248. c_p->catches--;
  1249. make_blank(yb(Arg(0)));
  1250. if (is_non_value(r(0))) {
  1251. if (x(1) == am_throw) {
  1252. r(0) = x(2);
  1253. } else {
  1254. if (x(1) == am_error) {
  1255. SWAPOUT;
  1256. x(2) = add_stacktrace(c_p, x(2), x(3));
  1257. SWAPIN;
  1258. }
  1259. /* only x(2) is included in the rootset here */
  1260. if (E - HTOP < 3 || c_p->mbuf) { /* Force GC in case add_stacktrace()
  1261. * created heap fragments */
  1262. SWAPOUT;
  1263. PROCESS_MAIN_CHK_LOCKS(c_p);
  1264. FCALLS -= erts_garbage_collect(c_p, 3, reg+2, 1);
  1265. PROCESS_MAIN_CHK_LOCKS(c_p);
  1266. SWAPIN;
  1267. }
  1268. r(0) = TUPLE2(HTOP, am_EXIT, x(2));
  1269. HTOP += 3;
  1270. }
  1271. }
  1272. CHECK_TERM(r(0));
  1273. Next(1);
  1274. }
  1275. OpCase(try_end_y): {
  1276. c_p->catches--;
  1277. make_blank(yb(Arg(0)));
  1278. if (is_non_value(r(0))) {
  1279. r(0) = x(1);
  1280. x(1) = x(2);
  1281. x(2) = x(3);
  1282. }
  1283. Next(1);
  1284. }
  1285. /*
  1286. * Skeleton for receive statement:
  1287. *
  1288. * L1: <-------------------+
  1289. * <-----------+ |
  1290. * | |
  1291. * loop_rec L2 ------+---+ |
  1292. * ... | | |
  1293. * remove_message | | |
  1294. * jump L3 | | |
  1295. * ... | | |
  1296. * loop_rec_end L1 --+ | |
  1297. * L2: <---------------+ |
  1298. * wait L1 -----------------+ or wait_timeout
  1299. * timeout
  1300. *
  1301. * L3: Code after receive...
  1302. *
  1303. *
  1304. */
  1305. /*
  1306. * Pick up the next message and place it in x(0).
  1307. * If no message, jump to a wait or wait_timeout instruction.
  1308. */
  1309. OpCase(i_loop_rec_fr):
  1310. {
  1311. Eterm* next;
  1312. ErlMessage* msgp;
  1313. loop_rec__:
  1314. PROCESS_MAIN_CHK_LOCKS(c_p);
  1315. msgp = PEEK_MESSAGE(c_p);
  1316. if (!msgp) {
  1317. #ifdef ERTS_SMP
  1318. erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1319. /* Make sure messages wont pass exit signals... */
  1320. if (ERTS_PROC_PENDING_EXIT(c_p)) {
  1321. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1322. SWAPOUT;
  1323. goto do_schedule; /* Will be rescheduled for exit */
  1324. }
  1325. ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
  1326. msgp = PEEK_MESSAGE(c_p);
  1327. if (msgp)
  1328. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1329. else {
  1330. #endif
  1331. SET_I((Eterm *) Arg(0));
  1332. Goto(*I); /* Jump to a wait or wait_timeout instruction */
  1333. #ifdef ERTS_SMP
  1334. }
  1335. #endif
  1336. }
  1337. ErtsMoveMsgAttachmentIntoProc(msgp, c_p, E, HTOP, FCALLS,
  1338. {
  1339. SWAPOUT;
  1340. reg[0] = r(0);
  1341. PROCESS_MAIN_CHK_LOCKS(c_p);
  1342. },
  1343. {
  1344. PROCESS_MAIN_CHK_LOCKS(c_p);
  1345. r(0) = reg[0];
  1346. SWAPIN;
  1347. });
  1348. if (is_non_value(ERL_MESSAGE_TERM(msgp))) {
  1349. /*
  1350. * A corrupt distribution message that we weren't able to decode;
  1351. * remove it...
  1352. */
  1353. ASSERT(!msgp->data.attached);
  1354. UNLINK_MESSAGE(c_p, msgp);
  1355. free_message(msgp);
  1356. goto loop_rec__;
  1357. }
  1358. PreFetch(1, next);
  1359. r(0) = ERL_MESSAGE_TERM(msgp);
  1360. NextPF(1, next);
  1361. }
  1362. /*
  1363. * Remove a (matched) message from the message queue.
  1364. */
  1365. OpCase(remove_message): {
  1366. Eterm* next;
  1367. ErlMessage* msgp;
  1368. PROCESS_MAIN_CHK_LOCKS(c_p);
  1369. PreFetch(0, next);
  1370. msgp = PEEK_MESSAGE(c_p);
  1371. if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) {
  1372. save_calls(c_p, &exp_receive);
  1373. }
  1374. if (ERL_MESSAGE_TOKEN(msgp) == NIL) {
  1375. SEQ_TRACE_TOKEN(c_p) = NIL;
  1376. } else if (ERL_MESSAGE_TOKEN(msgp) != am_undefined) {
  1377. Eterm msg;
  1378. SEQ_TRACE_TOKEN(c_p) = ERL_MESSAGE_TOKEN(msgp);
  1379. ASSERT(is_tuple(SEQ_TRACE_TOKEN(c_p)));
  1380. ASSERT(SEQ_TRACE_TOKEN_ARITY(c_p) == 5);
  1381. ASSERT(is_small(SEQ_TRACE_TOKEN_SERIAL(c_p)));
  1382. ASSERT(is_small(SEQ_TRACE_TOKEN_LASTCNT(c_p)));
  1383. ASSERT(is_small(SEQ_TRACE_TOKEN_FLAGS(c_p)));
  1384. ASSERT(is_pid(SEQ_TRACE_TOKEN_SENDER(c_p)));
  1385. c_p->seq_trace_lastcnt = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p));
  1386. if (c_p->seq_trace_clock < unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p))) {
  1387. c_p->seq_trace_clock = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p));
  1388. }
  1389. msg = ERL_MESSAGE_TERM(msgp);
  1390. seq_trace_output(SEQ_TRACE_TOKEN(c_p), msg, SEQ_TRACE_RECEIVE,
  1391. c_p->id, c_p);
  1392. }
  1393. UNLINK_MESSAGE(c_p, msgp);
  1394. JOIN_MESSAGE(c_p);
  1395. CANCEL_TIMER(c_p);
  1396. free_message(msgp);
  1397. PROCESS_MAIN_CHK_LOCKS(c_p);
  1398. NextPF(0, next);
  1399. }
  1400. /*
  1401. * Advance the save pointer to the next message (the current
  1402. * message didn't match), then jump to the loop_rec instruction.
  1403. */
  1404. OpCase(loop_rec_end_f): {
  1405. SET_I((Eterm *) Arg(0));
  1406. SAVE_MESSAGE(c_p);
  1407. goto loop_rec__;
  1408. }
  1409. /*
  1410. * Prepare to wait for a message or a timeout, whichever occurs first.
  1411. *
  1412. * Note: In order to keep the compatibility between 32 and 64 bits
  1413. * emulators, only timeout values that can be represented in 32 bits
  1414. * (unsigned) or less are allowed.
  1415. */
  1416. OpCase(i_wait_timeout_fs): {
  1417. erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1418. /* Fall through */
  1419. }
  1420. OpCase(i_wait_timeout_locked_fs): {
  1421. Eterm timeout_value;
  1422. /*
  1423. * If we have already set the timer, we must NOT set it again. Therefore,
  1424. * we must test the F_INSLPQUEUE flag as well as the F_TIMO flag.
  1425. */
  1426. if (c_p->flags & (F_INSLPQUEUE | F_TIMO)) {
  1427. goto wait2;
  1428. }
  1429. GetArg1(1, timeout_value);
  1430. if (timeout_value != make_small(0)) {
  1431. #if !defined(ARCH_64)
  1432. Uint time_val;
  1433. #endif
  1434. if (is_small(timeout_value) && signed_val(timeout_value) > 0 &&
  1435. #if defined(ARCH_64)
  1436. ((unsigned_val(timeout_value) >> 32) == 0)
  1437. #else
  1438. 1
  1439. #endif
  1440. ) {
  1441. /*
  1442. * The timer routiner will set c_p->i to the value in
  1443. * c_p->def_arg_reg[0]. Note that it is safe to use this
  1444. * location because there are no living x registers in
  1445. * a receive statement.
  1446. */
  1447. c_p->def_arg_reg[0] = (Eterm) (I+3);
  1448. set_timer(c_p, unsigned_val(timeout_value));
  1449. } else if (timeout_value == am_infinity) {
  1450. c_p->flags |= F_TIMO;
  1451. #if !defined(ARCH_64)
  1452. } else if (term_to_Uint(timeout_value, &time_val)) {
  1453. c_p->def_arg_reg[0] = (Eterm) (I+3);
  1454. set_timer(c_p, time_val);
  1455. #endif
  1456. } else { /* Wrong time */
  1457. OpCase(i_wait_error_locked): {
  1458. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1459. /* Fall through */
  1460. }
  1461. OpCase(i_wait_error): {
  1462. c_p->freason = EXC_TIMEOUT_VALUE;
  1463. goto find_func_info;
  1464. }
  1465. }
  1466. /*
  1467. * Prepare to wait indefinitely for a new message to arrive
  1468. * (or the time set above if falling through from above).
  1469. *
  1470. * When a new message arrives, control will be transferred
  1471. * the loop_rec instruction (at label L1). In case of
  1472. * of timeout, control will be transferred to the timeout
  1473. * instruction following the wait_timeout instruction.
  1474. */
  1475. OpCase(wait_locked_f):
  1476. OpCase(wait_f):
  1477. wait2: {
  1478. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  1479. c_p->i = (Eterm *) Arg(0); /* L1 */
  1480. SWAPOUT;
  1481. c_p->arity = 0;
  1482. c_p->status = P_WAITING;
  1483. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1484. c_p->current = NULL;
  1485. goto do_schedule;
  1486. }
  1487. OpCase(wait_unlocked_f): {
  1488. erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1489. goto wait2;
  1490. }
  1491. }
  1492. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1493. Next(2);
  1494. }
  1495. OpCase(i_wait_timeout_fI): {
  1496. erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1497. }
  1498. OpCase(i_wait_timeout_locked_fI):
  1499. {
  1500. /*
  1501. * If we have already set the timer, we must NOT set it again. Therefore,
  1502. * we must test the F_INSLPQUEUE flag as well as the F_TIMO flag.
  1503. */
  1504. if ((c_p->flags & (F_INSLPQUEUE | F_TIMO)) == 0) {
  1505. c_p->def_arg_reg[0] = (Eterm) (I+3);
  1506. set_timer(c_p, Arg(1));
  1507. }
  1508. goto wait2;
  1509. }
  1510. /*
  1511. * A timeout has occurred. Reset the save pointer so that the next
  1512. * receive statement will examine the first message first.
  1513. */
  1514. OpCase(timeout_locked): {
  1515. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
  1516. }
  1517. OpCase(timeout): {
  1518. Eterm* next;
  1519. PreFetch(0, next);
  1520. if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) {
  1521. trace_receive(c_p, am_timeout);
  1522. }
  1523. if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) {
  1524. save_calls(c_p, &exp_timeout);
  1525. }
  1526. c_p->flags &= ~F_TIMO;
  1527. JOIN_MESSAGE(c_p);
  1528. NextPF(0, next);
  1529. }
  1530. OpCase(i_select_val_sfI):
  1531. GetArg1(0, tmp_arg1);
  1532. do_binary_search:
  1533. {
  1534. struct Pairs {
  1535. Eterm val;
  1536. Eterm* addr;
  1537. };
  1538. struct Pairs* low;
  1539. struct Pairs* high;
  1540. struct Pairs* mid;
  1541. int bdiff; /* int not long because the arrays aren't that large */
  1542. low = (struct Pairs *) &Arg(3);
  1543. high = low + Arg(2);
  1544. /* The pointer subtraction (high-low) below must produce
  1545. * a signed result, because high could be < low. That
  1546. * requires the compiler to insert quite a bit of code.
  1547. *
  1548. * However, high will be > low so the result will be
  1549. * positive. We can use that knowledge to optimise the
  1550. * entire sequence, from the initial comparison to the
  1551. * computation of mid.
  1552. *
  1553. * -- Mikael Pettersson, Acumem AB
  1554. *
  1555. * Original loop control code:
  1556. *
  1557. * while (low < high) {
  1558. * mid = low + (high-low) / 2;
  1559. *
  1560. */
  1561. while ((bdiff = (int)((char*)high - (char*)low)) > 0) {
  1562. unsigned int boffset = ((unsigned int)bdiff >> 1) & ~(sizeof(struct Pairs)-1);
  1563. mid = (struct Pairs*)((char*)low + boffset);
  1564. if (tmp_arg1 < mid->val) {
  1565. high = mid;
  1566. } else if (tmp_arg1 > mid->val) {
  1567. low = mid + 1;
  1568. } else {
  1569. SET_I(mid->addr);
  1570. Goto(*I);
  1571. }
  1572. }
  1573. SET_I((Eterm *) Arg(1));
  1574. Goto(*I);
  1575. }
  1576. OpCase(i_jump_on_val_zero_sfI):
  1577. {
  1578. Eterm index;
  1579. GetArg1(0, index);
  1580. if (is_small(index)) {
  1581. index = signed_val(index);
  1582. if (index < Arg(2)) {
  1583. SET_I((Eterm *) (&Arg(3))[index]);
  1584. Goto(*I);
  1585. }
  1586. }
  1587. SET_I((Eterm *) Arg(1));
  1588. Goto(*I);
  1589. }
  1590. OpCase(i_jump_on_val_sfII):
  1591. {
  1592. Eterm index;
  1593. GetArg1(0, index);
  1594. if (is_small(index)) {
  1595. index = (Uint) (signed_val(index) - Arg(3));
  1596. if (index < Arg(2)) {
  1597. SET_I((Eterm *) (&Arg(4))[index]);
  1598. Goto(*I);
  1599. }
  1600. }
  1601. SET_I((Eterm *) Arg(1));
  1602. Goto(*I);
  1603. }
  1604. /*
  1605. * All guards with zero arguments have special instructions:
  1606. * self/0
  1607. * node/0
  1608. *
  1609. * All other guard BIFs take one or two arguments.
  1610. */
  1611. /*
  1612. * Guard BIF in head. On failure, ignore the error and jump
  1613. * to the code for the next clause. We don't support tracing
  1614. * of guard BIFs.
  1615. */
  1616. OpCase(bif1_fbsd):
  1617. {
  1618. Eterm (*bf)(Process*, Eterm);
  1619. Eterm arg;
  1620. Eterm result;
  1621. GetArg1(2, arg);
  1622. bf = (BifFunction) Arg(1);
  1623. c_p->fcalls = FCALLS;
  1624. PROCESS_MAIN_CHK_LOCKS(c_p);
  1625. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  1626. result = (*bf)(c_p, arg);
  1627. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
  1628. PROCESS_MAIN_CHK_LOCKS(c_p);
  1629. ERTS_HOLE_CHECK(c_p);
  1630. FCALLS = c_p->fcalls;
  1631. if (is_value(result)) {
  1632. StoreBifResult(3, result);
  1633. }
  1634. SET_I((Eterm *) Arg(0));
  1635. Goto(*I);
  1636. }
  1637. /*
  1638. * Guard BIF in body. It can fail like any BIF. No trace support.
  1639. */
  1640. OpCase(bif1_body_bsd):
  1641. {
  1642. Eterm (*bf)(Process*, Eterm);
  1643. Eterm arg;
  1644. Eterm result;
  1645. GetArg1(1, arg);
  1646. bf = (BifFunction) Arg(0);
  1647. c_p->fcalls = FCALLS;
  1648. PROCESS_MAIN_CHK_LOCKS(c_p);
  1649. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  1650. result = (*bf)(c_p, arg);
  1651. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
  1652. PROCESS_MAIN_CHK_LOCKS(c_p);
  1653. ERTS_HOLE_CHECK(c_p);
  1654. FCALLS = c_p->fcalls;
  1655. if (is_value(result)) {
  1656. StoreBifResult(2, result);
  1657. }
  1658. reg[0] = arg;
  1659. SWAPOUT;
  1660. I = handle_error(c_p, I, reg, bf);
  1661. goto post_error_handling;
  1662. }
  1663. OpCase(i_gc_bif1_jIsId):
  1664. {
  1665. typedef Eterm (*GcBifFunction)(Process*, Eterm*, Uint);
  1666. GcBifFunction bf;
  1667. Eterm arg;
  1668. Eterm result;
  1669. Uint live = Arg(3);
  1670. GetArg1(2, arg);
  1671. reg[0] = r(0);
  1672. reg[live] = arg;
  1673. bf = (GcBifFunction) Arg(1);
  1674. c_p->fcalls = FCALLS;
  1675. SWAPOUT;
  1676. PROCESS_MAIN_CHK_LOCKS(c_p);
  1677. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  1678. result = (*bf)(c_p, reg, live);
  1679. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  1680. PROCESS_MAIN_CHK_LOCKS(c_p);
  1681. SWAPIN;
  1682. r(0) = reg[0];
  1683. ERTS_HOLE_CHECK(c_p);
  1684. FCALLS = c_p->fcalls;
  1685. if (is_value(result)) {
  1686. StoreBifResult(4, result);
  1687. }
  1688. if (Arg(0) != 0) {
  1689. SET_I((Eterm *) Arg(0));
  1690. Goto(*I);
  1691. }
  1692. reg[0] = arg;
  1693. I = handle_error(c_p, I, reg, translate_gc_bif((void *) bf));
  1694. goto post_error_handling;
  1695. }
  1696. /*
  1697. * Guards bifs and, or, xor in guards.
  1698. */
  1699. OpCase(i_bif2_fbd):
  1700. {
  1701. Eterm (*bf)(Process*, Eterm, Eterm);
  1702. Eterm result;
  1703. bf = (BifFunction) Arg(1);
  1704. c_p->fcalls = FCALLS;
  1705. PROCESS_MAIN_CHK_LOCKS(c_p);
  1706. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  1707. result = (*bf)(c_p, tmp_arg1, tmp_arg2);
  1708. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
  1709. PROCESS_MAIN_CHK_LOCKS(c_p);
  1710. ERTS_HOLE_CHECK(c_p);
  1711. FCALLS = c_p->fcalls;
  1712. if (is_value(result)) {
  1713. StoreBifResult(2, result);
  1714. }
  1715. SET_I((Eterm *) Arg(0));
  1716. Goto(*I);
  1717. }
  1718. /*
  1719. * Guards bifs and, or, xor, relational operators in body.
  1720. */
  1721. OpCase(i_bif2_body_bd):
  1722. {
  1723. Eterm (*bf)(Process*, Eterm, Eterm);
  1724. Eterm result;
  1725. bf = (BifFunction) Arg(0);
  1726. PROCESS_MAIN_CHK_LOCKS(c_p);
  1727. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  1728. result = (*bf)(c_p, tmp_arg1, tmp_arg2);
  1729. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
  1730. PROCESS_MAIN_CHK_LOCKS(c_p);
  1731. ERTS_HOLE_CHECK(c_p);
  1732. if (is_value(result)) {
  1733. ASSERT(!is_CP(result));
  1734. StoreBifResult(1, result);
  1735. }
  1736. reg[0] = tmp_arg1;
  1737. reg[1] = tmp_arg2;
  1738. SWAPOUT;
  1739. I = handle_error(c_p, I, reg, bf);
  1740. goto post_error_handling;
  1741. }
  1742. /*
  1743. * The most general BIF call. The BIF may build any amount of data
  1744. * on the heap. The result is always returned in r(0).
  1745. */
  1746. OpCase(call_bif0_e):
  1747. {
  1748. Eterm (*bf)(Process*, Uint*) = GET_BIF_ADDRESS(Arg(0));
  1749. PRE_BIF_SWAPOUT(c_p);
  1750. c_p->fcalls = FCALLS - 1;
  1751. if (FCALLS <= 0) {
  1752. save_calls(c_p, (Export *) Arg(0));
  1753. }
  1754. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  1755. r(0) = (*bf)(c_p, I);
  1756. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(r(0)));
  1757. ERTS_HOLE_CHECK(c_p);
  1758. POST_BIF_GC_SWAPIN_0(c_p, r(0));
  1759. FCALLS = c_p->fcalls;
  1760. if (is_value(r(0))) {
  1761. CHECK_TERM(r(0));
  1762. Next(1);
  1763. }
  1764. else if (c_p->freason == TRAP) {
  1765. goto call_bif_trap3;
  1766. }
  1767. /*
  1768. * Error handling. SWAPOUT is not needed because it was done above.
  1769. */
  1770. ASSERT(c_p->stop == E);
  1771. reg[0] = r(0);
  1772. I = handle_error(c_p, I, reg, bf);
  1773. goto post_error_handling;
  1774. }
  1775. OpCase(call_bif1_e):
  1776. {
  1777. Eterm (*bf)(Process*, Eterm, Uint*) = GET_BIF_ADDRESS(Arg(0));
  1778. Eterm result;
  1779. Eterm* next;
  1780. c_p->fcalls = FCALLS - 1;
  1781. if (FCALLS <= 0) {
  1782. save_calls(c_p, (Export *) Arg(0));
  1783. }
  1784. PreFetch(1, next);
  1785. PRE_BIF_SWAPOUT(c_p);
  1786. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  1787. result = (*bf)(c_p, r(0), I);
  1788. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
  1789. ERTS_HOLE_CHECK(c_p);
  1790. POST_BIF_GC_SWAPIN(c_p, result, reg, 1);
  1791. FCALLS = c_p->fcalls;
  1792. if (is_value(result)) {
  1793. r(0) = result;
  1794. CHECK_TERM(r(0));
  1795. NextPF(1, next);
  1796. } else if (c_p->freason == TRAP) {
  1797. goto call_bif_trap3;
  1798. }
  1799. /*
  1800. * Error handling. SWAPOUT is not needed because it was done above.
  1801. */
  1802. ASSERT(c_p->stop == E);
  1803. reg[0] = r(0);
  1804. I = handle_error(c_p, I, reg, bf);
  1805. goto post_error_handling;
  1806. }
  1807. OpCase(call_bif2_e):
  1808. {
  1809. Eterm (*bf)(Process*, Eterm, Eterm, Uint*) = GET_BIF_ADDRESS(Arg(0));
  1810. Eterm result;
  1811. Eterm* next;
  1812. PRE_BIF_SWAPOUT(c_p);
  1813. c_p->fcalls = FCALLS - 1;
  1814. if (FCALLS <= 0) {
  1815. save_calls(c_p, (Export *) Arg(0));
  1816. }
  1817. PreFetch(1, next);
  1818. CHECK_TERM(r(0));
  1819. CHECK_TERM(x(1));
  1820. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  1821. result = (*bf)(c_p, r(0), x(1), I);
  1822. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
  1823. ERTS_HOLE_CHECK(c_p);
  1824. POST_BIF_GC_SWAPIN(c_p, result, reg, 2);
  1825. FCALLS = c_p->fcalls;
  1826. if (is_value(result)) {
  1827. r(0) = result;
  1828. CHECK_TERM(r(0));
  1829. NextPF(1, next);
  1830. } else if (c_p->freason == TRAP) {
  1831. goto call_bif_trap3;
  1832. }
  1833. /*
  1834. * Error handling. SWAPOUT is not needed because it was done above.
  1835. */
  1836. ASSERT(c_p->stop == E);
  1837. reg[0] = r(0);
  1838. I = handle_error(c_p, I, reg, bf);
  1839. goto post_error_handling;
  1840. }
  1841. OpCase(call_bif3_e):
  1842. {
  1843. Eterm (*bf)(Process*, Eterm, Eterm, Eterm, Uint*) = GET_BIF_ADDRESS(Arg(0));
  1844. Eterm result;
  1845. Eterm* next;
  1846. PRE_BIF_SWAPOUT(c_p);
  1847. c_p->fcalls = FCALLS - 1;
  1848. if (FCALLS <= 0) {
  1849. save_calls(c_p, (Export *) Arg(0));
  1850. }
  1851. PreFetch(1, next);
  1852. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  1853. result = (*bf)(c_p, r(0), x(1), x(2), I);
  1854. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
  1855. ERTS_HOLE_CHECK(c_p);
  1856. POST_BIF_GC_SWAPIN(c_p, result, reg, 3);
  1857. FCALLS = c_p->fcalls;
  1858. if (is_value(result)) {
  1859. r(0) = result;
  1860. CHECK_TERM(r(0));
  1861. NextPF(1, next);
  1862. } else if (c_p->freason == TRAP) {
  1863. call_bif_trap3:
  1864. SET_CP(c_p, I+2);
  1865. SET_I(((Export *)(c_p->def_arg_reg[3]))->address);
  1866. SWAPIN;
  1867. r(0) = c_p->def_arg_reg[0];
  1868. x(1) = c_p->def_arg_reg[1];
  1869. x(2) = c_p->def_arg_reg[2];
  1870. Dispatch();
  1871. }
  1872. /*
  1873. * Error handling. SWAPOUT is not needed because it was done above.
  1874. */
  1875. ASSERT(c_p->stop == E);
  1876. reg[0] = r(0);
  1877. I = handle_error(c_p, I, reg, bf);
  1878. goto post_error_handling;
  1879. }
  1880. /*
  1881. * Arithmetic operations.
  1882. */
  1883. OpCase(i_times_jId):
  1884. {
  1885. arith_func = ARITH_FUNC(mixed_times);
  1886. goto do_big_arith2;
  1887. }
  1888. OpCase(i_m_div_jId):
  1889. {
  1890. arith_func = ARITH_FUNC(mixed_div);
  1891. goto do_big_arith2;
  1892. }
  1893. OpCase(i_int_div_jId):
  1894. {
  1895. Eterm result;
  1896. if (tmp_arg2 == SMALL_ZERO) {
  1897. goto badarith;
  1898. } else if (is_both_small(tmp_arg1, tmp_arg2)) {
  1899. Sint ires = signed_val(tmp_arg1) / signed_val(tmp_arg2);
  1900. if (MY_IS_SSMALL(ires)) {
  1901. result = make_small(ires);
  1902. STORE_ARITH_RESULT(result);
  1903. }
  1904. }
  1905. arith_func = ARITH_FUNC(int_div);
  1906. goto do_big_arith2;
  1907. }
  1908. OpCase(i_rem_jId):
  1909. {
  1910. Eterm result;
  1911. if (tmp_arg2 == SMALL_ZERO) {
  1912. goto badarith;
  1913. } else if (is_both_small(tmp_arg1, tmp_arg2)) {
  1914. result = make_small(signed_val(tmp_arg1) % signed_val(tmp_arg2));
  1915. STORE_ARITH_RESULT(result);
  1916. } else {
  1917. arith_func = ARITH_FUNC(int_rem);
  1918. goto do_big_arith2;
  1919. }
  1920. }
  1921. OpCase(i_band_jId):
  1922. {
  1923. Eterm result;
  1924. if (is_both_small(tmp_arg1, tmp_arg2)) {
  1925. /*
  1926. * No need to untag -- TAG & TAG == TAG.
  1927. */
  1928. result = tmp_arg1 & tmp_arg2;
  1929. STORE_ARITH_RESULT(result);
  1930. }
  1931. arith_func = ARITH_FUNC(band);
  1932. goto do_big_arith2;
  1933. }
  1934. do_big_arith2:
  1935. {
  1936. Eterm result;
  1937. Uint live = Arg(1);
  1938. SWAPOUT;
  1939. reg[0] = r(0);
  1940. reg[live] = tmp_arg1;
  1941. reg[live+1] = tmp_arg2;
  1942. result = arith_func(c_p, reg, live);
  1943. r(0) = reg[0];
  1944. SWAPIN;
  1945. ERTS_HOLE_CHECK(c_p);
  1946. if (is_value(result)) {
  1947. STORE_ARITH_RESULT(result);
  1948. }
  1949. goto lb_Cl_error;
  1950. }
  1951. /*
  1952. * An error occured in an arithmetic operation or test that could
  1953. * appear either in a head or in a body.
  1954. * In a head, execution should continue at failure address in Arg(0).
  1955. * In a body, Arg(0) == 0 and an exception should be raised.
  1956. */
  1957. lb_Cl_error: {
  1958. if (Arg(0) != 0) {
  1959. OpCase(jump_f): {
  1960. SET_I((Eterm *) Arg(0));
  1961. Goto(*I);
  1962. }
  1963. }
  1964. ASSERT(c_p->freason != BADMATCH || is_value(c_p->fvalue));
  1965. goto find_func_info;
  1966. }
  1967. OpCase(i_bor_jId):
  1968. {
  1969. Eterm result;
  1970. if (is_both_small(tmp_arg1, tmp_arg2)) {
  1971. /*
  1972. * No need to untag -- TAG | TAG == TAG.
  1973. */
  1974. result = tmp_arg1 | tmp_arg2;
  1975. STORE_ARITH_RESULT(result);
  1976. }
  1977. arith_func = ARITH_FUNC(bor);
  1978. goto do_big_arith2;
  1979. }
  1980. OpCase(i_bxor_jId):
  1981. {
  1982. Eterm result;
  1983. if (is_both_small(tmp_arg1, tmp_arg2)) {
  1984. /*
  1985. * We could extract the tag from one argument, but a tag extraction
  1986. * could mean a shift. Therefore, play it safe here.
  1987. */
  1988. result = make_small(signed_val(tmp_arg1) ^ signed_val(tmp_arg2));
  1989. STORE_ARITH_RESULT(result);
  1990. }
  1991. arith_func = ARITH_FUNC(bxor);
  1992. goto do_big_arith2;
  1993. }
  1994. {
  1995. Sint i;
  1996. Sint ires;
  1997. Eterm* bigp;
  1998. OpCase(i_bsr_jId):
  1999. if (is_small(tmp_arg2)) {
  2000. i = -signed_val(tmp_arg2);
  2001. if (is_small(tmp_arg1)) {
  2002. goto small_shift;
  2003. } else if (is_big(tmp_arg1)) {
  2004. if (i == 0) {
  2005. StoreBifResult(2, tmp_arg1);
  2006. }
  2007. goto big_shift;
  2008. }
  2009. } else if (is_big(tmp_arg2)) {
  2010. /*
  2011. * N bsr NegativeBigNum == N bsl MAX_SMALL
  2012. * N bsr PositiveBigNum == N bsl MIN_SMALL
  2013. */
  2014. tmp_arg2 = make_small(bignum_header_is_neg(*big_val(tmp_arg2)) ?
  2015. MAX_SMALL : MIN_SMALL);
  2016. goto do_bsl;
  2017. }
  2018. goto badarith;
  2019. OpCase(i_bsl_jId):
  2020. do_bsl:
  2021. if (is_small(tmp_arg2)) {
  2022. i = signed_val(tmp_arg2);
  2023. if (is_small(tmp_arg1)) {
  2024. small_shift:
  2025. ires = signed_val(tmp_arg1);
  2026. if (i == 0 || ires == 0) {
  2027. StoreBifResult(2, tmp_arg1);
  2028. } else if (i < 0) { /* Right shift */
  2029. i = -i;
  2030. if (i >= SMALL_BITS-1) {
  2031. tmp_arg1 = (ires < 0) ? SMALL_MINUS_ONE : SMALL_ZERO;
  2032. } else {
  2033. tmp_arg1 = make_small(ires >> i);
  2034. }
  2035. StoreBifResult(2, tmp_arg1);
  2036. } else if (i < SMALL_BITS-1) { /* Left shift */
  2037. if ((ires > 0 && ((~(Uint)0 << ((SMALL_BITS-1)-i)) & ires) == 0) ||
  2038. ((~(Uint)0 << ((SMALL_BITS-1)-i)) & ~ires) == 0) {
  2039. tmp_arg1 = make_small(ires << i);
  2040. StoreBifResult(2, tmp_arg1);
  2041. }
  2042. }
  2043. tmp_arg1 = small_to_big(ires, tmp_big);
  2044. big_shift:
  2045. if (i > 0) { /* Left shift. */
  2046. ires = big_size(tmp_arg1) + (i / D_EXP);
  2047. } else { /* Right shift. */
  2048. ires = big_size(tmp_arg1);
  2049. if (ires <= (-i / D_EXP))
  2050. ires = 3; /* ??? */
  2051. else
  2052. ires -= (-i / D_EXP);
  2053. }
  2054. {
  2055. ires = BIG_NEED_SIZE(ires+1);
  2056. /*
  2057. * Slightly conservative check the size to avoid
  2058. * allocating huge amounts of memory for bignums that
  2059. * clearly would overflow the arity in the header
  2060. * word.
  2061. */
  2062. if (ires-8 > BIG_ARITY_MAX) {
  2063. c_p->freason = SYSTEM_LIMIT;
  2064. goto lb_Cl_error;
  2065. }
  2066. TestHeapPreserve(ires+1, Arg(1), tmp_arg1);
  2067. bigp = HTOP;
  2068. tmp_arg1 = big_lshift(tmp_arg1, i, bigp);
  2069. if (is_big(tmp_arg1)) {
  2070. HTOP += bignum_header_arity(*HTOP) + 1;
  2071. }
  2072. if (is_nil(tmp_arg1)) {
  2073. /*
  2074. * This result must have been only slight larger
  2075. * than allowed since it wasn't caught by the
  2076. * previous test.
  2077. */
  2078. c_p->freason = SYSTEM_LIMIT;
  2079. goto lb_Cl_error;
  2080. }
  2081. ERTS_HOLE_CHECK(c_p);
  2082. StoreBifResult(2, tmp_arg1);
  2083. }
  2084. } else if (is_big(tmp_arg1)) {
  2085. if (i == 0) {
  2086. StoreBifResult(2, tmp_arg1);
  2087. }
  2088. goto big_shift;
  2089. }
  2090. } else if (is_big(tmp_arg2)) {
  2091. if (bignum_header_is_neg(*big_val(tmp_arg2))) {
  2092. /*
  2093. * N bsl NegativeBigNum is either 0 or -1, depending on
  2094. * the sign of N. Since we don't believe this case
  2095. * is common, do the calculation with the minimum
  2096. * amount of code.
  2097. */
  2098. tmp_arg2 = make_small(MIN_SMALL);
  2099. goto do_bsl;
  2100. } else if (is_small(tmp_arg1) || is_big(tmp_arg1)) {
  2101. /*
  2102. * N bsl PositiveBigNum is too large to represent.
  2103. */
  2104. c_p->freason = SYSTEM_LIMIT;
  2105. goto lb_Cl_error;
  2106. }
  2107. /* Fall through if the left argument is not an integer. */
  2108. }
  2109. /*
  2110. * One or more non-integer arguments.
  2111. */
  2112. goto badarith;
  2113. }
  2114. OpCase(i_int_bnot_jsId):
  2115. {
  2116. GetArg1(1, tmp_arg1);
  2117. if (is_small(tmp_arg1)) {
  2118. tmp_arg1 = make_small(~signed_val(tmp_arg1));
  2119. } else {
  2120. Uint live = Arg(2);
  2121. SWAPOUT;
  2122. reg[0] = r(0);
  2123. reg[live] = tmp_arg1;
  2124. tmp_arg1 = erts_gc_bnot(c_p, reg, live);
  2125. r(0) = reg[0];
  2126. SWAPIN;
  2127. ERTS_HOLE_CHECK(c_p);
  2128. if (is_nil(tmp_arg1)) {
  2129. goto lb_Cl_error;
  2130. }
  2131. }
  2132. StoreBifResult(3, tmp_arg1);
  2133. }
  2134. badarith:
  2135. c_p->freason = BADARITH;
  2136. goto lb_Cl_error;
  2137. OpCase(i_apply): {
  2138. Eterm* next;
  2139. SWAPOUT;
  2140. next = apply(c_p, r(0), x(1), x(2), reg);
  2141. SWAPIN;
  2142. if (next != NULL) {
  2143. r(0) = reg[0];
  2144. SET_CP(c_p, I+1);
  2145. SET_I(next);
  2146. Dispatch();
  2147. }
  2148. I = handle_error(c_p, I, reg, apply_3);
  2149. goto post_error_handling;
  2150. }
  2151. OpCase(i_apply_last_P): {
  2152. Eterm* next;
  2153. SWAPOUT;
  2154. next = apply(c_p, r(0), x(1), x(2), reg);
  2155. SWAPIN;
  2156. if (next != NULL) {
  2157. r(0) = reg[0];
  2158. SET_CP(c_p, (Eterm *) E[0]);
  2159. E = ADD_BYTE_OFFSET(E, Arg(0));
  2160. SET_I(next);
  2161. Dispatch();
  2162. }
  2163. I = handle_error(c_p, I, reg, apply_3);
  2164. goto post_error_handling;
  2165. }
  2166. OpCase(i_apply_only): {
  2167. Eterm* next;
  2168. SWAPOUT;
  2169. next = apply(c_p, r(0), x(1), x(2), reg);
  2170. SWAPIN;
  2171. if (next != NULL) {
  2172. r(0) = reg[0];
  2173. SET_I(next);
  2174. Dispatch();
  2175. }
  2176. I = handle_error(c_p, I, reg, apply_3);
  2177. goto post_error_handling;
  2178. }
  2179. OpCase(apply_I): {
  2180. Eterm* next;
  2181. reg[0] = r(0);
  2182. SWAPOUT;
  2183. next = fixed_apply(c_p, reg, Arg(0));
  2184. SWAPIN;
  2185. if (next != NULL) {
  2186. r(0) = reg[0];
  2187. SET_CP(c_p, I+2);
  2188. SET_I(next);
  2189. Dispatch();
  2190. }
  2191. I = handle_error(c_p, I, reg, apply_3);
  2192. goto post_error_handling;
  2193. }
  2194. OpCase(apply_last_IP): {
  2195. Eterm* next;
  2196. reg[0] = r(0);
  2197. SWAPOUT;
  2198. next = fixed_apply(c_p, reg, Arg(0));
  2199. SWAPIN;
  2200. if (next != NULL) {
  2201. r(0) = reg[0];
  2202. SET_CP(c_p, (Eterm *) E[0]);
  2203. E = ADD_BYTE_OFFSET(E, Arg(1));
  2204. SET_I(next);
  2205. Dispatch();
  2206. }
  2207. I = handle_error(c_p, I, reg, apply_3);
  2208. goto post_error_handling;
  2209. }
  2210. OpCase(i_apply_fun): {
  2211. Eterm* next;
  2212. SWAPOUT;
  2213. next = apply_fun(c_p, r(0), x(1), reg);
  2214. SWAPIN;
  2215. if (next != NULL) {
  2216. r(0) = reg[0];
  2217. SET_CP(c_p, I+1);
  2218. SET_I(next);
  2219. Dispatchfun();
  2220. }
  2221. goto find_func_info;
  2222. }
  2223. OpCase(i_apply_fun_last_P): {
  2224. Eterm* next;
  2225. SWAPOUT;
  2226. next = apply_fun(c_p, r(0), x(1), reg);
  2227. SWAPIN;
  2228. if (next != NULL) {
  2229. r(0) = reg[0];
  2230. SET_CP(c_p, (Eterm *) E[0]);
  2231. E = ADD_BYTE_OFFSET(E, Arg(0));
  2232. SET_I(next);
  2233. Dispatchfun();
  2234. }
  2235. goto find_func_info;
  2236. }
  2237. OpCase(i_apply_fun_only): {
  2238. Eterm* next;
  2239. SWAPOUT;
  2240. next = apply_fun(c_p, r(0), x(1), reg);
  2241. SWAPIN;
  2242. if (next != NULL) {
  2243. r(0) = reg[0];
  2244. SET_I(next);
  2245. Dispatchfun();
  2246. }
  2247. goto find_func_info;
  2248. }
  2249. OpCase(i_call_fun_I): {
  2250. Eterm* next;
  2251. SWAPOUT;
  2252. reg[0] = r(0);
  2253. next = call_fun(c_p, Arg(0), reg, THE_NON_VALUE);
  2254. SWAPIN;
  2255. if (next != NULL) {
  2256. r(0) = reg[0];
  2257. SET_CP(c_p, I+2);
  2258. SET_I(next);
  2259. Dispatchfun();
  2260. }
  2261. goto find_func_info;
  2262. }
  2263. OpCase(i_call_fun_last_IP): {
  2264. Eterm* next;
  2265. SWAPOUT;
  2266. reg[0] = r(0);
  2267. next = call_fun(c_p, Arg(0), reg, THE_NON_VALUE);
  2268. SWAPIN;
  2269. if (next != NULL) {
  2270. r(0) = reg[0];
  2271. SET_CP(c_p, (Eterm *) E[0]);
  2272. E = ADD_BYTE_OFFSET(E, Arg(1));
  2273. SET_I(next);
  2274. Dispatchfun();
  2275. }
  2276. goto find_func_info;
  2277. }
  2278. #ifdef DEBUG
  2279. /*
  2280. * Set a breakpoint here to get control just after a call instruction.
  2281. * I points to the first instruction in the called function.
  2282. *
  2283. * In gdb, use 'call dis(I-5, 1)' to show the name of the function.
  2284. */
  2285. do_dispatch:
  2286. DispatchMacro();
  2287. do_dispatchx:
  2288. DispatchMacrox();
  2289. do_dispatchfun:
  2290. DispatchMacroFun();
  2291. #endif
  2292. /*
  2293. * Jumped to from the Dispatch() macro when the reductions are used up.
  2294. *
  2295. * Since the I register points just beyond the FuncBegin instruction, we
  2296. * can get the module, function, and arity for the function being
  2297. * called from I[-3], I[-2], and I[-1] respectively.
  2298. */
  2299. context_switch_fun:
  2300. c_p->arity = I[-1] + 1;
  2301. goto context_switch2;
  2302. context_switch:
  2303. c_p->arity = I[-1];
  2304. context_switch2: /* Entry for fun calls. */
  2305. c_p->current = I-3; /* Pointer to Mod, Func, Arity */
  2306. {
  2307. Eterm* argp;
  2308. int i;
  2309. /*
  2310. * Make sure that there is enough room for the argument registers to be saved.
  2311. */
  2312. if (c_p->arity > c_p->max_arg_reg) {
  2313. /*
  2314. * Yes, this is an expensive operation, but you only pay it the first
  2315. * time you call a function with more than 6 arguments which is
  2316. * scheduled out. This is better than paying for 26 words of wasted
  2317. * space for most processes which never call functions with more than
  2318. * 6 arguments.
  2319. */
  2320. Uint size = c_p->arity * sizeof(c_p->arg_reg[0]);
  2321. if (c_p->arg_reg != c_p->def_arg_reg) {
  2322. c_p->arg_reg = (Eterm *) erts_realloc(ERTS_ALC_T_ARG_REG,
  2323. (void *) c_p->arg_reg,
  2324. size);
  2325. } else {
  2326. c_p->arg_reg = (Eterm *) erts_alloc(ERTS_ALC_T_ARG_REG, size);
  2327. }
  2328. c_p->max_arg_reg = c_p->arity;
  2329. }
  2330. /*
  2331. * Since REDS_IN(c_p) is stored in the save area (c_p->arg_reg) we must read it
  2332. * now before saving registers.
  2333. *
  2334. * The '+ 1' compensates for the last increment which was not done
  2335. * (beacuse the code for the Dispatch() macro becomes shorter that way).
  2336. */
  2337. reds_used = REDS_IN(c_p) - FCALLS + 1;
  2338. /*
  2339. * Save the argument registers and everything else.
  2340. */
  2341. argp = c_p->arg_reg;
  2342. for (i = c_p->arity - 1; i > 0; i--) {
  2343. argp[i] = reg[i];
  2344. }
  2345. c_p->arg_reg[0] = r(0);
  2346. SWAPOUT;
  2347. c_p->i = I;
  2348. erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_STATUS);
  2349. if (c_p->status != P_SUSPENDED)
  2350. erts_add_to_runq(c_p);
  2351. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS);
  2352. goto do_schedule1;
  2353. }
  2354. OpCase(i_select_tuple_arity_sfI):
  2355. {
  2356. GetArg1(0, tmp_arg1);
  2357. if (is_tuple(tmp_arg1)) {
  2358. tmp_arg1 = *tuple_val(tmp_arg1);
  2359. goto do_binary_search;
  2360. }
  2361. SET_I((Eterm *) Arg(1));
  2362. Goto(*I);
  2363. }
  2364. OpCase(i_select_big_sf):
  2365. {
  2366. Eterm* bigp;
  2367. Uint arity;
  2368. Eterm* given;
  2369. Uint given_arity;
  2370. Uint given_size;
  2371. GetArg1(0, tmp_arg1);
  2372. if (is_big(tmp_arg1)) {
  2373. /*
  2374. * The loader has sorted the bignumbers in descending order
  2375. * on the arity word. Therefore, we know that the search
  2376. * has failed as soon as we encounter an arity word less than
  2377. * the arity word of the given number. There is a zero word
  2378. * (less than any valid arity word) stored after the last bignumber.
  2379. */
  2380. given = big_val(tmp_arg1);
  2381. given_arity = given[0];
  2382. given_size = thing_arityval(given_arity);
  2383. bigp = &Arg(2);
  2384. while ((arity = bigp[0]) > given_arity) {
  2385. bigp += thing_arityval(arity) + 2;
  2386. }
  2387. while (bigp[0] == given_arity) {
  2388. if (memcmp(bigp+1, given+1, sizeof(Eterm)*given_size) == 0) {
  2389. SET_I((Eterm *) bigp[given_size+1]);
  2390. Goto(*I);
  2391. }
  2392. bigp += thing_arityval(arity) + 2;
  2393. }
  2394. }
  2395. /*
  2396. * Failed.
  2397. */
  2398. SET_I((Eterm *) Arg(1));
  2399. Goto(*I);
  2400. }
  2401. #ifdef ARCH_64
  2402. OpCase(i_select_float_sfI):
  2403. {
  2404. Uint f;
  2405. int n;
  2406. struct ValLabel {
  2407. Uint f;
  2408. Eterm* addr;
  2409. };
  2410. struct ValLabel* ptr;
  2411. GetArg1(0, tmp_arg1);
  2412. ASSERT(is_float(tmp_arg1));
  2413. f = float_val(tmp_arg1)[1];
  2414. n = Arg(2);
  2415. ptr = (struct ValLabel *) &Arg(3);
  2416. while (n-- > 0) {
  2417. if (ptr->f == f) {
  2418. SET_I(ptr->addr);
  2419. Goto(*I);
  2420. }
  2421. ptr++;
  2422. }
  2423. SET_I((Eterm *) Arg(1));
  2424. Goto(*I);
  2425. }
  2426. #else
  2427. OpCase(i_select_float_sfI):
  2428. {
  2429. Uint fpart1;
  2430. Uint fpart2;
  2431. int n;
  2432. struct ValLabel {
  2433. Uint fpart1;
  2434. Uint fpart2;
  2435. Eterm* addr;
  2436. };
  2437. struct ValLabel* ptr;
  2438. GetArg1(0, tmp_arg1);
  2439. ASSERT(is_float(tmp_arg1));
  2440. fpart1 = float_val(tmp_arg1)[1];
  2441. fpart2 = float_val(tmp_arg1)[2];
  2442. n = Arg(2);
  2443. ptr = (struct ValLabel *) &Arg(3);
  2444. while (n-- > 0) {
  2445. if (ptr->fpart1 == fpart1 && ptr->fpart2 == fpart2) {
  2446. SET_I(ptr->addr);
  2447. Goto(*I);
  2448. }
  2449. ptr++;
  2450. }
  2451. SET_I((Eterm *) Arg(1));
  2452. Goto(*I);
  2453. }
  2454. #endif
  2455. OpCase(set_tuple_element_sdP): {
  2456. Eterm element;
  2457. Eterm tuple;
  2458. Eterm* next;
  2459. Eterm* p;
  2460. PreFetch(3, next);
  2461. GetArg2(0, element, tuple);
  2462. ASSERT(is_tuple(tuple));
  2463. p = (Eterm *) ((unsigned char *) tuple_val(tuple) + Arg(2));
  2464. *p = element;
  2465. NextPF(3, next);
  2466. }
  2467. OpCase(i_is_ne_exact_f):
  2468. if (EQ(tmp_arg1, tmp_arg2)) {
  2469. ClauseFail();
  2470. }
  2471. Next(1);
  2472. OpCase(normal_exit): {
  2473. SWAPOUT;
  2474. c_p->freason = EXC_NORMAL;
  2475. c_p->arity = 0; /* In case this process will ever be garbed again. */
  2476. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  2477. erts_do_exit_process(c_p, am_normal);
  2478. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  2479. goto do_schedule;
  2480. }
  2481. OpCase(continue_exit): {
  2482. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  2483. erts_continue_exit_process(c_p);
  2484. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  2485. goto do_schedule;
  2486. }
  2487. OpCase(raise_ss): {
  2488. /* This was not done very well in R10-0; then, we passed the tag in
  2489. the first argument and hoped that the existing c_p->ftrace was
  2490. still correct. But the ftrace-object already includes the tag
  2491. (or rather, the freason). Now, we pass the original ftrace in
  2492. the first argument. We also handle atom tags in the first
  2493. argument for backwards compatibility.
  2494. */
  2495. GetArg2(0, tmp_arg1, tmp_arg2);
  2496. c_p->fvalue = tmp_arg2;
  2497. if (c_p->freason == EXC_NULL) {
  2498. /* a safety check for the R10-0 case; should not happen */
  2499. c_p->ftrace = NIL;
  2500. c_p->freason = EXC_ERROR;
  2501. }
  2502. /* for R10-0 code, keep existing c_p->ftrace and hope it's correct */
  2503. switch (tmp_arg1) {
  2504. case am_throw:
  2505. c_p->freason = EXC_THROWN & ~EXF_SAVETRACE;
  2506. break;
  2507. case am_error:
  2508. c_p->freason = EXC_ERROR & ~EXF_SAVETRACE;
  2509. break;
  2510. case am_exit:
  2511. c_p->freason = EXC_EXIT & ~EXF_SAVETRACE;
  2512. break;
  2513. default:
  2514. {/* R10-1 and later
  2515. XXX note: should do sanity check on given trace if it can be
  2516. passed from a user! Currently only expecting generated calls.
  2517. */
  2518. struct StackTrace *s;
  2519. c_p->ftrace = tmp_arg1;
  2520. s = get_trace_from_exc(tmp_arg1);
  2521. if (s == NULL) {
  2522. c_p->freason = EXC_ERROR;
  2523. } else {
  2524. c_p->freason = PRIMARY_EXCEPTION(s->freason);
  2525. }
  2526. }
  2527. }
  2528. goto find_func_info;
  2529. }
  2530. OpCase(badmatch_s): {
  2531. GetArg1(0, tmp_arg1);
  2532. c_p->fvalue = tmp_arg1;
  2533. c_p->freason = BADMATCH;
  2534. }
  2535. /* Fall through here */
  2536. find_func_info: {
  2537. reg[0] = r(0);
  2538. SWAPOUT;
  2539. I = handle_error(c_p, I, reg, NULL);
  2540. goto post_error_handling;
  2541. }
  2542. OpCase(call_error_handler):
  2543. /*
  2544. * At this point, I points to the code[3] in the export entry for
  2545. * a function which is not loaded.
  2546. *
  2547. * code[0]: Module
  2548. * code[1]: Function
  2549. * code[2]: Arity
  2550. * code[3]: &&call_error_handler
  2551. * code[4]: Not used
  2552. */
  2553. SWAPOUT;
  2554. reg[0] = r(0);
  2555. tmp_arg1 = call_error_handler(c_p, I-3, reg);
  2556. r(0) = reg[0];
  2557. SWAPIN;
  2558. if (tmp_arg1) {
  2559. SET_I(c_p->i);
  2560. Dispatch();
  2561. }
  2562. /* Fall through */
  2563. OpCase(error_action_code): {
  2564. no_error_handler:
  2565. reg[0] = r(0);
  2566. SWAPOUT;
  2567. I = handle_error(c_p, NULL, reg, NULL);
  2568. post_error_handling:
  2569. if (I == 0) {
  2570. goto do_schedule;
  2571. } else {
  2572. r(0) = reg[0];
  2573. ASSERT(!is_value(r(0)));
  2574. if (c_p->mbuf) {
  2575. erts_garbage_collect(c_p, 0, reg+1, 3);
  2576. }
  2577. SWAPIN;
  2578. Goto(*I);
  2579. }
  2580. }
  2581. OpCase(apply_bif):
  2582. /*
  2583. * At this point, I points to the code[3] in the export entry for
  2584. * the BIF:
  2585. *
  2586. * code[0]: Module
  2587. * code[1]: Function
  2588. * code[2]: Arity
  2589. * code[3]: &&apply_bif
  2590. * code[4]: Function pointer to BIF function
  2591. */
  2592. {
  2593. BifFunction vbf;
  2594. c_p->current = I-3; /* In case we apply process_info/1,2. */
  2595. c_p->i = I; /* In case we apply check_process_code/2. */
  2596. c_p->arity = 0; /* To allow garbage collection on ourselves
  2597. * (check_process_code/2).
  2598. */
  2599. SWAPOUT;
  2600. c_p->fcalls = FCALLS - 1;
  2601. vbf = (BifFunction) Arg(0);
  2602. PROCESS_MAIN_CHK_LOCKS(c_p);
  2603. tmp_arg2 = I[-1];
  2604. ASSERT(tmp_arg2 <= 3);
  2605. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  2606. switch (tmp_arg2) {
  2607. case 3:
  2608. {
  2609. Eterm (*bf)(Process*, Eterm, Eterm, Eterm, Uint*) = vbf;
  2610. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  2611. tmp_arg1 = (*bf)(c_p, r(0), x(1), x(2), I);
  2612. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(tmp_arg1));
  2613. PROCESS_MAIN_CHK_LOCKS(c_p);
  2614. }
  2615. break;
  2616. case 2:
  2617. {
  2618. Eterm (*bf)(Process*, Eterm, Eterm, Uint*) = vbf;
  2619. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  2620. tmp_arg1 = (*bf)(c_p, r(0), x(1), I);
  2621. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(tmp_arg1));
  2622. PROCESS_MAIN_CHK_LOCKS(c_p);
  2623. }
  2624. break;
  2625. case 1:
  2626. {
  2627. Eterm (*bf)(Process*, Eterm, Uint*) = vbf;
  2628. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  2629. tmp_arg1 = (*bf)(c_p, r(0), I);
  2630. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(tmp_arg1));
  2631. PROCESS_MAIN_CHK_LOCKS(c_p);
  2632. }
  2633. break;
  2634. case 0:
  2635. {
  2636. Eterm (*bf)(Process*, Uint*) = vbf;
  2637. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  2638. tmp_arg1 = (*bf)(c_p, I);
  2639. ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(tmp_arg1));
  2640. PROCESS_MAIN_CHK_LOCKS(c_p);
  2641. break;
  2642. }
  2643. }
  2644. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  2645. ERTS_HOLE_CHECK(c_p);
  2646. if (c_p->mbuf) {
  2647. reg[0] = r(0);
  2648. tmp_arg1 = erts_gc_after_bif_call(c_p, tmp_arg1, reg, tmp_arg2);
  2649. r(0) = reg[0];
  2650. }
  2651. SWAPIN; /* There might have been a garbage collection. */
  2652. FCALLS = c_p->fcalls;
  2653. if (is_value(tmp_arg1)) {
  2654. r(0) = tmp_arg1;
  2655. CHECK_TERM(r(0));
  2656. SET_I(c_p->cp);
  2657. Goto(*I);
  2658. } else if (c_p->freason == TRAP) {
  2659. SET_I(((Export *)(c_p->def_arg_reg[3]))->address);
  2660. r(0) = c_p->def_arg_reg[0];
  2661. x(1) = c_p->def_arg_reg[1];
  2662. x(2) = c_p->def_arg_reg[2];
  2663. Dispatch();
  2664. }
  2665. reg[0] = r(0);
  2666. I = handle_error(c_p, c_p->cp, reg, vbf);
  2667. goto post_error_handling;
  2668. }
  2669. OpCase(i_get_sd):
  2670. {
  2671. Eterm arg;
  2672. Eterm result;
  2673. GetArg1(0, arg);
  2674. result = erts_pd_hash_get(c_p, arg);
  2675. StoreBifResult(1, result);
  2676. }
  2677. OpCase(i_put_tuple_only_Ad): {
  2678. tmp_arg1 = make_tuple(HTOP);
  2679. *HTOP++ = Arg(0);
  2680. StoreBifResult(1, tmp_arg1);
  2681. }
  2682. OpCase(case_end_s):
  2683. GetArg1(0, tmp_arg1);
  2684. c_p->fvalue = tmp_arg1;
  2685. c_p->freason = EXC_CASE_CLAUSE;
  2686. goto find_func_info;
  2687. OpCase(if_end):
  2688. c_p->freason = EXC_IF_CLAUSE;
  2689. goto find_func_info;
  2690. OpCase(i_func_info_IaaI): {
  2691. c_p->freason = EXC_FUNCTION_CLAUSE;
  2692. c_p->current = I + 2;
  2693. goto lb_error_action_code;
  2694. }
  2695. OpCase(try_case_end_s):
  2696. GetArg1(0, tmp_arg1);
  2697. c_p->fvalue = tmp_arg1;
  2698. c_p->freason = EXC_TRY_CLAUSE;
  2699. goto find_func_info;
  2700. /*
  2701. * Construction of binaries using new instructions.
  2702. */
  2703. {
  2704. Eterm new_binary;
  2705. Eterm num_bits_term;
  2706. Uint num_bits;
  2707. Uint alloc;
  2708. Uint num_bytes;
  2709. OpCase(i_bs_init_bits_heap_IIId): {
  2710. num_bits = Arg(0);
  2711. alloc = Arg(1);
  2712. I++;
  2713. goto do_bs_init_bits_known;
  2714. }
  2715. OpCase(i_bs_init_bits_IId): {
  2716. num_bits = Arg(0);
  2717. alloc = 0;
  2718. goto do_bs_init_bits_known;
  2719. }
  2720. OpCase(i_bs_init_bits_fail_heap_IjId): {
  2721. /* tmp_arg1 was fetched by an i_fetch instruction */
  2722. num_bits_term = tmp_arg1;
  2723. alloc = Arg(0);
  2724. I++;
  2725. goto do_bs_init_bits;
  2726. }
  2727. OpCase(i_bs_init_bits_fail_rjId): {
  2728. num_bits_term = r(0);
  2729. alloc = 0;
  2730. goto do_bs_init_bits;
  2731. }
  2732. OpCase(i_bs_init_bits_fail_yjId): {
  2733. num_bits_term = yb(Arg(0));
  2734. I++;
  2735. alloc = 0;
  2736. goto do_bs_init_bits;
  2737. }
  2738. OpCase(i_bs_init_bits_fail_xjId): {
  2739. num_bits_term = xb(Arg(0));
  2740. I++;
  2741. alloc = 0;
  2742. /* FALL THROUGH */
  2743. }
  2744. /* num_bits_term = Term for number of bits to build (small/big)
  2745. * alloc = Number of words to allocate on heap
  2746. * Operands: Fail Live Dst
  2747. */
  2748. do_bs_init_bits:
  2749. if (is_small(num_bits_term)) {
  2750. Sint size = signed_val(num_bits_term);
  2751. if (size < 0) {
  2752. goto badarg;
  2753. }
  2754. num_bits = (Uint) size;
  2755. } else {
  2756. Uint bits;
  2757. if (!term_to_Uint(num_bits_term, &bits)) {
  2758. c_p->freason = bits;
  2759. goto lb_Cl_error;
  2760. }
  2761. num_bits = (Eterm) bits;
  2762. }
  2763. /* num_bits = Number of bits to build
  2764. * alloc = Number of extra words to allocate on heap
  2765. * Operands: NotUsed Live Dst
  2766. */
  2767. do_bs_init_bits_known:
  2768. num_bytes = (num_bits+7) >> 3;
  2769. if (num_bits & 7) {
  2770. alloc += ERL_SUB_BIN_SIZE;
  2771. }
  2772. if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) {
  2773. alloc += heap_bin_size(num_bytes);
  2774. } else {
  2775. alloc += PROC_BIN_SIZE;
  2776. }
  2777. TestHeap(alloc, Arg(1));
  2778. /* num_bits = Number of bits to build
  2779. * num_bytes = Number of bytes to allocate in the binary
  2780. * alloc = Total number of words to allocate on heap
  2781. * Operands: NotUsed NotUsed Dst
  2782. */
  2783. if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) {
  2784. ErlHeapBin* hb;
  2785. erts_bin_offset = 0;
  2786. erts_writable_bin = 0;
  2787. hb = (ErlHeapBin *) HTOP;
  2788. HTOP += heap_bin_size(num_bytes);
  2789. hb->thing_word = header_heap_bin(num_bytes);
  2790. hb->size = num_bytes;
  2791. erts_current_bin = (byte *) hb->data;
  2792. new_binary = make_binary(hb);
  2793. do_bits_sub_bin:
  2794. if (num_bits & 7) {
  2795. ErlSubBin* sb;
  2796. sb = (ErlSubBin *) HTOP;
  2797. HTOP += ERL_SUB_BIN_SIZE;
  2798. sb->thing_word = HEADER_SUB_BIN;
  2799. sb->size = num_bytes - 1;
  2800. sb->bitsize = num_bits & 7;
  2801. sb->offs = 0;
  2802. sb->bitoffs = 0;
  2803. sb->is_writable = 0;
  2804. sb->orig = new_binary;
  2805. new_binary = make_binary(sb);
  2806. }
  2807. StoreBifResult(2, new_binary);
  2808. } else {
  2809. Binary* bptr;
  2810. ProcBin* pb;
  2811. erts_bin_offset = 0;
  2812. erts_writable_bin = 0;
  2813. /*
  2814. * Allocate the binary struct itself.
  2815. */
  2816. bptr = erts_bin_nrml_alloc(num_bytes);
  2817. bptr->flags = 0;
  2818. bptr->orig_size = num_bytes;
  2819. erts_refc_init(&bptr->refc, 1);
  2820. erts_current_bin = (byte *) bptr->orig_bytes;
  2821. /*
  2822. * Now allocate the ProcBin on the heap.
  2823. */
  2824. pb = (ProcBin *) HTOP;
  2825. HTOP += PROC_BIN_SIZE;
  2826. pb->thing_word = HEADER_PROC_BIN;
  2827. pb->size = num_bytes;
  2828. pb->next = MSO(c_p).mso;
  2829. MSO(c_p).mso = pb;
  2830. pb->val = bptr;
  2831. pb->bytes = (byte*) bptr->orig_bytes;
  2832. pb->flags = 0;
  2833. MSO(c_p).overhead += pb->size / BINARY_OVERHEAD_FACTOR / sizeof(Eterm);
  2834. new_binary = make_binary(pb);
  2835. goto do_bits_sub_bin;
  2836. }
  2837. }
  2838. {
  2839. OpCase(i_bs_init_fail_heap_IjId): {
  2840. /* tmp_arg1 was fetched by an i_fetch instruction */
  2841. tmp_arg2 = Arg(0);
  2842. I++;
  2843. goto do_bs_init;
  2844. }
  2845. OpCase(i_bs_init_fail_rjId): {
  2846. tmp_arg1 = r(0);
  2847. tmp_arg2 = 0;
  2848. goto do_bs_init;
  2849. }
  2850. OpCase(i_bs_init_fail_yjId): {
  2851. tmp_arg1 = yb(Arg(0));
  2852. tmp_arg2 = 0;
  2853. I++;
  2854. goto do_bs_init;
  2855. }
  2856. OpCase(i_bs_init_fail_xjId): {
  2857. tmp_arg1 = xb(Arg(0));
  2858. tmp_arg2 = 0;
  2859. I++;
  2860. }
  2861. /* FALL THROUGH */
  2862. do_bs_init:
  2863. if (is_small(tmp_arg1)) {
  2864. Sint size = signed_val(tmp_arg1);
  2865. if (size < 0) {
  2866. goto badarg;
  2867. }
  2868. tmp_arg1 = (Eterm) size;
  2869. } else {
  2870. Uint bytes;
  2871. if (!term_to_Uint(tmp_arg1, &bytes)) {
  2872. c_p->freason = bytes;
  2873. goto lb_Cl_error;
  2874. }
  2875. if ((bytes >> (8*sizeof(Uint)-3)) != 0) {
  2876. goto system_limit;
  2877. }
  2878. tmp_arg1 = (Eterm) bytes;
  2879. }
  2880. if (tmp_arg1 <= ERL_ONHEAP_BIN_LIMIT) {
  2881. goto do_heap_bin_alloc;
  2882. } else {
  2883. goto do_proc_bin_alloc;
  2884. }
  2885. OpCase(i_bs_init_heap_IIId): {
  2886. tmp_arg1 = Arg(0);
  2887. tmp_arg2 = Arg(1);
  2888. I++;
  2889. goto do_proc_bin_alloc;
  2890. }
  2891. OpCase(i_bs_init_IId): {
  2892. tmp_arg1 = Arg(0);
  2893. tmp_arg2 = 0;
  2894. }
  2895. /* FALL THROUGH */
  2896. do_proc_bin_alloc: {
  2897. Binary* bptr;
  2898. ProcBin* pb;
  2899. erts_bin_offset = 0;
  2900. erts_writable_bin = 0;
  2901. TestHeap(tmp_arg2 + PROC_BIN_SIZE + ERL_SUB_BIN_SIZE, Arg(1));
  2902. /*
  2903. * Allocate the binary struct itself.
  2904. */
  2905. bptr = erts_bin_nrml_alloc(tmp_arg1);
  2906. bptr->flags = 0;
  2907. bptr->orig_size = tmp_arg1;
  2908. erts_refc_init(&bptr->refc, 1);
  2909. erts_current_bin = (byte *) bptr->orig_bytes;
  2910. /*
  2911. * Now allocate the ProcBin on the heap.
  2912. */
  2913. pb = (ProcBin *) HTOP;
  2914. HTOP += PROC_BIN_SIZE;
  2915. pb->thing_word = HEADER_PROC_BIN;
  2916. pb->size = tmp_arg1;
  2917. pb->next = MSO(c_p).mso;
  2918. MSO(c_p).mso = pb;
  2919. pb->val = bptr;
  2920. pb->bytes = (byte*) bptr->orig_bytes;
  2921. pb->flags = 0;
  2922. MSO(c_p).overhead += pb->size / BINARY_OVERHEAD_FACTOR / sizeof(Eterm);
  2923. StoreBifResult(2, make_binary(pb));
  2924. }
  2925. OpCase(i_bs_init_heap_bin_heap_IIId): {
  2926. tmp_arg1 = Arg(0);
  2927. tmp_arg2 = Arg(1);
  2928. I++;
  2929. goto do_heap_bin_alloc;
  2930. }
  2931. OpCase(i_bs_init_heap_bin_IId): {
  2932. tmp_arg1 = Arg(0);
  2933. tmp_arg2 = 0;
  2934. }
  2935. /* Fall through */
  2936. do_heap_bin_alloc:
  2937. {
  2938. ErlHeapBin* hb;
  2939. Uint bin_need;
  2940. bin_need = heap_bin_size(tmp_arg1);
  2941. erts_bin_offset = 0;
  2942. erts_writable_bin = 0;
  2943. TestHeap(bin_need+tmp_arg2+ERL_SUB_BIN_SIZE, Arg(1));
  2944. hb = (ErlHeapBin *) HTOP;
  2945. HTOP += bin_need;
  2946. hb->thing_word = header_heap_bin(tmp_arg1);
  2947. hb->size = tmp_arg1;
  2948. erts_current_bin = (byte *) hb->data;
  2949. tmp_arg1 = make_binary(hb);
  2950. StoreBifResult(2, tmp_arg1);
  2951. }
  2952. }
  2953. OpCase(i_bs_bits_to_bytes_rjd): {
  2954. tmp_arg1 = r(0);
  2955. goto do_bits_to_bytes;
  2956. }
  2957. OpCase(i_bs_bits_to_bytes_yjd): {
  2958. tmp_arg1 = yb(Arg(0));
  2959. I++;
  2960. goto do_bits_to_bytes;
  2961. OpCase(i_bs_bits_to_bytes_xjd): {
  2962. tmp_arg1 = xb(Arg(0));
  2963. I++;
  2964. }
  2965. do_bits_to_bytes:
  2966. {
  2967. if (is_valid_bit_size(tmp_arg1)) {
  2968. tmp_arg1 = make_small(unsigned_val(tmp_arg1) >> 3);
  2969. } else {
  2970. Uint bytes;
  2971. if (!term_to_Uint(tmp_arg1, &bytes)) {
  2972. goto badarg;
  2973. }
  2974. tmp_arg1 = bytes;
  2975. if ((tmp_arg1 & 0x07) != 0) {
  2976. goto badarg;
  2977. }
  2978. SWAPOUT;
  2979. tmp_arg1 = erts_make_integer(tmp_arg1 >> 3, c_p);
  2980. HTOP = HEAP_TOP(c_p);
  2981. }
  2982. StoreBifResult(1, tmp_arg1);
  2983. }
  2984. }
  2985. OpCase(i_bs_add_jId): {
  2986. Uint Unit = Arg(1);
  2987. if (is_both_small(tmp_arg1, tmp_arg2)) {
  2988. Sint Arg1 = signed_val(tmp_arg1);
  2989. Sint Arg2 = signed_val(tmp_arg2);
  2990. if (Arg1 >= 0 && Arg2 >= 0) {
  2991. BsSafeMul(Arg2, Unit, goto system_limit, tmp_arg1);
  2992. tmp_arg1 += Arg1;
  2993. store_bs_add_result:
  2994. if (MY_IS_SSMALL((Sint) tmp_arg1)) {
  2995. tmp_arg1 = make_small(tmp_arg1);
  2996. } else {
  2997. /*
  2998. * May generate a heap fragment, but in this
  2999. * particular case it is OK, since the value will be
  3000. * stored into an x register (the GC will scan x
  3001. * registers for references to heap fragments) and
  3002. * there is no risk that value can be stored into a
  3003. * location that is not scanned for heap-fragment
  3004. * references (such as the heap).
  3005. */
  3006. SWAPOUT;
  3007. tmp_arg1 = erts_make_integer(tmp_arg1, c_p);
  3008. HTOP = HEAP_TOP(c_p);
  3009. }
  3010. StoreBifResult(2, tmp_arg1);
  3011. }
  3012. goto badarg;
  3013. } else {
  3014. Uint a;
  3015. Uint b;
  3016. Uint c;
  3017. /*
  3018. * Now we know that one of the arguments is
  3019. * not at small. We must convert both arguments
  3020. * to Uints and check for errors at the same time.
  3021. *
  3022. * Error checking is tricky.
  3023. *
  3024. * If one of the arguments is not numeric or
  3025. * not positive, the error reason is BADARG.
  3026. *
  3027. * Otherwise if both arguments are numeric,
  3028. * but at least one argument does not fit in
  3029. * an Uint, the reason is SYSTEM_LIMIT.
  3030. */
  3031. if (!term_to_Uint(tmp_arg1, &a)) {
  3032. if (a == BADARG) {
  3033. goto badarg;
  3034. }
  3035. if (!term_to_Uint(tmp_arg2, &b)) {
  3036. c_p->freason = b;
  3037. goto lb_Cl_error;
  3038. }
  3039. goto system_limit;
  3040. } else if (!term_to_Uint(tmp_arg2, &b)) {
  3041. c_p->freason = b;
  3042. goto lb_Cl_error;
  3043. }
  3044. /*
  3045. * The arguments are now correct and stored in a and b.
  3046. */
  3047. BsSafeMul(b, Unit, goto system_limit, c);
  3048. tmp_arg1 = a + c;
  3049. if (tmp_arg1 < a) {
  3050. /*
  3051. * If the result is less than one of the
  3052. * arguments, there must have been an overflow.
  3053. */
  3054. goto system_limit;
  3055. }
  3056. goto store_bs_add_result;
  3057. }
  3058. /* No fallthrough */
  3059. ASSERT(0);
  3060. }
  3061. OpCase(bs_put_string_II):
  3062. {
  3063. Eterm* next;
  3064. PreFetch(2, next);
  3065. erts_new_bs_put_string(ERL_BITS_ARGS_2((byte *) Arg(1), Arg(0)));
  3066. NextPF(2, next);
  3067. }
  3068. /*
  3069. * tmp_arg1 = Number of bytes to build
  3070. * tmp_arg2 = Source binary
  3071. * Operands: Fail ExtraHeap Live Unit Dst
  3072. */
  3073. OpCase(i_bs_append_jIIId): {
  3074. Uint live = Arg(2);
  3075. Uint res;
  3076. SWAPOUT;
  3077. reg[0] = r(0);
  3078. reg[live] = tmp_arg2;
  3079. res = erts_bs_append(c_p, reg, live, tmp_arg1, Arg(1), Arg(3));
  3080. r(0) = reg[0];
  3081. SWAPIN;
  3082. if (is_non_value(res)) {
  3083. /* c_p->freason is already set (may be either BADARG or SYSTEM_LIMIT). */
  3084. goto lb_Cl_error;
  3085. }
  3086. StoreBifResult(4, res);
  3087. }
  3088. /*
  3089. * tmp_arg1 = Number of bytes to build
  3090. * tmp_arg2 = Source binary
  3091. * Operands: Fail Unit Dst
  3092. */
  3093. OpCase(i_bs_private_append_jId): {
  3094. Eterm res;
  3095. res = erts_bs_private_append(c_p, tmp_arg2, tmp_arg1, Arg(1));
  3096. if (is_non_value(res)) {
  3097. /* c_p->freason is already set (may be either BADARG or SYSTEM_LIMIT). */
  3098. goto lb_Cl_error;
  3099. }
  3100. StoreBifResult(2, res);
  3101. }
  3102. /*
  3103. * tmp_arg1 = Initial size of writable binary
  3104. * Operands: Live Dst
  3105. */
  3106. OpCase(bs_init_writable): {
  3107. SWAPOUT;
  3108. r(0) = erts_bs_init_writable(c_p, r(0));
  3109. SWAPIN;
  3110. Next(0);
  3111. }
  3112. /*
  3113. * Calculate the number of bytes needed to encode the source
  3114. * operarand to UTF-8. If the source operand is invalid (e.g. wrong
  3115. * type or range) we return a nonsense integer result (0 or 4). We
  3116. * can get away with that because we KNOW that bs_put_utf8 will do
  3117. * full error checking.
  3118. */
  3119. OpCase(i_bs_utf8_size_sd): {
  3120. Eterm arg;
  3121. Eterm result;
  3122. GetArg1(0, arg);
  3123. if (arg < make_small(0x80UL)) {
  3124. result = make_small(1);
  3125. } else if (arg < make_small(0x800UL)) {
  3126. result = make_small(2);
  3127. } else if (arg < make_small(0x10000UL)) {
  3128. result = make_small(3);
  3129. } else {
  3130. result = make_small(4);
  3131. }
  3132. StoreBifResult(1, result);
  3133. }
  3134. OpCase(i_bs_put_utf8_js): {
  3135. Eterm arg;
  3136. GetArg1(1, arg);
  3137. if (!erts_bs_put_utf8(ERL_BITS_ARGS_1(arg))) {
  3138. goto badarg;
  3139. }
  3140. Next(2);
  3141. }
  3142. /*
  3143. * Calculate the number of bytes needed to encode the source
  3144. * operarand to UTF-8. If the source operand is invalid (e.g. wrong
  3145. * type or range) we return a nonsense integer result (2 or 4). We
  3146. * can get away with that because we KNOW that bs_put_utf16 will do
  3147. * full error checking.
  3148. */
  3149. OpCase(i_bs_utf16_size_sd): {
  3150. Eterm arg;
  3151. Eterm result = make_small(2);
  3152. GetArg1(0, arg);
  3153. if (arg >= make_small(0x10000UL)) {
  3154. result = make_small(4);
  3155. }
  3156. StoreBifResult(1, result);
  3157. }
  3158. OpCase(i_bs_put_utf16_jIs): {
  3159. Eterm arg;
  3160. GetArg1(2, arg);
  3161. if (!erts_bs_put_utf16(ERL_BITS_ARGS_2(arg, Arg(1)))) {
  3162. goto badarg;
  3163. }
  3164. Next(3);
  3165. }
  3166. /*
  3167. * Only used for validating a value about to be stored in a binary.
  3168. */
  3169. OpCase(i_bs_validate_unicode_js): {
  3170. Eterm val;
  3171. GetArg1(1, val);
  3172. /*
  3173. * There is no need to untag the integer, but it IS necessary
  3174. * to make sure it is small (if the term is a bignum, it could
  3175. * slip through the test, and there is no further test that
  3176. * would catch it, since bit syntax construction silently masks
  3177. * too big numbers).
  3178. */
  3179. if (is_not_small(val) || val > make_small(0x10FFFFUL) ||
  3180. (make_small(0xD800UL) <= val && val <= make_small(0xDFFFUL)) ||
  3181. val == make_small(0xFFFEUL) || val == make_small(0xFFFFUL)) {
  3182. goto badarg;
  3183. }
  3184. Next(2);
  3185. }
  3186. /*
  3187. * Only used for validating a value matched out.
  3188. *
  3189. * tmp_arg1 = Integer to validate
  3190. * tmp_arg2 = Match context
  3191. */
  3192. OpCase(i_bs_validate_unicode_retract_j): {
  3193. /*
  3194. * There is no need to untag the integer, but it IS necessary
  3195. * to make sure it is small (a bignum pointer could fall in
  3196. * the valid range).
  3197. */
  3198. if (is_not_small(tmp_arg1) || tmp_arg1 > make_small(0x10FFFFUL) ||
  3199. (make_small(0xD800UL) <= tmp_arg1 && tmp_arg1 <= make_small(0xDFFFUL)) ||
  3200. tmp_arg1 == make_small(0xFFFEUL) || tmp_arg1 == make_small(0xFFFFUL)) {
  3201. ErlBinMatchBuffer *mb = ms_matchbuffer(tmp_arg2);
  3202. mb->offset -= 32;
  3203. goto badarg;
  3204. }
  3205. Next(1);
  3206. }
  3207. /*
  3208. * Matching of binaries.
  3209. */
  3210. {
  3211. Eterm header;
  3212. Eterm* next;
  3213. Uint slots;
  3214. OpCase(i_bs_start_match2_rfIId): {
  3215. tmp_arg1 = r(0);
  3216. do_start_match:
  3217. slots = Arg(2);
  3218. if (!is_boxed(tmp_arg1)) {
  3219. ClauseFail();
  3220. }
  3221. PreFetch(4, next);
  3222. header = *boxed_val(tmp_arg1);
  3223. if (header_is_bin_matchstate(header)) {
  3224. ErlBinMatchState* ms = (ErlBinMatchState *) boxed_val(tmp_arg1);
  3225. Uint actual_slots = HEADER_NUM_SLOTS(header);
  3226. ms->save_offset[0] = ms->mb.offset;
  3227. if (actual_slots < slots) {
  3228. ErlBinMatchState* dst;
  3229. Uint live = Arg(1);
  3230. Uint wordsneeded = ERL_BIN_MATCHSTATE_SIZE(slots);
  3231. TestHeapPreserve(wordsneeded, live, tmp_arg1);
  3232. ms = (ErlBinMatchState *) boxed_val(tmp_arg1);
  3233. dst = (ErlBinMatchState *) HTOP;
  3234. *dst = *ms;
  3235. *HTOP = HEADER_BIN_MATCHSTATE(slots);
  3236. HTOP += wordsneeded;
  3237. StoreResult(make_matchstate(dst), Arg(3));
  3238. }
  3239. } else if (is_binary_header(header)) {
  3240. Eterm result;
  3241. Uint live = Arg(1);
  3242. Uint wordsneeded = ERL_BIN_MATCHSTATE_SIZE(slots);
  3243. TestHeapPreserve(wordsneeded, live, tmp_arg1);
  3244. HEAP_TOP(c_p) = HTOP;
  3245. #ifdef DEBUG
  3246. c_p->stop = E; /* Needed for checking in HeapOnlyAlloc(). */
  3247. #endif
  3248. result = erts_bs_start_match_2(c_p, tmp_arg1, slots);
  3249. HTOP = HEAP_TOP(c_p);
  3250. if (is_non_value(result)) {
  3251. ClauseFail();
  3252. } else {
  3253. StoreResult(result, Arg(3));
  3254. }
  3255. } else {
  3256. ClauseFail();
  3257. }
  3258. NextPF(4, next);
  3259. }
  3260. OpCase(i_bs_start_match2_xfIId): {
  3261. tmp_arg1 = xb(Arg(0));
  3262. I++;
  3263. goto do_start_match;
  3264. }
  3265. OpCase(i_bs_start_match2_yfIId): {
  3266. tmp_arg1 = yb(Arg(0));
  3267. I++;
  3268. goto do_start_match;
  3269. }
  3270. }
  3271. OpCase(bs_test_zero_tail2_fr): {
  3272. Eterm* next;
  3273. ErlBinMatchBuffer *_mb;
  3274. PreFetch(1, next);
  3275. _mb = (ErlBinMatchBuffer*) ms_matchbuffer(r(0));
  3276. if (_mb->size != _mb->offset) {
  3277. ClauseFail();
  3278. }
  3279. NextPF(1, next);
  3280. }
  3281. OpCase(bs_test_zero_tail2_fx): {
  3282. Eterm* next;
  3283. ErlBinMatchBuffer *_mb;
  3284. PreFetch(2, next);
  3285. _mb = (ErlBinMatchBuffer*) ms_matchbuffer(xb(Arg(1)));
  3286. if (_mb->size != _mb->offset) {
  3287. ClauseFail();
  3288. }
  3289. NextPF(2, next);
  3290. }
  3291. OpCase(bs_test_tail_imm2_frI): {
  3292. Eterm* next;
  3293. ErlBinMatchBuffer *_mb;
  3294. PreFetch(2, next);
  3295. _mb = ms_matchbuffer(r(0));
  3296. if (_mb->size - _mb->offset != Arg(1)) {
  3297. ClauseFail();
  3298. }
  3299. NextPF(2, next);
  3300. }
  3301. OpCase(bs_test_tail_imm2_fxI): {
  3302. Eterm* next;
  3303. ErlBinMatchBuffer *_mb;
  3304. PreFetch(3, next);
  3305. _mb = ms_matchbuffer(xb(Arg(1)));
  3306. if (_mb->size - _mb->offset != Arg(2)) {
  3307. ClauseFail();
  3308. }
  3309. NextPF(3, next);
  3310. }
  3311. OpCase(bs_test_unit_frI): {
  3312. Eterm* next;
  3313. ErlBinMatchBuffer *_mb;
  3314. PreFetch(2, next);
  3315. _mb = ms_matchbuffer(r(0));
  3316. if ((_mb->size - _mb->offset) % Arg(1)) {
  3317. ClauseFail();
  3318. }
  3319. NextPF(2, next);
  3320. }
  3321. OpCase(bs_test_unit_fxI): {
  3322. Eterm* next;
  3323. ErlBinMatchBuffer *_mb;
  3324. PreFetch(3, next);
  3325. _mb = ms_matchbuffer(xb(Arg(1)));
  3326. if ((_mb->size - _mb->offset) % Arg(2)) {
  3327. ClauseFail();
  3328. }
  3329. NextPF(3, next);
  3330. }
  3331. OpCase(bs_test_unit8_fr): {
  3332. Eterm* next;
  3333. ErlBinMatchBuffer *_mb;
  3334. PreFetch(1, next);
  3335. _mb = ms_matchbuffer(r(0));
  3336. if ((_mb->size - _mb->offset) & 7) {
  3337. ClauseFail();
  3338. }
  3339. NextPF(1, next);
  3340. }
  3341. OpCase(bs_test_unit8_fx): {
  3342. Eterm* next;
  3343. ErlBinMatchBuffer *_mb;
  3344. PreFetch(2, next);
  3345. _mb = ms_matchbuffer(xb(Arg(1)));
  3346. if ((_mb->size - _mb->offset) & 7) {
  3347. ClauseFail();
  3348. }
  3349. NextPF(2, next);
  3350. }
  3351. OpCase(i_bs_get_integer_8_rfd): {
  3352. tmp_arg1 = r(0);
  3353. goto do_bs_get_integer_8;
  3354. }
  3355. OpCase(i_bs_get_integer_8_xfd): {
  3356. tmp_arg1 = xb(Arg(0));
  3357. I++;
  3358. }
  3359. do_bs_get_integer_8: {
  3360. ErlBinMatchBuffer *_mb;
  3361. Eterm _result;
  3362. _mb = ms_matchbuffer(tmp_arg1);
  3363. if (_mb->size - _mb->offset < 8) {
  3364. ClauseFail();
  3365. }
  3366. if (BIT_OFFSET(_mb->offset) != 0) {
  3367. _result = erts_bs_get_integer_2(c_p, 8, 0, _mb);
  3368. } else {
  3369. _result = make_small(_mb->base[BYTE_OFFSET(_mb->offset)]);
  3370. _mb->offset += 8;
  3371. }
  3372. StoreBifResult(1, _result);
  3373. }
  3374. OpCase(i_bs_get_integer_16_rfd): {
  3375. tmp_arg1 = r(0);
  3376. goto do_bs_get_integer_16;
  3377. }
  3378. OpCase(i_bs_get_integer_16_xfd): {
  3379. tmp_arg1 = xb(Arg(0));
  3380. I++;
  3381. }
  3382. do_bs_get_integer_16: {
  3383. ErlBinMatchBuffer *_mb;
  3384. Eterm _result;
  3385. _mb = ms_matchbuffer(tmp_arg1);
  3386. if (_mb->size - _mb->offset < 16) {
  3387. ClauseFail();
  3388. }
  3389. if (BIT_OFFSET(_mb->offset) != 0) {
  3390. _result = erts_bs_get_integer_2(c_p, 16, 0, _mb);
  3391. } else {
  3392. _result = make_small(get_int16(_mb->base+BYTE_OFFSET(_mb->offset)));
  3393. _mb->offset += 16;
  3394. }
  3395. StoreBifResult(1, _result);
  3396. }
  3397. OpCase(i_bs_get_integer_32_rfId): {
  3398. tmp_arg1 = r(0);
  3399. goto do_bs_get_integer_32;
  3400. }
  3401. OpCase(i_bs_get_integer_32_xfId): {
  3402. tmp_arg1 = xb(Arg(0));
  3403. I++;
  3404. }
  3405. do_bs_get_integer_32: {
  3406. ErlBinMatchBuffer *_mb;
  3407. Uint32 _integer;
  3408. Eterm _result;
  3409. _mb = ms_matchbuffer(tmp_arg1);
  3410. if (_mb->size - _mb->offset < 32) { ClauseFail(); }
  3411. if (BIT_OFFSET(_mb->offset) != 0) {
  3412. _integer = erts_bs_get_unaligned_uint32(_mb);
  3413. } else {
  3414. _integer = get_int32(_mb->base + _mb->offset/8);
  3415. }
  3416. _mb->offset += 32;
  3417. #ifndef ARCH_64
  3418. if (IS_USMALL(0, _integer)) {
  3419. #endif
  3420. _result = make_small(_integer);
  3421. #ifndef ARCH_64
  3422. } else {
  3423. TestHeap(BIG_UINT_HEAP_SIZE, Arg(1));
  3424. _result = uint_to_big((Uint) _integer, HTOP);
  3425. HTOP += BIG_UINT_HEAP_SIZE;
  3426. }
  3427. #endif
  3428. StoreBifResult(2, _result);
  3429. }
  3430. /* Operands: Size Live Fail Flags Dst */
  3431. OpCase(i_bs_get_integer_imm_rIIfId): {
  3432. tmp_arg1 = r(0);
  3433. /* Operands: Size Live Fail Flags Dst */
  3434. goto do_bs_get_integer_imm_test_heap;
  3435. }
  3436. /* Operands: x(Reg) Size Live Fail Flags Dst */
  3437. OpCase(i_bs_get_integer_imm_xIIfId): {
  3438. tmp_arg1 = xb(Arg(0));
  3439. I++;
  3440. /* Operands: Size Live Fail Flags Dst */
  3441. goto do_bs_get_integer_imm_test_heap;
  3442. }
  3443. /*
  3444. * tmp_arg1 = match context
  3445. * Operands: Size Live Fail Flags Dst
  3446. */
  3447. do_bs_get_integer_imm_test_heap: {
  3448. Uint wordsneeded;
  3449. tmp_arg2 = Arg(0);
  3450. wordsneeded = 1+WSIZE(NBYTES(tmp_arg2));
  3451. TestHeapPreserve(wordsneeded, Arg(1), tmp_arg1);
  3452. I += 2;
  3453. /* Operands: Fail Flags Dst */
  3454. goto do_bs_get_integer_imm;
  3455. }
  3456. /* Operands: Size Fail Flags Dst */
  3457. OpCase(i_bs_get_integer_small_imm_rIfId): {
  3458. tmp_arg1 = r(0);
  3459. tmp_arg2 = Arg(0);
  3460. I++;
  3461. /* Operands: Fail Flags Dst */
  3462. goto do_bs_get_integer_imm;
  3463. }
  3464. /* Operands: x(Reg) Size Fail Flags Dst */
  3465. OpCase(i_bs_get_integer_small_imm_xIfId): {
  3466. tmp_arg1 = xb(Arg(0));
  3467. tmp_arg2 = Arg(1);
  3468. I += 2;
  3469. /* Operands: Fail Flags Dst */
  3470. goto do_bs_get_integer_imm;
  3471. }
  3472. /*
  3473. * tmp_arg1 = match context
  3474. * tmp_arg2 = size of field
  3475. * Operands: Fail Flags Dst
  3476. */
  3477. do_bs_get_integer_imm: {
  3478. ErlBinMatchBuffer* mb;
  3479. Eterm result;
  3480. mb = ms_matchbuffer(tmp_arg1);
  3481. LIGHT_SWAPOUT;
  3482. result = erts_bs_get_integer_2(c_p, tmp_arg2, Arg(1), mb);
  3483. LIGHT_SWAPIN;
  3484. if (is_non_value(result)) {
  3485. ClauseFail();
  3486. }
  3487. StoreBifResult(2, result);
  3488. }
  3489. /*
  3490. * tmp_arg1 = Match context
  3491. * tmp_arg2 = Size field
  3492. * Operands: Fail Live FlagsAndUnit Dst
  3493. */
  3494. OpCase(i_bs_get_integer_fIId): {
  3495. Uint flags;
  3496. Uint size;
  3497. ErlBinMatchBuffer* mb;
  3498. Eterm result;
  3499. flags = Arg(2);
  3500. BsGetFieldSize(tmp_arg2, (flags >> 3), ClauseFail(), size);
  3501. if (size >= SMALL_BITS) {
  3502. Uint wordsneeded = 1+WSIZE(NBYTES((Uint) size));
  3503. TestHeapPreserve(wordsneeded, Arg(1), tmp_arg1);
  3504. }
  3505. mb = ms_matchbuffer(tmp_arg1);
  3506. LIGHT_SWAPOUT;
  3507. result = erts_bs_get_integer_2(c_p, size, flags, mb);
  3508. LIGHT_SWAPIN;
  3509. if (is_non_value(result)) {
  3510. ClauseFail();
  3511. }
  3512. StoreBifResult(3, result);
  3513. }
  3514. /* Operands: MatchContext Fail Dst */
  3515. OpCase(i_bs_get_utf8_rfd): {
  3516. tmp_arg1 = r(0);
  3517. goto do_bs_get_utf8;
  3518. }
  3519. OpCase(i_bs_get_utf8_xfd): {
  3520. tmp_arg1 = xb(Arg(0));
  3521. I++;
  3522. }
  3523. /*
  3524. * tmp_arg1 = match_context
  3525. * Operands: Fail Dst
  3526. */
  3527. do_bs_get_utf8: {
  3528. Eterm result = erts_bs_get_utf8(ms_matchbuffer(tmp_arg1));
  3529. if (is_non_value(result)) {
  3530. ClauseFail();
  3531. }
  3532. StoreBifResult(1, result);
  3533. }
  3534. /* Operands: MatchContext Fail Flags Dst */
  3535. OpCase(i_bs_get_utf16_rfId): {
  3536. tmp_arg1 = r(0);
  3537. goto do_bs_get_utf16;
  3538. }
  3539. OpCase(i_bs_get_utf16_xfId): {
  3540. tmp_arg1 = xb(Arg(0));
  3541. I++;
  3542. }
  3543. /*
  3544. * tmp_arg1 = match_context
  3545. * Operands: Fail Flags Dst
  3546. */
  3547. do_bs_get_utf16: {
  3548. Eterm result = erts_bs_get_utf16(ms_matchbuffer(tmp_arg1), Arg(1));
  3549. if (is_non_value(result)) {
  3550. ClauseFail();
  3551. }
  3552. StoreBifResult(2, result);
  3553. }
  3554. {
  3555. ErlBinMatchBuffer* mb;
  3556. ErlSubBin* sb;
  3557. Uint size;
  3558. Uint offs;
  3559. Uint orig;
  3560. Uint hole_size;
  3561. OpCase(bs_context_to_binary_r): {
  3562. tmp_arg1 = x0;
  3563. I -= 2;
  3564. goto do_context_to_binary;
  3565. }
  3566. /* Unfortunately, inlining can generate this instruction. */
  3567. OpCase(bs_context_to_binary_y): {
  3568. tmp_arg1 = yb(Arg(0));
  3569. goto do_context_to_binary0;
  3570. }
  3571. OpCase(bs_context_to_binary_x): {
  3572. tmp_arg1 = xb(Arg(0));
  3573. do_context_to_binary0:
  3574. I--;
  3575. }
  3576. do_context_to_binary:
  3577. if (is_boxed(tmp_arg1) && header_is_bin_matchstate(*boxed_val(tmp_arg1))) {
  3578. ErlBinMatchState* ms = (ErlBinMatchState *) boxed_val(tmp_arg1);
  3579. mb = &ms->mb;
  3580. offs = ms->save_offset[0];
  3581. size = mb->size - offs;
  3582. goto do_bs_get_binary_all_reuse_common;
  3583. }
  3584. Next(2);
  3585. OpCase(i_bs_get_binary_all_reuse_rfI): {
  3586. tmp_arg1 = x0;
  3587. goto do_bs_get_binary_all_reuse;
  3588. }
  3589. OpCase(i_bs_get_binary_all_reuse_xfI): {
  3590. tmp_arg1 = xb(Arg(0));
  3591. I++;
  3592. }
  3593. do_bs_get_binary_all_reuse:
  3594. mb = ms_matchbuffer(tmp_arg1);
  3595. size = mb->size - mb->offset;
  3596. if (size % Arg(1) != 0) {
  3597. ClauseFail();
  3598. }
  3599. offs = mb->offset;
  3600. do_bs_get_binary_all_reuse_common:
  3601. orig = mb->orig;
  3602. sb = (ErlSubBin *) boxed_val(tmp_arg1);
  3603. hole_size = 1 + header_arity(sb->thing_word) - ERL_SUB_BIN_SIZE;
  3604. sb->thing_word = HEADER_SUB_BIN;
  3605. sb->size = BYTE_OFFSET(size);
  3606. sb->bitsize = BIT_OFFSET(size);
  3607. sb->offs = BYTE_OFFSET(offs);
  3608. sb->bitoffs = BIT_OFFSET(offs);
  3609. sb->is_writable = 0;
  3610. sb->orig = orig;
  3611. if (hole_size) {
  3612. sb[1].thing_word = make_pos_bignum_header(hole_size-1);
  3613. }
  3614. Next(2);
  3615. }
  3616. {
  3617. OpCase(i_bs_match_string_rfII): {
  3618. tmp_arg1 = r(0);
  3619. goto do_bs_match_string;
  3620. }
  3621. OpCase(i_bs_match_string_xfII): {
  3622. tmp_arg1 = xb(Arg(0));
  3623. I++;
  3624. }
  3625. do_bs_match_string:
  3626. {
  3627. Eterm* next;
  3628. byte* bytes;
  3629. Uint bits;
  3630. ErlBinMatchBuffer* mb;
  3631. Uint offs;
  3632. PreFetch(3, next);
  3633. bits = Arg(1);
  3634. bytes = (byte *) Arg(2);
  3635. mb = ms_matchbuffer(tmp_arg1);
  3636. if (mb->size - mb->offset < bits) {
  3637. ClauseFail();
  3638. }
  3639. offs = mb->offset & 7;
  3640. if (offs == 0 && (bits & 7) == 0) {
  3641. if (sys_memcmp(bytes, mb->base+(mb->offset>>3), bits>>3)) {
  3642. ClauseFail();
  3643. }
  3644. } else if (erts_cmp_bits(bytes, 0, mb->base+(mb->offset>>3), mb->offset & 7, bits)) {
  3645. ClauseFail();
  3646. }
  3647. mb->offset += bits;
  3648. NextPF(3, next);
  3649. }
  3650. }
  3651. OpCase(i_bs_save2_rI): {
  3652. Eterm* next;
  3653. ErlBinMatchState *_ms;
  3654. PreFetch(1, next);
  3655. _ms = (ErlBinMatchState*) boxed_val((Eterm) r(0));
  3656. _ms->save_offset[Arg(0)] = _ms->mb.offset;
  3657. NextPF(1, next);
  3658. }
  3659. OpCase(i_bs_save2_xI): {
  3660. Eterm* next;
  3661. ErlBinMatchState *_ms;
  3662. PreFetch(2, next);
  3663. _ms = (ErlBinMatchState*) boxed_val((Eterm) xb(Arg(0)));
  3664. _ms->save_offset[Arg(1)] = _ms->mb.offset;
  3665. NextPF(2, next);
  3666. }
  3667. OpCase(i_bs_restore2_rI): {
  3668. Eterm* next;
  3669. ErlBinMatchState *_ms;
  3670. PreFetch(1, next);
  3671. _ms = (ErlBinMatchState*) boxed_val((Eterm) r(0));
  3672. _ms->mb.offset = _ms->save_offset[Arg(0)];
  3673. NextPF(1, next);
  3674. }
  3675. OpCase(i_bs_restore2_xI): {
  3676. Eterm* next;
  3677. ErlBinMatchState *_ms;
  3678. PreFetch(2, next);
  3679. _ms = (ErlBinMatchState*) boxed_val((Eterm) xb(Arg(0)));
  3680. _ms->mb.offset = _ms->save_offset[Arg(1)];
  3681. NextPF(2, next);
  3682. }
  3683. #include "beam_cold.h"
  3684. /*
  3685. * This instruction is probably never used (because it is combined with a
  3686. * a return). However, a future compiler might for some reason emit a
  3687. * deallocate not followed by a return, and that should work.
  3688. */
  3689. OpCase(deallocate_I): {
  3690. Eterm* next;
  3691. PreFetch(1, next);
  3692. D(Arg(0));
  3693. NextPF(1, next);
  3694. }
  3695. /*
  3696. * Trace and debugging support.
  3697. */
  3698. /*
  3699. * At this point, I points to the code[3] in the export entry for
  3700. * a trace-enabled function.
  3701. *
  3702. * code[0]: Module
  3703. * code[1]: Function
  3704. * code[2]: Arity
  3705. * code[3]: &&call_traced_function
  3706. * code[4]: Address of function.
  3707. */
  3708. OpCase(call_traced_function): {
  3709. if (IS_TRACED_FL(c_p, F_TRACE_CALLS)) {
  3710. unsigned offset = offsetof(Export, code) + 3*sizeof(Eterm);
  3711. Export* ep = (Export *) (((char *)I)-offset);
  3712. Uint32 flags;
  3713. SWAPOUT;
  3714. reg[0] = r(0);
  3715. PROCESS_MAIN_CHK_LOCKS(c_p);
  3716. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  3717. flags = erts_call_trace(c_p, ep->code, ep->match_prog_set, reg,
  3718. 0, &c_p->tracer_proc);
  3719. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  3720. PROCESS_MAIN_CHK_LOCKS(c_p);
  3721. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  3722. SWAPIN;
  3723. if (flags & MATCH_SET_RX_TRACE) {
  3724. ASSERT(c_p->htop <= E && E <= c_p->hend);
  3725. if (E - 3 < HTOP) {
  3726. /* SWAPOUT, SWAPIN was done and r(0) was saved above */
  3727. PROCESS_MAIN_CHK_LOCKS(c_p);
  3728. FCALLS -= erts_garbage_collect(c_p, 3, reg, ep->code[2]);
  3729. PROCESS_MAIN_CHK_LOCKS(c_p);
  3730. r(0) = reg[0];
  3731. SWAPIN;
  3732. }
  3733. E -= 3;
  3734. ASSERT(c_p->htop <= E && E <= c_p->hend);
  3735. ASSERT(is_CP((Eterm)(ep->code)));
  3736. ASSERT(is_internal_pid(c_p->tracer_proc) ||
  3737. is_internal_port(c_p->tracer_proc));
  3738. E[2] = make_cp(c_p->cp);
  3739. E[1] = am_true; /* Process tracer */
  3740. E[0] = make_cp(ep->code);
  3741. c_p->cp = (Eterm*)
  3742. make_cp(flags & MATCH_SET_EXCEPTION_TRACE
  3743. ? beam_exception_trace : beam_return_trace);
  3744. erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
  3745. c_p->trace_flags |= F_EXCEPTION_TRACE;
  3746. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
  3747. }
  3748. }
  3749. SET_I((Uint *) Arg(0));
  3750. Dispatch();
  3751. }
  3752. OpCase(return_trace): {
  3753. Uint* code = (Uint *) E[0];
  3754. SWAPOUT; /* Needed for shared heap */
  3755. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  3756. erts_trace_return(c_p, code, r(0), E+1/*Process tracer*/);
  3757. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  3758. SWAPIN;
  3759. c_p->cp = NULL;
  3760. SET_I((Eterm *) E[2]);
  3761. E += 3;
  3762. Goto(*I);
  3763. }
  3764. OpCase(i_count_breakpoint): {
  3765. Uint real_I;
  3766. ErtsCountBreak((Uint *) I, &real_I);
  3767. ASSERT(VALID_INSTR(real_I));
  3768. Goto(real_I);
  3769. }
  3770. OpCase(i_trace_breakpoint):
  3771. if (! IS_TRACED_FL(c_p, F_TRACE_CALLS)) {
  3772. Uint real_I;
  3773. ErtsBreakSkip((Uint *) I, &real_I);
  3774. Goto(real_I);
  3775. }
  3776. /* Fall through to next case */
  3777. OpCase(i_mtrace_breakpoint): {
  3778. Uint real_I;
  3779. Uint32 flags;
  3780. Eterm tracer_pid;
  3781. Uint *cpp;
  3782. int return_to_trace = 0, need = 0;
  3783. flags = 0;
  3784. SWAPOUT;
  3785. reg[0] = r(0);
  3786. if (*cp_val((Eterm)c_p->cp)
  3787. == (Uint) OpCode(return_trace)) {
  3788. cpp = (Uint*)&E[2];
  3789. } else if (*cp_val((Eterm)c_p->cp)
  3790. == (Uint) OpCode(i_return_to_trace)) {
  3791. return_to_trace = !0;
  3792. cpp = (Uint*)&E[0];
  3793. } else {
  3794. cpp = NULL;
  3795. }
  3796. if (cpp) {
  3797. /* This _IS_ a tail recursive call, if there are
  3798. * return_trace and/or i_return_to_trace stackframes
  3799. * on the stack, they are not intermixed with y registers
  3800. */
  3801. Eterm *cp_save = c_p->cp;
  3802. for (;;) {
  3803. ASSERT(is_CP(*cpp));
  3804. if (*cp_val(*cpp) == (Uint) OpCode(return_trace)) {
  3805. cpp += 3;
  3806. } else if (*cp_val(*cpp) == (Uint) OpCode(i_return_to_trace)) {
  3807. return_to_trace = !0;
  3808. cpp += 1;
  3809. } else
  3810. break;
  3811. }
  3812. c_p->cp = (Eterm *) *cpp;
  3813. ASSERT(is_CP((Eterm)c_p->cp));
  3814. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  3815. real_I = erts_trace_break(c_p, I, reg, &flags, &tracer_pid);
  3816. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  3817. SWAPIN; /* Needed by shared heap. */
  3818. c_p->cp = cp_save;
  3819. } else {
  3820. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  3821. real_I = erts_trace_break(c_p, I, reg, &flags, &tracer_pid);
  3822. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  3823. SWAPIN; /* Needed by shared heap. */
  3824. }
  3825. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  3826. if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) {
  3827. need += 1;
  3828. }
  3829. if (flags & MATCH_SET_RX_TRACE) {
  3830. need += 3;
  3831. }
  3832. if (need) {
  3833. ASSERT(c_p->htop <= E && E <= c_p->hend);
  3834. if (E - need < HTOP) {
  3835. /* SWAPOUT was done and r(0) was saved above */
  3836. PROCESS_MAIN_CHK_LOCKS(c_p);
  3837. FCALLS -= erts_garbage_collect(c_p, need, reg, I[-1]);
  3838. PROCESS_MAIN_CHK_LOCKS(c_p);
  3839. r(0) = reg[0];
  3840. SWAPIN;
  3841. }
  3842. }
  3843. if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) {
  3844. E -= 1;
  3845. ASSERT(c_p->htop <= E && E <= c_p->hend);
  3846. E[0] = make_cp(c_p->cp);
  3847. c_p->cp = (Eterm *) make_cp(beam_return_to_trace);
  3848. }
  3849. if (flags & MATCH_SET_RX_TRACE) {
  3850. E -= 3;
  3851. ASSERT(c_p->htop <= E && E <= c_p->hend);
  3852. ASSERT(is_CP((Eterm) (I - 3)));
  3853. ASSERT(am_true == tracer_pid ||
  3854. is_internal_pid(tracer_pid) || is_internal_port(tracer_pid));
  3855. E[2] = make_cp(c_p->cp);
  3856. E[1] = tracer_pid;
  3857. E[0] = make_cp(I - 3); /* We ARE at the beginning of an
  3858. instruction,
  3859. the funcinfo is above i. */
  3860. c_p->cp = (Eterm*)
  3861. make_cp(flags & MATCH_SET_EXCEPTION_TRACE
  3862. ? beam_exception_trace : beam_return_trace);
  3863. erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
  3864. c_p->trace_flags |= F_EXCEPTION_TRACE;
  3865. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
  3866. }
  3867. Goto(real_I);
  3868. }
  3869. OpCase(i_return_to_trace): {
  3870. if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO)) {
  3871. Uint *cpp = (Uint*) E;
  3872. for(;;) {
  3873. ASSERT(is_CP(*cpp));
  3874. if (*cp_val(*cpp) == (Uint) OpCode(return_trace)) {
  3875. do ++cpp; while(is_not_CP(*cpp));
  3876. cpp += 2;
  3877. } else if (*cp_val(*cpp) == (Uint) OpCode(i_return_to_trace)) {
  3878. do ++cpp; while(is_not_CP(*cpp));
  3879. } else break;
  3880. }
  3881. SWAPOUT; /* Needed for shared heap */
  3882. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  3883. erts_trace_return_to(c_p, cp_val(*cpp));
  3884. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  3885. SWAPIN;
  3886. }
  3887. c_p->cp = NULL;
  3888. SET_I((Eterm *) E[0]);
  3889. E += 1;
  3890. Goto(*I);
  3891. }
  3892. /*
  3893. * Instructions for allocating on the message area.
  3894. */
  3895. OpCase(i_global_cons):
  3896. {
  3897. Eterm *next;
  3898. #ifdef HYBRID
  3899. Eterm *hp;
  3900. PreFetch(0,next);
  3901. TestGlobalHeap(2,2,hp);
  3902. hp[0] = r(0);
  3903. hp[1] = x(1);
  3904. r(0) = make_list(hp);
  3905. #ifndef INCREMENTAL
  3906. global_htop += 2;
  3907. #endif
  3908. NextPF(0,next);
  3909. #else
  3910. PreFetch(0,next);
  3911. c_p->freason = EXC_INTERNAL_ERROR;
  3912. goto find_func_info;
  3913. #endif
  3914. }
  3915. OpCase(i_global_tuple):
  3916. {
  3917. Eterm *next;
  3918. int len;
  3919. #ifdef HYBRID
  3920. Eterm list;
  3921. Eterm *hp;
  3922. #endif
  3923. if ((len = list_length(r(0))) < 0) {
  3924. goto badarg;
  3925. }
  3926. PreFetch(0,next);
  3927. #ifdef HYBRID
  3928. TestGlobalHeap(len + 1,1,hp);
  3929. list = r(0);
  3930. r(0) = make_tuple(hp);
  3931. *hp++ = make_arityval(len);
  3932. while(is_list(list))
  3933. {
  3934. Eterm* cons = list_val(list);
  3935. *hp++ = CAR(cons);
  3936. list = CDR(cons);
  3937. }
  3938. #ifndef INCREMENTAL
  3939. global_htop += len + 1;
  3940. #endif
  3941. NextPF(0,next);
  3942. #else
  3943. c_p->freason = EXC_INTERNAL_ERROR;
  3944. goto find_func_info;
  3945. #endif
  3946. }
  3947. OpCase(i_global_copy):
  3948. {
  3949. Eterm *next;
  3950. PreFetch(0,next);
  3951. #ifdef HYBRID
  3952. if (!IS_CONST(r(0)))
  3953. {
  3954. BM_SWAP_TIMER(system,copy);
  3955. SWAPOUT;
  3956. reg[0] = r(0);
  3957. reg[1] = NIL;
  3958. r(0) = copy_struct_lazy(c_p,r(0),0);
  3959. ASSERT(ma_src_top == 0);
  3960. ASSERT(ma_dst_top == 0);
  3961. ASSERT(ma_offset_top == 0);
  3962. SWAPIN;
  3963. BM_SWAP_TIMER(copy,system);
  3964. }
  3965. NextPF(0,next);
  3966. #else
  3967. c_p->freason = EXC_INTERNAL_ERROR;
  3968. goto find_func_info;
  3969. #endif
  3970. }
  3971. /*
  3972. * New floating point instructions.
  3973. */
  3974. OpCase(fmove_ql): {
  3975. Eterm fr = Arg(1);
  3976. Eterm* next;
  3977. PreFetch(2, next);
  3978. GET_DOUBLE(Arg(0), *(FloatDef*)ADD_BYTE_OFFSET(freg, fr));
  3979. NextPF(2, next);
  3980. }
  3981. OpCase(fmove_dl): {
  3982. Eterm targ1;
  3983. Eterm fr = Arg(1);
  3984. Eterm* next;
  3985. PreFetch(2, next);
  3986. GetR(0, targ1);
  3987. /* Arg(0) == HEADER_FLONUM */
  3988. GET_DOUBLE(targ1, *(FloatDef*)ADD_BYTE_OFFSET(freg, fr));
  3989. NextPF(2, next);
  3990. }
  3991. OpCase(fmove_new_ld): {
  3992. Eterm fr = Arg(0);
  3993. Eterm dest = make_float(HTOP);
  3994. PUT_DOUBLE(*(FloatDef*)ADD_BYTE_OFFSET(freg, fr), HTOP);
  3995. HTOP += FLOAT_SIZE_OBJECT;
  3996. StoreBifResult(1, dest);
  3997. }
  3998. OpCase(fconv_dl): {
  3999. Eterm targ1;
  4000. Eterm fr = Arg(1);
  4001. Eterm* next;
  4002. GetR(0, targ1);
  4003. PreFetch(2, next);
  4004. if (is_small(targ1)) {
  4005. fb(fr) = (double) signed_val(targ1);
  4006. } else if (is_big(targ1)) {
  4007. if (big_to_double(targ1, &fb(fr)) < 0) {
  4008. goto fbadarith;
  4009. }
  4010. } else if (is_float(targ1)) {
  4011. GET_DOUBLE(targ1, *(FloatDef*)ADD_BYTE_OFFSET(freg, fr));
  4012. } else {
  4013. goto fbadarith;
  4014. }
  4015. NextPF(2, next);
  4016. }
  4017. /*
  4018. * Old allocating fmove.
  4019. */
  4020. #ifdef NO_FPE_SIGNALS
  4021. OpCase(fclearerror):
  4022. OpCase(i_fcheckerror):
  4023. erl_exit(1, "fclearerror/i_fcheckerror without fpe signals (beam_emu)");
  4024. #else
  4025. OpCase(fclearerror): {
  4026. Eterm* next;
  4027. PreFetch(0, next);
  4028. ERTS_FP_CHECK_INIT(c_p);
  4029. NextPF(0, next);
  4030. }
  4031. OpCase(i_fcheckerror): {
  4032. Eterm* next;
  4033. PreFetch(0, next);
  4034. ERTS_FP_ERROR(c_p, freg[0].fd, goto fbadarith);
  4035. NextPF(0, next);
  4036. }
  4037. # undef ERTS_FP_CHECK_INIT
  4038. # undef ERTS_FP_ERROR
  4039. # define ERTS_FP_CHECK_INIT(p)
  4040. # define ERTS_FP_ERROR(p, a, b)
  4041. #endif
  4042. OpCase(i_fadd_lll): {
  4043. Eterm* next;
  4044. PreFetch(3, next);
  4045. ERTS_FP_CHECK_INIT(c_p);
  4046. fb(Arg(2)) = fb(Arg(0)) + fb(Arg(1));
  4047. ERTS_FP_ERROR(c_p, fb(Arg(2)), goto fbadarith);
  4048. NextPF(3, next);
  4049. }
  4050. OpCase(i_fsub_lll): {
  4051. Eterm* next;
  4052. PreFetch(3, next);
  4053. ERTS_FP_CHECK_INIT(c_p);
  4054. fb(Arg(2)) = fb(Arg(0)) - fb(Arg(1));
  4055. ERTS_FP_ERROR(c_p, fb(Arg(2)), goto fbadarith);
  4056. NextPF(3, next);
  4057. }
  4058. OpCase(i_fmul_lll): {
  4059. Eterm* next;
  4060. PreFetch(3, next);
  4061. ERTS_FP_CHECK_INIT(c_p);
  4062. fb(Arg(2)) = fb(Arg(0)) * fb(Arg(1));
  4063. ERTS_FP_ERROR(c_p, fb(Arg(2)), goto fbadarith);
  4064. NextPF(3, next);
  4065. }
  4066. OpCase(i_fdiv_lll): {
  4067. Eterm* next;
  4068. PreFetch(3, next);
  4069. ERTS_FP_CHECK_INIT(c_p);
  4070. fb(Arg(2)) = fb(Arg(0)) / fb(Arg(1));
  4071. ERTS_FP_ERROR(c_p, fb(Arg(2)), goto fbadarith);
  4072. NextPF(3, next);
  4073. }
  4074. OpCase(i_fnegate_ll): {
  4075. Eterm* next;
  4076. PreFetch(2, next);
  4077. ERTS_FP_CHECK_INIT(c_p);
  4078. fb(Arg(1)) = -fb(Arg(0));
  4079. ERTS_FP_ERROR(c_p, fb(Arg(1)), goto fbadarith);
  4080. NextPF(2, next);
  4081. fbadarith:
  4082. c_p->freason = BADARITH;
  4083. goto find_func_info;
  4084. }
  4085. #ifdef HIPE
  4086. {
  4087. unsigned cmd;
  4088. OpCase(hipe_trap_call): {
  4089. /*
  4090. * I[-5]: &&lb_i_func_info_IaaI
  4091. * I[-4]: Native code callee (inserted by HiPE)
  4092. * I[-3]: Module (tagged atom)
  4093. * I[-2]: Function (tagged atom)
  4094. * I[-1]: Arity (untagged integer)
  4095. * I[ 0]: &&lb_hipe_trap_call
  4096. * ... remainder of original BEAM code
  4097. */
  4098. ASSERT(I[-5] == (Uint) OpCode(i_func_info_IaaI));
  4099. c_p->hipe.ncallee = (void(*)(void)) I[-4];
  4100. cmd = HIPE_MODE_SWITCH_CMD_CALL | (I[-1] << 8);
  4101. ++hipe_trap_count;
  4102. goto L_hipe_mode_switch;
  4103. }
  4104. OpCase(hipe_trap_call_closure): {
  4105. ASSERT(I[-5] == (Uint) OpCode(i_func_info_IaaI));
  4106. c_p->hipe.ncallee = (void(*)(void)) I[-4];
  4107. cmd = HIPE_MODE_SWITCH_CMD_CALL_CLOSURE | (I[-1] << 8);
  4108. ++hipe_trap_count;
  4109. goto L_hipe_mode_switch;
  4110. }
  4111. OpCase(hipe_trap_return): {
  4112. cmd = HIPE_MODE_SWITCH_CMD_RETURN;
  4113. goto L_hipe_mode_switch;
  4114. }
  4115. OpCase(hipe_trap_throw): {
  4116. cmd = HIPE_MODE_SWITCH_CMD_THROW;
  4117. goto L_hipe_mode_switch;
  4118. }
  4119. OpCase(hipe_trap_resume): {
  4120. cmd = HIPE_MODE_SWITCH_CMD_RESUME;
  4121. goto L_hipe_mode_switch;
  4122. }
  4123. L_hipe_mode_switch:
  4124. /* XXX: this abuse of def_arg_reg[] is horrid! */
  4125. SWAPOUT;
  4126. c_p->fcalls = FCALLS;
  4127. c_p->def_arg_reg[4] = -neg_o_reds;
  4128. reg[0] = r(0);
  4129. c_p = hipe_mode_switch(c_p, cmd, reg);
  4130. #ifdef ERTS_SMP
  4131. reg = c_p->scheduler_data->save_reg;
  4132. freg = c_p->scheduler_data->freg;
  4133. #endif
  4134. ERL_BITS_RELOAD_STATEP(c_p);
  4135. neg_o_reds = -c_p->def_arg_reg[4];
  4136. FCALLS = c_p->fcalls;
  4137. SWAPIN;
  4138. switch( c_p->def_arg_reg[3] ) {
  4139. case HIPE_MODE_SWITCH_RES_RETURN:
  4140. ASSERT(is_value(reg[0]));
  4141. MoveReturn(reg[0], r(0));
  4142. case HIPE_MODE_SWITCH_RES_CALL:
  4143. SET_I(c_p->i);
  4144. r(0) = reg[0];
  4145. Dispatch();
  4146. case HIPE_MODE_SWITCH_RES_CALL_CLOSURE:
  4147. /* This can be used to call any function value, but currently it's
  4148. only used to call closures referring to unloaded modules. */
  4149. {
  4150. Eterm *next;
  4151. next = call_fun(c_p, c_p->arity - 1, reg, THE_NON_VALUE);
  4152. SWAPIN;
  4153. if (next != NULL) {
  4154. r(0) = reg[0];
  4155. SET_I(next);
  4156. Dispatchfun();
  4157. }
  4158. goto find_func_info;
  4159. }
  4160. case HIPE_MODE_SWITCH_RES_THROW:
  4161. c_p->cp = NULL;
  4162. I = handle_error(c_p, I, reg, NULL);
  4163. goto post_error_handling;
  4164. default:
  4165. erl_exit(1, "hipe_mode_switch: result %u\n", c_p->def_arg_reg[3]);
  4166. }
  4167. }
  4168. OpCase(hipe_call_count): {
  4169. /*
  4170. * I[-5]: &&lb_i_func_info_IaaI
  4171. * I[-4]: pointer to struct hipe_call_count (inserted by HiPE)
  4172. * I[-3]: Module (tagged atom)
  4173. * I[-2]: Function (tagged atom)
  4174. * I[-1]: Arity (untagged integer)
  4175. * I[ 0]: &&lb_hipe_call_count
  4176. * ... remainder of original BEAM code
  4177. */
  4178. struct hipe_call_count *hcc = (struct hipe_call_count*)I[-4];
  4179. ASSERT(I[-5] == (Uint) OpCode(i_func_info_IaaI));
  4180. ASSERT(hcc != NULL);
  4181. ASSERT(VALID_INSTR(hcc->opcode));
  4182. ++(hcc->count);
  4183. Goto(hcc->opcode);
  4184. }
  4185. #endif /* HIPE */
  4186. OpCase(i_yield):
  4187. {
  4188. /* This is safe as long as REDS_IN(c_p) is never stored
  4189. * in c_p->arg_reg[0]. It is currently stored in c_p->def_arg_reg[5],
  4190. * which may be c_p->arg_reg[5], which is close, but no banana.
  4191. */
  4192. c_p->arg_reg[0] = am_true;
  4193. c_p->arity = 1; /* One living register (the 'true' return value) */
  4194. SWAPOUT;
  4195. c_p->i = I + 1; /* Next instruction */
  4196. erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_STATUS);
  4197. erts_add_to_runq(c_p);
  4198. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS);
  4199. c_p->current = NULL;
  4200. goto do_schedule;
  4201. }
  4202. OpCase(i_hibernate): {
  4203. SWAPOUT;
  4204. if (hibernate(c_p, r(0), x(1), x(2), reg)) {
  4205. goto do_schedule;
  4206. } else {
  4207. I = handle_error(c_p, I, reg, hibernate_3);
  4208. goto post_error_handling;
  4209. }
  4210. }
  4211. OpCase(i_debug_breakpoint): {
  4212. SWAPOUT;
  4213. reg[0] = r(0);
  4214. tmp_arg1 = call_breakpoint_handler(c_p, I-3, reg);
  4215. r(0) = reg[0];
  4216. SWAPIN;
  4217. if (tmp_arg1) {
  4218. SET_I(c_p->i);
  4219. Dispatch();
  4220. }
  4221. goto no_error_handler;
  4222. }
  4223. OpCase(system_limit_j):
  4224. system_limit:
  4225. c_p->freason = SYSTEM_LIMIT;
  4226. goto lb_Cl_error;
  4227. #ifdef ERTS_OPCODE_COUNTER_SUPPORT
  4228. DEFINE_COUNTING_LABELS;
  4229. #endif
  4230. #ifndef NO_JUMP_TABLE
  4231. #ifdef DEBUG
  4232. end_emulator_loop:
  4233. #endif
  4234. #endif
  4235. OpCase(int_code_end):
  4236. OpCase(label_L):
  4237. OpCase(too_old_compiler):
  4238. erl_exit(1, "meta op\n");
  4239. /*
  4240. * One-time initialization of Beam emulator.
  4241. */
  4242. init_emulator:
  4243. {
  4244. int i;
  4245. Export* ep;
  4246. #ifndef NO_JUMP_TABLE
  4247. #ifdef ERTS_OPCODE_COUNTER_SUPPORT
  4248. /* Are tables correctly generated by beam_makeops? */
  4249. ASSERT(sizeof(counting_opcodes) == sizeof(opcodes));
  4250. if (count_instructions) {
  4251. #ifdef DEBUG
  4252. counting_opcodes[op_catch_end_y] = LabelAddr(lb_catch_end_y);
  4253. #endif
  4254. counting_opcodes[op_i_func_info_IaaI] = LabelAddr(lb_i_func_info_IaaI);
  4255. beam_ops = counting_opcodes;
  4256. }
  4257. else
  4258. #endif /* #ifndef ERTS_OPCODE_COUNTER_SUPPORT */
  4259. {
  4260. beam_ops = opcodes;
  4261. }
  4262. #endif /* NO_JUMP_TABLE */
  4263. em_call_error_handler = OpCode(call_error_handler);
  4264. em_call_traced_function = OpCode(call_traced_function);
  4265. em_apply_bif = OpCode(apply_bif);
  4266. beam_apply[0] = (Eterm) OpCode(i_apply);
  4267. beam_apply[1] = (Eterm) OpCode(normal_exit);
  4268. beam_exit[0] = (Eterm) OpCode(error_action_code);
  4269. beam_continue_exit[0] = (Eterm) OpCode(continue_exit);
  4270. beam_return_to_trace[0] = (Eterm) OpCode(i_return_to_trace);
  4271. beam_return_trace[0] = (Eterm) OpCode(return_trace);
  4272. beam_exception_trace[0] = (Eterm) OpCode(return_trace); /* UGLY */
  4273. /*
  4274. * Enter all BIFs into the export table.
  4275. */
  4276. for (i = 0; i < BIF_SIZE; i++) {
  4277. ep = erts_export_put(bif_table[i].module,
  4278. bif_table[i].name,
  4279. bif_table[i].arity);
  4280. bif_export[i] = ep;
  4281. ep->code[3] = (Eterm) OpCode(apply_bif);
  4282. ep->code[4] = (Eterm) bif_table[i].f;
  4283. }
  4284. return;
  4285. }
  4286. #ifdef NO_JUMP_TABLE
  4287. default:
  4288. erl_exit(1, "unexpected op code %d\n",Go);
  4289. }
  4290. #endif
  4291. return; /* Never executed */
  4292. save_calls1:
  4293. {
  4294. Eterm* dis_next;
  4295. save_calls(c_p, (Export *) Arg(0));
  4296. SET_I(((Export *) Arg(0))->address);
  4297. dis_next = (Eterm *) *I;
  4298. FCALLS--;
  4299. Goto(dis_next);
  4300. }
  4301. }
  4302. static BifFunction
  4303. translate_gc_bif(void* gcf)
  4304. {
  4305. if (gcf == erts_gc_length_1) {
  4306. return length_1;
  4307. } else if (gcf == erts_gc_size_1) {
  4308. return size_1;
  4309. } else if (gcf == erts_gc_bit_size_1) {
  4310. return bit_size_1;
  4311. } else if (gcf == erts_gc_byte_size_1) {
  4312. return byte_size_1;
  4313. } else if (gcf == erts_gc_abs_1) {
  4314. return abs_1;
  4315. } else if (gcf == erts_gc_float_1) {
  4316. return float_1;
  4317. } else if (gcf == erts_gc_round_1) {
  4318. return round_1;
  4319. } else if (gcf == erts_gc_trunc_1) {
  4320. return round_1;
  4321. } else {
  4322. erl_exit(1, "bad gc bif");
  4323. }
  4324. }
  4325. /*
  4326. * Mapping from the error code 'class tag' to atoms.
  4327. */
  4328. Eterm exception_tag[NUMBER_EXC_TAGS] = {
  4329. am_error, /* 0 */
  4330. am_exit, /* 1 */
  4331. am_throw, /* 2 */
  4332. };
  4333. /*
  4334. * Mapping from error code 'index' to atoms.
  4335. */
  4336. Eterm error_atom[NUMBER_EXIT_CODES] = {
  4337. am_internal_error, /* 0 */
  4338. am_normal, /* 1 */
  4339. am_internal_error, /* 2 */
  4340. am_badarg, /* 3 */
  4341. am_badarith, /* 4 */
  4342. am_badmatch, /* 5 */
  4343. am_function_clause, /* 6 */
  4344. am_case_clause, /* 7 */
  4345. am_if_clause, /* 8 */
  4346. am_undef, /* 9 */
  4347. am_badfun, /* 10 */
  4348. am_badarity, /* 11 */
  4349. am_timeout_value, /* 12 */
  4350. am_noproc, /* 13 */
  4351. am_notalive, /* 14 */
  4352. am_system_limit, /* 15 */
  4353. am_try_clause, /* 16 */
  4354. am_notsup /* 17 */
  4355. };
  4356. /*
  4357. * To fully understand the error handling, one must keep in mind that
  4358. * when an exception is thrown, the search for a handler can jump back
  4359. * and forth between Beam and native code. Upon each mode switch, a
  4360. * dummy handler is inserted so that if an exception reaches that point,
  4361. * the handler is invoked (like any handler) and transfers control so
  4362. * that the search for a real handler is continued in the other mode.
  4363. * Therefore, c_p->freason and c_p->fvalue must still hold the exception
  4364. * info when the handler is executed, but normalized so that creation of
  4365. * error terms and saving of the stack trace is only done once, even if
  4366. * we pass through the error handling code several times.
  4367. *
  4368. * When a new exception is raised, the current stack trace information
  4369. * is quick-saved in a small structure allocated on the heap. Depending
  4370. * on how the exception is eventually caught (perhaps by causing the
  4371. * current process to terminate), the saved information may be used to
  4372. * create a symbolic (human-readable) representation of the stack trace
  4373. * at the point of the original exception.
  4374. */
  4375. static Eterm*
  4376. handle_error(Process* c_p, Eterm* pc, Eterm* reg, BifFunction bf)
  4377. {
  4378. Eterm* hp;
  4379. Eterm Value = c_p->fvalue;
  4380. Eterm Args = am_true;
  4381. c_p->i = pc; /* In case we call erl_exit(). */
  4382. ASSERT(c_p->freason != TRAP); /* Should have been handled earlier. */
  4383. /*
  4384. * Check if we have an arglist for the top level call. If so, this
  4385. * is encoded in Value, so we have to dig out the real Value as well
  4386. * as the Arglist.
  4387. */
  4388. if (c_p->freason & EXF_ARGLIST) {
  4389. Eterm* tp;
  4390. ASSERT(is_tuple(Value));
  4391. tp = tuple_val(Value);
  4392. Value = tp[1];
  4393. Args = tp[2];
  4394. }
  4395. /*
  4396. * Save the stack trace info if the EXF_SAVETRACE flag is set. The
  4397. * main reason for doing this separately is to allow throws to later
  4398. * become promoted to errors without losing the original stack
  4399. * trace, even if they have passed through one or more catch and
  4400. * rethrow. It also makes the creation of symbolic stack traces much
  4401. * more modular.
  4402. */
  4403. if (c_p->freason & EXF_SAVETRACE) {
  4404. save_stacktrace(c_p, pc, reg, bf, Args);
  4405. }
  4406. /*
  4407. * Throws that are not caught are turned into 'nocatch' errors
  4408. */
  4409. if ((c_p->freason & EXF_THROWN) && (c_p->catches <= 0) ) {
  4410. hp = HAlloc(c_p, 3);
  4411. Value = TUPLE2(hp, am_nocatch, Value);
  4412. c_p->freason = EXC_ERROR;
  4413. }
  4414. /* Get the fully expanded error term */
  4415. Value = expand_error_value(c_p, c_p->freason, Value);
  4416. /* Save final error term and stabilize the exception flags so no
  4417. further expansion is done. */
  4418. c_p->fvalue = Value;
  4419. c_p->freason = PRIMARY_EXCEPTION(c_p->freason);
  4420. /* Find a handler or die */
  4421. if ((c_p->catches > 0 || IS_TRACED_FL(c_p, F_EXCEPTION_TRACE))
  4422. && !(c_p->freason & EXF_PANIC)) {
  4423. Eterm *new_pc;
  4424. /* The Beam handler code (catch_end or try_end) checks reg[0]
  4425. for THE_NON_VALUE to see if the previous code finished
  4426. abnormally. If so, reg[1], reg[2] and reg[3] should hold the
  4427. exception class, term and trace, respectively. (If the
  4428. handler is just a trap to native code, these registers will
  4429. be ignored.) */
  4430. reg[0] = THE_NON_VALUE;
  4431. reg[1] = exception_tag[GET_EXC_CLASS(c_p->freason)];
  4432. reg[2] = Value;
  4433. reg[3] = c_p->ftrace;
  4434. if ((new_pc = next_catch(c_p, reg))) {
  4435. c_p->cp = 0; /* To avoid keeping stale references. */
  4436. return new_pc;
  4437. }
  4438. if (c_p->catches > 0) erl_exit(1, "Catch not found");
  4439. }
  4440. ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
  4441. terminate_proc(c_p, Value);
  4442. ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
  4443. return NULL;
  4444. }
  4445. /*
  4446. * Find the nearest catch handler
  4447. */
  4448. static Eterm*
  4449. next_catch(Process* c_p, Eterm *reg) {
  4450. int active_catches = c_p->catches > 0;
  4451. int have_return_to_trace = 0;
  4452. Eterm *ptr, *prev, *return_to_trace_ptr = NULL;
  4453. Uint i_return_trace = beam_return_trace[0];
  4454. Uint i_return_to_trace = beam_return_to_trace[0];
  4455. ptr = prev = c_p->stop;
  4456. ASSERT(is_CP(*ptr));
  4457. ASSERT(ptr <= STACK_START(c_p));
  4458. if (ptr == STACK_START(c_p)) return NULL;
  4459. if ((is_not_CP(*ptr) || (*cp_val(*ptr) != i_return_trace &&
  4460. *cp_val(*ptr) != i_return_to_trace))
  4461. && c_p->cp) {
  4462. /* Can not follow cp here - code may be unloaded */
  4463. Uint *cpp = cp_val((Eterm) c_p->cp);
  4464. if (cpp == beam_exception_trace) {
  4465. erts_trace_exception(c_p, (Eterm*) ptr[0],
  4466. reg[1], reg[2], ptr+1);
  4467. /* Skip return_trace parameters */
  4468. ptr += 2;
  4469. } else if (cpp == beam_return_trace) {
  4470. /* Skip return_trace parameters */
  4471. ptr += 2;
  4472. } else if (cpp == beam_return_to_trace) {
  4473. have_return_to_trace = !0; /* Record next cp */
  4474. }
  4475. }
  4476. while (ptr < STACK_START(c_p)) {
  4477. if (is_catch(*ptr)) {
  4478. if (active_catches) goto found_catch;
  4479. ptr++;
  4480. }
  4481. else if (is_CP(*ptr)) {
  4482. prev = ptr;
  4483. if (*cp_val(*prev) == i_return_trace) {
  4484. /* Skip stack frame variables */
  4485. while (++ptr, ptr < STACK_START(c_p) && is_not_CP(*ptr)) {
  4486. if (is_catch(*ptr) && active_catches) goto found_catch;
  4487. }
  4488. if (cp_val(*prev) == beam_exception_trace) {
  4489. erts_trace_exception(c_p, (Eterm*) ptr[0],
  4490. reg[1], reg[2], ptr+1);
  4491. }
  4492. /* Skip return_trace parameters */
  4493. ptr += 2;
  4494. } else if (*cp_val(*prev) == i_return_to_trace) {
  4495. /* Skip stack frame variables */
  4496. while (++ptr, ptr < STACK_START(c_p) && is_not_CP(*ptr)) {
  4497. if (is_catch(*ptr) && active_catches) goto found_catch;
  4498. }
  4499. have_return_to_trace = !0; /* Record next cp */
  4500. return_to_trace_ptr = NULL;
  4501. } else {
  4502. if (have_return_to_trace) {
  4503. /* Record this cp as possible return_to trace cp */
  4504. have_return_to_trace = 0;
  4505. return_to_trace_ptr = ptr;
  4506. } else return_to_trace_ptr = NULL;
  4507. ptr++;
  4508. }
  4509. } else ptr++;
  4510. }
  4511. return NULL;
  4512. found_catch:
  4513. ASSERT(ptr < STACK_START(c_p));
  4514. c_p->stop = prev;
  4515. if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO) && return_to_trace_ptr) {
  4516. /* The stackframe closest to the catch contained an
  4517. * return_to_trace entry, so since the execution now
  4518. * continues after the catch, a return_to trace message
  4519. * would be appropriate.
  4520. */
  4521. erts_trace_return_to(c_p, cp_val(*return_to_trace_ptr));
  4522. }
  4523. return catch_pc(*ptr);
  4524. }
  4525. /*
  4526. * Terminating the process when an exception is not caught
  4527. */
  4528. static void
  4529. terminate_proc(Process* c_p, Eterm Value)
  4530. {
  4531. /* Add a stacktrace if this is an error. */
  4532. if (GET_EXC_CLASS(c_p->freason) == EXTAG_ERROR) {
  4533. Value = add_stacktrace(c_p, Value, c_p->ftrace);
  4534. }
  4535. /* EXF_LOG is a primary exception flag */
  4536. if (c_p->freason & EXF_LOG) {
  4537. erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
  4538. erts_dsprintf(dsbufp, "Error in process %T ", c_p->id);
  4539. if (erts_is_alive)
  4540. erts_dsprintf(dsbufp, "on node %T ", erts_this_node->sysname);
  4541. erts_dsprintf(dsbufp,"with exit value: %0.*T\n", display_items, Value);
  4542. erts_send_error_to_logger(c_p->group_leader, dsbufp);
  4543. }
  4544. /*
  4545. * If we use a shared heap, the process will be garbage-collected.
  4546. * Must zero c_p->arity to indicate that there are no live registers.
  4547. */
  4548. c_p->arity = 0;
  4549. erts_do_exit_process(c_p, Value);
  4550. }
  4551. /*
  4552. * Build and add a symbolic stack trace to the error value.
  4553. */
  4554. static Eterm
  4555. add_stacktrace(Process* c_p, Eterm Value, Eterm exc) {
  4556. Eterm Where = build_stacktrace(c_p, exc);
  4557. Eterm* hp = HAlloc(c_p, 3);
  4558. return TUPLE2(hp, Value, Where);
  4559. }
  4560. /*
  4561. * Forming the correct error value from the internal error code.
  4562. * This does not update c_p->fvalue or c_p->freason.
  4563. */
  4564. Eterm
  4565. expand_error_value(Process* c_p, Uint freason, Eterm Value) {
  4566. Eterm* hp;
  4567. Uint r;
  4568. r = GET_EXC_INDEX(freason);
  4569. ASSERT(r < NUMBER_EXIT_CODES); /* range check */
  4570. ASSERT(is_value(Value));
  4571. switch (r) {
  4572. case (GET_EXC_INDEX(EXC_PRIMARY)):
  4573. /* Primary exceptions use fvalue as it is */
  4574. break;
  4575. case (GET_EXC_INDEX(EXC_BADMATCH)):
  4576. case (GET_EXC_INDEX(EXC_CASE_CLAUSE)):
  4577. case (GET_EXC_INDEX(EXC_TRY_CLAUSE)):
  4578. case (GET_EXC_INDEX(EXC_BADFUN)):
  4579. case (GET_EXC_INDEX(EXC_BADARITY)):
  4580. /* Some common exceptions: value -> {atom, value} */
  4581. ASSERT(is_value(Value));
  4582. hp = HAlloc(c_p, 3);
  4583. Value = TUPLE2(hp, error_atom[r], Value);
  4584. break;
  4585. default:
  4586. /* Other exceptions just use an atom as descriptor */
  4587. Value = error_atom[r];
  4588. break;
  4589. }
  4590. #ifdef DEBUG
  4591. ASSERT(Value != am_internal_error);
  4592. #endif
  4593. return Value;
  4594. }
  4595. /*
  4596. * Quick-saving the stack trace in an internal form on the heap. Note
  4597. * that c_p->ftrace will point to a cons cell which holds the given args
  4598. * and the saved data (encoded as a bignum).
  4599. *
  4600. * (It would be much better to put the arglist - when it exists - in the
  4601. * error value instead of in the actual trace; e.g. '{badarg, Args}'
  4602. * instead of using 'badarg' with Args in the trace. The arglist may
  4603. * contain very large values, and right now they will be kept alive as
  4604. * long as the stack trace is live. Preferably, the stack trace should
  4605. * always be small, so that it does not matter if it is long-lived.
  4606. * However, it is probably not possible to ever change the format of
  4607. * error terms.)
  4608. */
  4609. static void
  4610. save_stacktrace(Process* c_p, Eterm* pc, Eterm* reg, BifFunction bf,
  4611. Eterm args) {
  4612. struct StackTrace* s;
  4613. int sz;
  4614. int depth = erts_backtrace_depth; /* max depth (never negative) */
  4615. if (depth > 0) {
  4616. /* There will always be a current function */
  4617. depth --;
  4618. }
  4619. /* Create a container for the exception data */
  4620. sz = (offsetof(struct StackTrace, trace) + sizeof(Eterm)*depth
  4621. + sizeof(Eterm) - 1) / sizeof(Eterm);
  4622. s = (struct StackTrace *) HAlloc(c_p, 1 + sz);
  4623. /* The following fields are inside the bignum */
  4624. s->header = make_pos_bignum_header(sz);
  4625. s->freason = c_p->freason;
  4626. s->depth = 0;
  4627. /*
  4628. * If the failure was in a BIF other than 'error', 'exit' or
  4629. * 'throw', find the bif-table index and save the argument
  4630. * registers by consing up an arglist.
  4631. */
  4632. if (bf != NULL && bf != error_1 && bf != error_2 &&
  4633. bf != exit_1 && bf != throw_1) {
  4634. int i;
  4635. int a = 0;
  4636. for (i = 0; i < BIF_SIZE; i++) {
  4637. if (bf == bif_table[i].f || bf == bif_table[i].traced) {
  4638. Export *ep = bif_export[i];
  4639. s->current = ep->code;
  4640. a = bif_table[i].arity;
  4641. break;
  4642. }
  4643. }
  4644. if (i >= BIF_SIZE) {
  4645. /*
  4646. * The Bif does not really exist (no BIF entry). It is a
  4647. * TRAP and traps are called through apply_bif, which also
  4648. * sets c_p->current (luckily).
  4649. */
  4650. ASSERT(c_p->current);
  4651. s->current = c_p->current;
  4652. a = s->current[2];
  4653. ASSERT(s->current[2] <= 3);
  4654. }
  4655. /* Save first stack entry */
  4656. ASSERT(pc);
  4657. if (depth > 0) {
  4658. s->trace[s->depth++] = pc;
  4659. depth--;
  4660. }
  4661. /* Save second stack entry if CP is valid and different from pc */
  4662. if (depth > 0 && c_p->cp != 0 && c_p->cp != pc) {
  4663. s->trace[s->depth++] = c_p->cp;
  4664. depth--;
  4665. }
  4666. s->pc = NULL;
  4667. args = make_arglist(c_p, reg, a); /* Overwrite CAR(c_p->ftrace) */
  4668. } else {
  4669. s->current = c_p->current;
  4670. /*
  4671. * For a function_clause error, the arguments are in the beam
  4672. * registers, c_p->cp is valid, and c_p->current is set.
  4673. */
  4674. if ( (GET_EXC_INDEX(s->freason)) ==
  4675. (GET_EXC_INDEX(EXC_FUNCTION_CLAUSE)) ) {
  4676. int a;
  4677. ASSERT(s->current);
  4678. a = s->current[2];
  4679. args = make_arglist(c_p, reg, a); /* Overwrite CAR(c_p->ftrace) */
  4680. /* Save first stack entry */
  4681. ASSERT(c_p->cp);
  4682. if (depth > 0) {
  4683. s->trace[s->depth++] = c_p->cp;
  4684. depth--;
  4685. }
  4686. s->pc = NULL; /* Ignore pc */
  4687. } else {
  4688. if (depth > 0 && c_p->cp != 0 && c_p->cp != pc) {
  4689. s->trace[s->depth++] = c_p->cp;
  4690. depth--;
  4691. }
  4692. s->pc = pc;
  4693. }
  4694. }
  4695. /* Package args and stack trace */
  4696. {
  4697. Eterm *hp;
  4698. hp = HAlloc(c_p, 2);
  4699. c_p->ftrace = CONS(hp, args, make_big((Eterm *) s));
  4700. }
  4701. /* Save the actual stack trace */
  4702. if (depth > 0) {
  4703. Eterm *ptr, *prev = s->depth ? s->trace[s->depth-1] : NULL;
  4704. Uint i_return_trace = beam_return_trace[0];
  4705. Uint i_return_to_trace = beam_return_to_trace[0];
  4706. /*
  4707. * Traverse the stack backwards and add all unique continuation
  4708. * pointers to the buffer, up to the maximum stack trace size.
  4709. *
  4710. * Skip trace stack frames.
  4711. */
  4712. ptr = c_p->stop;
  4713. if (ptr < STACK_START(c_p)
  4714. && (is_not_CP(*ptr)|| (*cp_val(*ptr) != i_return_trace &&
  4715. *cp_val(*ptr) != i_return_to_trace))
  4716. && c_p->cp) {
  4717. /* Can not follow cp here - code may be unloaded */
  4718. Uint *cpp = cp_val((Eterm) c_p->cp);
  4719. if (cpp == beam_exception_trace || cpp == beam_return_trace) {
  4720. /* Skip return_trace parameters */
  4721. ptr += 2;
  4722. } else if (cpp == beam_return_to_trace) {
  4723. /* Skip return_to_trace parameters */
  4724. ptr += 1;
  4725. }
  4726. }
  4727. while (ptr < STACK_START(c_p) && depth > 0) {
  4728. if (is_CP(*ptr)) {
  4729. if (*cp_val(*ptr) == i_return_trace) {
  4730. /* Skip stack frame variables */
  4731. do ++ptr; while (is_not_CP(*ptr));
  4732. /* Skip return_trace parameters */
  4733. ptr += 2;
  4734. } else if (*cp_val(*ptr) == i_return_to_trace) {
  4735. /* Skip stack frame variables */
  4736. do ++ptr; while (is_not_CP(*ptr));
  4737. } else {
  4738. Eterm *cp = (Eterm *)(*ptr);
  4739. if (cp != prev) {
  4740. /* Record non-duplicates only */
  4741. prev = cp;
  4742. s->trace[s->depth++] = cp;
  4743. depth--;
  4744. }
  4745. ptr++;
  4746. }
  4747. } else ptr++;
  4748. }
  4749. }
  4750. }
  4751. /*
  4752. * Getting the relevant fields from the term pointed to by ftrace
  4753. */
  4754. static struct StackTrace *get_trace_from_exc(Eterm exc) {
  4755. if (exc == NIL) {
  4756. return NULL;
  4757. } else {
  4758. ASSERT(is_list(exc));
  4759. return (struct StackTrace *) big_val(CDR(list_val(exc)));
  4760. }
  4761. }
  4762. static Eterm get_args_from_exc(Eterm exc) {
  4763. if (exc == NIL) {
  4764. return NIL;
  4765. } else {
  4766. ASSERT(is_list(exc));
  4767. return CAR(list_val(exc));
  4768. }
  4769. }
  4770. static int is_raised_exc(Eterm exc) {
  4771. if (exc == NIL) {
  4772. return 0;
  4773. } else {
  4774. ASSERT(is_list(exc));
  4775. return bignum_header_is_neg(*big_val(CDR(list_val(exc))));
  4776. }
  4777. }
  4778. /*
  4779. * Creating a list with the argument registers
  4780. */
  4781. static Eterm
  4782. make_arglist(Process* c_p, Eterm* reg, int a) {
  4783. Eterm args = NIL;
  4784. Eterm* hp = HAlloc(c_p, 2*a);
  4785. while (a > 0) {
  4786. args = CONS(hp, reg[a-1], args);
  4787. hp += 2;
  4788. a--;
  4789. }
  4790. return args;
  4791. }
  4792. /*
  4793. * Building a symbolic representation of a saved stack trace. Note that
  4794. * the exception object 'exc', unless NIL, points to a cons cell which
  4795. * holds the given args and the quick-saved data (encoded as a bignum).
  4796. *
  4797. * If the bignum is negative, the given args is a complete stacktrace.
  4798. */
  4799. Eterm
  4800. build_stacktrace(Process* c_p, Eterm exc) {
  4801. struct StackTrace* s;
  4802. Eterm args;
  4803. int depth;
  4804. Eterm* current;
  4805. Eterm Where = NIL;
  4806. Eterm* next_p = &Where;
  4807. if (! (s = get_trace_from_exc(exc))) {
  4808. return NIL;
  4809. }
  4810. #ifdef HIPE
  4811. if (s->freason & EXF_NATIVE) {
  4812. return hipe_build_stacktrace(c_p, s);
  4813. }
  4814. #endif
  4815. if (is_raised_exc(exc)) {
  4816. return get_args_from_exc(exc);
  4817. }
  4818. /*
  4819. * Find the current function. If the saved s->pc is null, then the
  4820. * saved s->current should already contain the proper value.
  4821. */
  4822. if (s->pc != NULL) {
  4823. current = find_function_from_pc(s->pc);
  4824. } else {
  4825. current = s->current;
  4826. }
  4827. /*
  4828. * If current is still NULL, default to the initial function
  4829. * (e.g. spawn_link(erlang, abs, [1])).
  4830. */
  4831. if (current == NULL) {
  4832. current = c_p->initial;
  4833. args = am_true; /* Just in case */
  4834. } else {
  4835. args = get_args_from_exc(exc);
  4836. }
  4837. depth = s->depth;
  4838. /*
  4839. * Add the {M,F,A} for the current function
  4840. * (where A is arity or [Argument]).
  4841. */
  4842. {
  4843. int i;
  4844. Eterm mfa;
  4845. Uint heap_size = 6*(depth+1);
  4846. Eterm* hp = HAlloc(c_p, heap_size);
  4847. Eterm* hp_end = hp + heap_size;
  4848. if (args != am_true) {
  4849. /* We have an arglist - use it */
  4850. mfa = TUPLE3(hp, current[0], current[1], args);
  4851. } else {
  4852. Eterm arity = make_small(current[2]);
  4853. mfa = TUPLE3(hp, current[0], current[1], arity);
  4854. }
  4855. hp += 4;
  4856. ASSERT(*next_p == NIL);
  4857. *next_p = CONS(hp, mfa, NIL);
  4858. next_p = &CDR(list_val(*next_p));
  4859. hp += 2;
  4860. /*
  4861. * Finally, we go through the saved continuation pointers.
  4862. */
  4863. for (i = 0; i < depth; i++) {
  4864. Eterm *fi = find_function_from_pc((Eterm *) s->trace[i]);
  4865. if (fi == NULL) continue;
  4866. mfa = TUPLE3(hp, fi[0], fi[1], make_small(fi[2]));
  4867. hp += 4;
  4868. ASSERT(*next_p == NIL);
  4869. *next_p = CONS(hp, mfa, NIL);
  4870. next_p = &CDR(list_val(*next_p));
  4871. hp += 2;
  4872. }
  4873. ASSERT(hp <= hp_end);
  4874. HRelease(c_p, hp_end, hp);
  4875. }
  4876. return Where;
  4877. }
  4878. static Eterm
  4879. call_error_handler(Process* p, Eterm* fi, Eterm* reg)
  4880. {
  4881. Eterm* hp;
  4882. Export* ep;
  4883. int arity;
  4884. Eterm args;
  4885. Uint sz;
  4886. int i;
  4887. /*
  4888. * Search for the error_handler module.
  4889. */
  4890. ep = erts_find_function(erts_proc_get_error_handler(p),
  4891. am_undefined_function, 3);
  4892. if (ep == NULL) { /* No error handler */
  4893. p->current = fi;
  4894. p->freason = EXC_UNDEF;
  4895. return 0;
  4896. }
  4897. p->i = ep->address;
  4898. /*
  4899. * Create a list with all arguments in the x registers.
  4900. */
  4901. arity = fi[2];
  4902. sz = 2 * arity;
  4903. if (HeapWordsLeft(p) < sz) {
  4904. erts_garbage_collect(p, sz, reg, arity);
  4905. }
  4906. hp = HEAP_TOP(p);
  4907. HEAP_TOP(p) += sz;
  4908. args = NIL;
  4909. for (i = arity-1; i >= 0; i--) {
  4910. args = CONS(hp, reg[i], args);
  4911. hp += 2;
  4912. }
  4913. /*
  4914. * Set up registers for call to error_handler:undefined_function/3.
  4915. */
  4916. reg[0] = fi[0];
  4917. reg[1] = fi[1];
  4918. reg[2] = args;
  4919. return 1;
  4920. }
  4921. static Eterm
  4922. call_breakpoint_handler(Process* p, Eterm* fi, Eterm* reg)
  4923. {
  4924. Eterm* hp;
  4925. Export* ep;
  4926. int arity;
  4927. Eterm args;
  4928. Uint sz;
  4929. int i;
  4930. /*
  4931. * Search for error handler module.
  4932. */
  4933. ep = erts_find_function(erts_proc_get_error_handler(p),
  4934. am_breakpoint, 3);
  4935. if (ep == NULL) { /* No error handler */
  4936. p->current = fi;
  4937. p->freason = EXC_UNDEF;
  4938. return 0;
  4939. }
  4940. p->i = ep->address;
  4941. /*
  4942. * Create a list with all arguments in the x registers.
  4943. */
  4944. arity = fi[2];
  4945. sz = 2 * arity;
  4946. if (HeapWordsLeft(p) < sz) {
  4947. erts_garbage_collect(p, sz, reg, arity);
  4948. }
  4949. hp = HEAP_TOP(p);
  4950. HEAP_TOP(p) += sz;
  4951. args = NIL;
  4952. for (i = arity-1; i >= 0; i--) {
  4953. args = CONS(hp, reg[i], args);
  4954. hp += 2;
  4955. }
  4956. /*
  4957. * Set up registers for call to error_handler:breakpoint/3.
  4958. */
  4959. reg[0] = fi[0];
  4960. reg[1] = fi[1];
  4961. reg[2] = args;
  4962. return 1;
  4963. }
  4964. static Export*
  4965. apply_setup_error_handler(Process* p, Eterm module, Eterm function, Uint arity, Eterm* reg)
  4966. {
  4967. Export* ep;
  4968. /*
  4969. * Find the export table index for the error handler. Return NULL if
  4970. * there is no error handler module.
  4971. */
  4972. if ((ep = erts_find_export_entry(erts_proc_get_error_handler(p),
  4973. am_undefined_function, 3)) == NULL) {
  4974. return NULL;
  4975. } else {
  4976. int i;
  4977. Uint sz = 2*arity;
  4978. Eterm* hp;
  4979. Eterm args = NIL;
  4980. /*
  4981. * Always copy args from registers to a new list; this ensures
  4982. * that we have the same behaviour whether or not this was
  4983. * called from apply or fixed_apply (any additional last
  4984. * THIS-argument will be included, assuming that arity has been
  4985. * properly adjusted).
  4986. */
  4987. if (HeapWordsLeft(p) < sz) {
  4988. erts_garbage_collect(p, sz, reg, arity);
  4989. }
  4990. hp = HEAP_TOP(p);
  4991. HEAP_TOP(p) += sz;
  4992. for (i = arity-1; i >= 0; i--) {
  4993. args = CONS(hp, reg[i], args);
  4994. hp += 2;
  4995. }
  4996. reg[0] = module;
  4997. reg[1] = function;
  4998. reg[2] = args;
  4999. }
  5000. return ep;
  5001. }
  5002. static Uint*
  5003. apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg)
  5004. {
  5005. int arity;
  5006. Export* ep;
  5007. Eterm tmp, this;
  5008. /*
  5009. * Check the arguments which should be of the form apply(Module,
  5010. * Function, Arguments) where Function is an atom and
  5011. * Arguments is an arity long list of terms.
  5012. */
  5013. if (is_not_atom(function)) {
  5014. /*
  5015. * No need to test args here -- done below.
  5016. */
  5017. error:
  5018. p->freason = BADARG;
  5019. error2:
  5020. reg[0] = module;
  5021. reg[1] = function;
  5022. reg[2] = args;
  5023. return 0;
  5024. }
  5025. /* The module argument may be either an atom or an abstract module
  5026. * (currently implemented using tuples, but this might change).
  5027. */
  5028. this = THE_NON_VALUE;
  5029. if (is_not_atom(module)) {
  5030. Eterm* tp;
  5031. if (is_not_tuple(module)) goto error;
  5032. tp = tuple_val(module);
  5033. if (arityval(tp[0]) < 1) goto error;
  5034. this = module;
  5035. module = tp[1];
  5036. if (is_not_atom(module)) goto error;
  5037. }
  5038. /*
  5039. * Walk down the 3rd parameter of apply (the argument list) and copy
  5040. * the parameters to the x registers (reg[]). If the module argument
  5041. * was an abstract module, add 1 to the function arity and put the
  5042. * module argument in the n+1st x register as a THIS reference.
  5043. */
  5044. tmp = args;
  5045. arity = 0;
  5046. while (is_list(tmp)) {
  5047. if (arity < (MAX_REG - 1)) {
  5048. reg[arity++] = CAR(list_val(tmp));
  5049. tmp = CDR(list_val(tmp));
  5050. } else {
  5051. p->freason = SYSTEM_LIMIT;
  5052. goto error2;
  5053. }
  5054. }
  5055. if (is_not_nil(tmp)) { /* Must be well-formed list */
  5056. goto error;
  5057. }
  5058. if (this != THE_NON_VALUE) {
  5059. reg[arity++] = this;
  5060. }
  5061. /*
  5062. * Get the index into the export table, or failing that the export
  5063. * entry for the error handler.
  5064. *
  5065. * Note: All BIFs have export entries; thus, no special case is needed.
  5066. */
  5067. if ((ep = erts_find_export_entry(module, function, arity)) == NULL) {
  5068. if ((ep = apply_setup_error_handler(p, module, function, arity, reg)) == NULL) goto error;
  5069. } else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) {
  5070. save_calls(p, ep);
  5071. }
  5072. return ep->address;
  5073. }
  5074. static Uint*
  5075. fixed_apply(Process* p, Eterm* reg, Uint arity)
  5076. {
  5077. Export* ep;
  5078. Eterm module;
  5079. Eterm function;
  5080. module = reg[arity]; /* The THIS pointer already in place */
  5081. function = reg[arity+1];
  5082. if (is_not_atom(function)) {
  5083. error:
  5084. p->freason = BADARG;
  5085. reg[0] = module;
  5086. reg[1] = function;
  5087. reg[2] = NIL;
  5088. return 0;
  5089. }
  5090. /* The module argument may be either an atom or an abstract module
  5091. * (currently implemented using tuples, but this might change).
  5092. */
  5093. if (is_not_atom(module)) {
  5094. Eterm* tp;
  5095. if (is_not_tuple(module)) goto error;
  5096. tp = tuple_val(module);
  5097. if (arityval(tp[0]) < 1) goto error;
  5098. module = tp[1];
  5099. if (is_not_atom(module)) goto error;
  5100. ++arity;
  5101. }
  5102. /*
  5103. * Get the index into the export table, or failing that the export
  5104. * entry for the error handler module.
  5105. *
  5106. * Note: All BIFs have export entries; thus, no special case is needed.
  5107. */
  5108. if ((ep = erts_find_export_entry(module, function, arity)) == NULL) {
  5109. if ((ep = apply_setup_error_handler(p, module, function, arity, reg)) == NULL)
  5110. goto error;
  5111. } else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) {
  5112. save_calls(p, ep);
  5113. }
  5114. return ep->address;
  5115. }
  5116. static int
  5117. hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* reg)
  5118. {
  5119. int arity;
  5120. Eterm tmp;
  5121. if (is_not_atom(module) || is_not_atom(function)) {
  5122. /*
  5123. * No need to test args here -- done below.
  5124. */
  5125. error:
  5126. c_p->freason = BADARG;
  5127. error2:
  5128. reg[0] = module;
  5129. reg[1] = function;
  5130. reg[2] = args;
  5131. return 0;
  5132. }
  5133. arity = 0;
  5134. tmp = args;
  5135. while (is_list(tmp)) {
  5136. if (arity < MAX_REG) {
  5137. tmp = CDR(list_val(tmp));
  5138. arity++;
  5139. } else {
  5140. c_p->freason = SYSTEM_LIMIT;
  5141. goto error2;
  5142. }
  5143. }
  5144. if (is_not_nil(tmp)) { /* Must be well-formed list */
  5145. goto error;
  5146. }
  5147. /*
  5148. * At this point, arguments are known to be good.
  5149. */
  5150. if (c_p->arg_reg != c_p->def_arg_reg) {
  5151. /* Save some memory */
  5152. erts_free(ERTS_ALC_T_ARG_REG, c_p->arg_reg);
  5153. c_p->arg_reg = c_p->def_arg_reg;
  5154. c_p->max_arg_reg = sizeof(c_p->def_arg_reg)/sizeof(c_p->def_arg_reg[0]);
  5155. }
  5156. /*
  5157. * Arrange for the process to be resumed at the given MFA with
  5158. * the stack cleared.
  5159. */
  5160. c_p->arity = 3;
  5161. c_p->arg_reg[0] = module;
  5162. c_p->arg_reg[1] = function;
  5163. c_p->arg_reg[2] = args;
  5164. c_p->stop = STACK_START(c_p);
  5165. c_p->catches = 0;
  5166. c_p->i = beam_apply;
  5167. c_p->cp = (Eterm *) beam_apply+1;
  5168. /*
  5169. * If there are no waiting messages, garbage collect and
  5170. * shrink the heap.
  5171. */
  5172. erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS);
  5173. ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
  5174. if (c_p->msg.len > 0) {
  5175. erts_add_to_runq(c_p);
  5176. } else {
  5177. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS);
  5178. c_p->fvalue = NIL;
  5179. PROCESS_MAIN_CHK_LOCKS(c_p);
  5180. erts_garbage_collect_hibernate(c_p);
  5181. PROCESS_MAIN_CHK_LOCKS(c_p);
  5182. erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS);
  5183. ASSERT(!ERTS_PROC_IS_EXITING(c_p));
  5184. c_p->status = P_WAITING;
  5185. #ifdef ERTS_SMP
  5186. ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
  5187. if (c_p->msg.len > 0)
  5188. erts_add_to_runq(c_p);
  5189. #endif
  5190. }
  5191. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS);
  5192. c_p->current = bif_export[BIF_hibernate_3]->code;
  5193. return 1;
  5194. }
  5195. static Uint*
  5196. call_fun(Process* p, /* Current process. */
  5197. int arity, /* Number of arguments for Fun. */
  5198. Eterm* reg, /* Contents of registers. */
  5199. Eterm args) /* THE_NON_VALUE or pre-built list of arguments. */
  5200. {
  5201. Eterm fun = reg[arity];
  5202. Eterm hdr;
  5203. int i;
  5204. Eterm function;
  5205. Eterm* hp;
  5206. if (!is_boxed(fun)) {
  5207. goto badfun;
  5208. }
  5209. hdr = *boxed_val(fun);
  5210. if (is_fun_header(hdr)) {
  5211. ErlFunThing* funp = (ErlFunThing *) fun_val(fun);
  5212. ErlFunEntry* fe;
  5213. Eterm* code_ptr;
  5214. Eterm* var_ptr;
  5215. int actual_arity;
  5216. unsigned num_free;
  5217. fe = funp->fe;
  5218. num_free = funp->num_free;
  5219. code_ptr = fe->address;
  5220. actual_arity = (int) code_ptr[-1];
  5221. if (actual_arity == arity+num_free) {
  5222. if (num_free == 0) {
  5223. return code_ptr;
  5224. } else {
  5225. var_ptr = funp->env;
  5226. reg += arity;
  5227. i = 0;
  5228. do {
  5229. reg[i] = var_ptr[i];
  5230. i++;
  5231. } while (i < num_free);
  5232. reg[i] = fun;
  5233. return code_ptr;
  5234. }
  5235. return code_ptr;
  5236. } else {
  5237. /*
  5238. * Something wrong here. First build a list of the arguments.
  5239. */
  5240. if (is_non_value(args)) {
  5241. Uint sz = 2 * arity;
  5242. args = NIL;
  5243. if (HeapWordsLeft(p) < sz) {
  5244. erts_garbage_collect(p, sz, reg, arity+1);
  5245. fun = reg[arity];
  5246. }
  5247. hp = HEAP_TOP(p);
  5248. HEAP_TOP(p) += sz;
  5249. for (i = arity-1; i >= 0; i--) {
  5250. args = CONS(hp, reg[i], args);
  5251. hp += 2;
  5252. }
  5253. }
  5254. if (actual_arity >= 0) {
  5255. /*
  5256. * There is a fun defined, but the call has the wrong arity.
  5257. */
  5258. hp = HAlloc(p, 3);
  5259. p->freason = EXC_BADARITY;
  5260. p->fvalue = TUPLE2(hp, fun, args);
  5261. return NULL;
  5262. } else {
  5263. Export* ep;
  5264. Module* modp;
  5265. Eterm module;
  5266. /*
  5267. * No arity. There is no module loaded that defines the fun,
  5268. * either because the fun is newly created from the external
  5269. * representation (the module has never been loaded),
  5270. * or the module defining the fun has been unloaded.
  5271. */
  5272. module = fe->module;
  5273. if ((modp = erts_get_module(module)) != NULL && modp->code != NULL) {
  5274. /*
  5275. * There is a module loaded, but obviously the fun is not
  5276. * defined in it. We must not call the error_handler
  5277. * (or we will get into an infinite loop).
  5278. */
  5279. goto badfun;
  5280. }
  5281. /*
  5282. * No current code for this module. Call the error_handler module
  5283. * to attempt loading the module.
  5284. */
  5285. ep = erts_find_function(erts_proc_get_error_handler(p),
  5286. am_undefined_lambda, 3);
  5287. if (ep == NULL) { /* No error handler */
  5288. p->current = NULL;
  5289. p->freason = EXC_UNDEF;
  5290. return NULL;
  5291. }
  5292. reg[0] = module;
  5293. reg[1] = fun;
  5294. reg[2] = args;
  5295. return ep->address;
  5296. }
  5297. }
  5298. } else if (is_export_header(hdr)) {
  5299. Export* ep = (Export *) (export_val(fun))[1];
  5300. int actual_arity = (int) ep->code[2];
  5301. if (arity == actual_arity) {
  5302. return ep->address;
  5303. } else {
  5304. /*
  5305. * Wrong arity. First build a list of the arguments.
  5306. */
  5307. if (is_non_value(args)) {
  5308. args = NIL;
  5309. hp = HAlloc(p, arity*2);
  5310. for (i = arity-1; i >= 0; i--) {
  5311. args = CONS(hp, reg[i], args);
  5312. hp += 2;
  5313. }
  5314. }
  5315. hp = HAlloc(p, 3);
  5316. p->freason = EXC_BADARITY;
  5317. p->fvalue = TUPLE2(hp, fun, args);
  5318. return NULL;
  5319. }
  5320. } else if (hdr == make_arityval(2)) {
  5321. Eterm* tp;
  5322. Export* ep;
  5323. Eterm module;
  5324. tp = tuple_val(fun);
  5325. module = tp[1];
  5326. function = tp[2];
  5327. if (!is_atom(module) || !is_atom(function)) {
  5328. goto badfun;
  5329. }
  5330. if ((ep = erts_find_export_entry(module, function, arity)) == NULL) {
  5331. ep = erts_find_export_entry(erts_proc_get_error_handler(p),
  5332. am_undefined_function, 3);
  5333. if (ep == NULL) {
  5334. p->freason = EXC_UNDEF;
  5335. return 0;
  5336. }
  5337. if (is_non_value(args)) {
  5338. Uint sz = 2 * arity;
  5339. if (HeapWordsLeft(p) < sz) {
  5340. erts_garbage_collect(p, sz, reg, arity);
  5341. }
  5342. hp = HEAP_TOP(p);
  5343. HEAP_TOP(p) += sz;
  5344. args = NIL;
  5345. while (arity-- > 0) {
  5346. args = CONS(hp, reg[arity], args);
  5347. hp += 2;
  5348. }
  5349. }
  5350. reg[0] = module;
  5351. reg[1] = function;
  5352. reg[2] = args;
  5353. }
  5354. return ep->address;
  5355. } else {
  5356. badfun:
  5357. p->current = NULL;
  5358. p->freason = EXC_BADFUN;
  5359. p->fvalue = fun;
  5360. return NULL;
  5361. }
  5362. }
  5363. static Eterm*
  5364. apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg)
  5365. {
  5366. int arity;
  5367. Eterm tmp;
  5368. /*
  5369. * Walk down the 3rd parameter of apply (the argument list) and copy
  5370. * the parameters to the x registers (reg[]).
  5371. */
  5372. tmp = args;
  5373. arity = 0;
  5374. while (is_list(tmp)) {
  5375. if (arity < MAX_REG-1) {
  5376. reg[arity++] = CAR(list_val(tmp));
  5377. tmp = CDR(list_val(tmp));
  5378. } else {
  5379. p->freason = SYSTEM_LIMIT;
  5380. return NULL;
  5381. }
  5382. }
  5383. if (is_not_nil(tmp)) { /* Must be well-formed list */
  5384. p->freason = EXC_UNDEF;
  5385. return NULL;
  5386. }
  5387. reg[arity] = fun;
  5388. return call_fun(p, arity, reg, args);
  5389. }
  5390. static Eterm
  5391. new_fun(Process* p, Eterm* reg, ErlFunEntry* fe, int num_free)
  5392. {
  5393. unsigned needed = ERL_FUN_SIZE + num_free;
  5394. ErlFunThing* funp;
  5395. Eterm* hp;
  5396. int i;
  5397. if (HEAP_LIMIT(p) - HEAP_TOP(p) <= needed) {
  5398. PROCESS_MAIN_CHK_LOCKS(p);
  5399. erts_garbage_collect(p, needed, reg, num_free);
  5400. PROCESS_MAIN_CHK_LOCKS(p);
  5401. }
  5402. hp = p->htop;
  5403. p->htop = hp + needed;
  5404. funp = (ErlFunThing *) hp;
  5405. hp = funp->env;
  5406. erts_refc_inc(&fe->refc, 2);
  5407. funp->thing_word = HEADER_FUN;
  5408. #ifndef HYBRID /* FIND ME! */
  5409. funp->next = MSO(p).funs;
  5410. MSO(p).funs = funp;
  5411. #endif
  5412. funp->fe = fe;
  5413. funp->num_free = num_free;
  5414. funp->creator = p->id;
  5415. #ifdef HIPE
  5416. funp->native_address = fe->native_address;
  5417. #endif
  5418. funp->arity = (int)fe->address[-1] - num_free;
  5419. for (i = 0; i < num_free; i++) {
  5420. *hp++ = reg[i];
  5421. }
  5422. return make_fun(funp);
  5423. }
  5424. int catchlevel(Process *p)
  5425. {
  5426. return p->catches;
  5427. }
  5428. /*
  5429. * Check if the given function is built-in (i.e. a BIF implemented in C).
  5430. *
  5431. * Returns 0 if not built-in, and a non-zero value if built-in.
  5432. */
  5433. int
  5434. erts_is_builtin(Eterm Mod, Eterm Name, int arity)
  5435. {
  5436. Export e;
  5437. Export* ep;
  5438. e.code[0] = Mod;
  5439. e.code[1] = Name;
  5440. e.code[2] = arity;
  5441. if ((ep = export_get(&e)) == NULL) {
  5442. return 0;
  5443. }
  5444. return ep->address == ep->code+3 && (ep->code[3] == (Uint) em_apply_bif);
  5445. }
  5446. /*
  5447. * Return the current number of reductions for the given process.
  5448. * To get the total number of reductions, p->reds must be added.
  5449. */
  5450. Uint
  5451. erts_current_reductions(Process *current, Process *p)
  5452. {
  5453. if (current != p) {
  5454. return 0;
  5455. } else if (current->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(current)) {
  5456. return -current->fcalls;
  5457. } else {
  5458. return REDS_IN(current) - current->fcalls;
  5459. }
  5460. }