/erts/emulator/beam/beam_bif_load.c

https://github.com/dudefrommangalore/otp · C · 782 lines · 603 code · 94 blank · 85 comment · 154 complexity · accd7c02432c58ccce7a64d7315ef8db MD5 · raw file

  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 1999-2010. 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 "sys.h"
  23. #include "erl_vm.h"
  24. #include "global.h"
  25. #include "erl_process.h"
  26. #include "error.h"
  27. #include "bif.h"
  28. #include "beam_load.h"
  29. #include "big.h"
  30. #include "beam_bp.h"
  31. #include "beam_catches.h"
  32. #include "erl_binary.h"
  33. #include "erl_nif.h"
  34. static void set_default_trace_pattern(Eterm module);
  35. static Eterm check_process_code(Process* rp, Module* modp);
  36. static void delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp);
  37. static void delete_export_references(Eterm module);
  38. static int purge_module(int module);
  39. static int is_native(Eterm* code);
  40. static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size);
  41. static int any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size);
  42. static void remove_from_address_table(Eterm* code);
  43. Eterm
  44. load_module_2(BIF_ALIST_2)
  45. {
  46. Eterm reason;
  47. Eterm* hp;
  48. int i;
  49. int sz;
  50. byte* code;
  51. Eterm res;
  52. byte* temp_alloc = NULL;
  53. if (is_not_atom(BIF_ARG_1)) {
  54. error:
  55. erts_free_aligned_binary_bytes(temp_alloc);
  56. BIF_ERROR(BIF_P, BADARG);
  57. }
  58. if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) {
  59. goto error;
  60. }
  61. erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
  62. erts_smp_block_system(0);
  63. erts_export_consolidate();
  64. hp = HAlloc(BIF_P, 3);
  65. sz = binary_size(BIF_ARG_2);
  66. if ((i = erts_load_module(BIF_P, 0,
  67. BIF_P->group_leader, &BIF_ARG_1, code, sz)) < 0) {
  68. switch (i) {
  69. case -1: reason = am_badfile; break;
  70. case -2: reason = am_nofile; break;
  71. case -3: reason = am_not_purged; break;
  72. case -4:
  73. reason = am_atom_put("native_code", sizeof("native_code")-1);
  74. break;
  75. case -5:
  76. {
  77. /*
  78. * The module contains an on_load function. The loader
  79. * has loaded the module as usual, except that the
  80. * export entries does not point into the module, so it
  81. * is not possible to call any code in the module.
  82. */
  83. ERTS_DECL_AM(on_load);
  84. reason = AM_on_load;
  85. break;
  86. }
  87. default: reason = am_badfile; break;
  88. }
  89. res = TUPLE2(hp, am_error, reason);
  90. goto done;
  91. }
  92. set_default_trace_pattern(BIF_ARG_1);
  93. res = TUPLE2(hp, am_module, BIF_ARG_1);
  94. done:
  95. erts_free_aligned_binary_bytes(temp_alloc);
  96. erts_smp_release_system();
  97. erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
  98. BIF_RET(res);
  99. }
  100. BIF_RETTYPE purge_module_1(BIF_ALIST_1)
  101. {
  102. int purge_res;
  103. if (is_not_atom(BIF_ARG_1)) {
  104. BIF_ERROR(BIF_P, BADARG);
  105. }
  106. erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
  107. erts_smp_block_system(0);
  108. erts_export_consolidate();
  109. purge_res = purge_module(atom_val(BIF_ARG_1));
  110. erts_smp_release_system();
  111. erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
  112. if (purge_res < 0) {
  113. BIF_ERROR(BIF_P, BADARG);
  114. }
  115. BIF_RET(am_true);
  116. }
  117. BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1)
  118. {
  119. Module* modp;
  120. if (is_not_atom(BIF_ARG_1)) {
  121. BIF_ERROR(BIF_P, BADARG);
  122. }
  123. if ((modp = erts_get_module(BIF_ARG_1)) == NULL) {
  124. return am_undefined;
  125. }
  126. return (is_native(modp->code) ||
  127. (modp->old_code != 0 && is_native(modp->old_code))) ?
  128. am_true : am_false;
  129. }
  130. BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3)
  131. {
  132. Eterm res;
  133. erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
  134. erts_smp_block_system(0);
  135. erts_export_consolidate();
  136. res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
  137. erts_smp_release_system();
  138. erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
  139. return res;
  140. }
  141. Eterm
  142. check_process_code_2(BIF_ALIST_2)
  143. {
  144. Process* rp;
  145. Module* modp;
  146. if (is_not_atom(BIF_ARG_2)) {
  147. goto error;
  148. }
  149. if (is_internal_pid(BIF_ARG_1)) {
  150. Eterm res;
  151. if (internal_pid_index(BIF_ARG_1) >= erts_max_processes)
  152. goto error;
  153. rp = erts_pid2proc_not_running(BIF_P, ERTS_PROC_LOCK_MAIN,
  154. BIF_ARG_1, ERTS_PROC_LOCK_MAIN);
  155. if (!rp) {
  156. BIF_RET(am_false);
  157. }
  158. if (rp == ERTS_PROC_LOCK_BUSY) {
  159. ERTS_BIF_YIELD2(bif_export[BIF_check_process_code_2], BIF_P,
  160. BIF_ARG_1, BIF_ARG_2);
  161. }
  162. modp = erts_get_module(BIF_ARG_2);
  163. res = check_process_code(rp, modp);
  164. #ifdef ERTS_SMP
  165. if (BIF_P != rp)
  166. erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);
  167. #endif
  168. BIF_RET(res);
  169. }
  170. else if (is_external_pid(BIF_ARG_1)
  171. && external_pid_dist_entry(BIF_ARG_1) == erts_this_dist_entry) {
  172. BIF_RET(am_false);
  173. }
  174. error:
  175. BIF_ERROR(BIF_P, BADARG);
  176. }
  177. BIF_RETTYPE delete_module_1(BIF_ALIST_1)
  178. {
  179. int res;
  180. if (is_not_atom(BIF_ARG_1))
  181. goto badarg;
  182. erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
  183. erts_smp_block_system(0);
  184. {
  185. Module *modp = erts_get_module(BIF_ARG_1);
  186. if (!modp) {
  187. res = am_undefined;
  188. }
  189. else if (modp->old_code != 0) {
  190. erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
  191. erts_dsprintf(dsbufp, "Module %T must be purged before loading\n",
  192. BIF_ARG_1);
  193. erts_send_error_to_logger(BIF_P->group_leader, dsbufp);
  194. res = am_badarg;
  195. }
  196. else {
  197. delete_export_references(BIF_ARG_1);
  198. delete_code(BIF_P, 0, modp);
  199. res = am_true;
  200. }
  201. }
  202. erts_smp_release_system();
  203. erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
  204. if (res == am_badarg) {
  205. badarg:
  206. BIF_ERROR(BIF_P, BADARG);
  207. }
  208. BIF_RET(res);
  209. }
  210. BIF_RETTYPE module_loaded_1(BIF_ALIST_1)
  211. {
  212. Module* modp;
  213. if (is_not_atom(BIF_ARG_1)) {
  214. BIF_ERROR(BIF_P, BADARG);
  215. }
  216. if ((modp = erts_get_module(BIF_ARG_1)) == NULL ||
  217. modp->code == NULL ||
  218. modp->code[MI_ON_LOAD_FUNCTION_PTR] != 0) {
  219. BIF_RET(am_false);
  220. }
  221. BIF_RET(am_true);
  222. }
  223. BIF_RETTYPE pre_loaded_0(BIF_ALIST_0)
  224. {
  225. return erts_preloaded(BIF_P);
  226. }
  227. BIF_RETTYPE loaded_0(BIF_ALIST_0)
  228. {
  229. Eterm previous = NIL;
  230. Eterm* hp;
  231. int i;
  232. int j = 0;
  233. for (i = 0; i < module_code_size(); i++) {
  234. if (module_code(i) != NULL &&
  235. ((module_code(i)->code_length != 0) ||
  236. (module_code(i)->old_code_length != 0))) {
  237. j++;
  238. }
  239. }
  240. if (j > 0) {
  241. hp = HAlloc(BIF_P, j*2);
  242. for (i = 0; i < module_code_size(); i++) {
  243. if (module_code(i) != NULL &&
  244. ((module_code(i)->code_length != 0) ||
  245. (module_code(i)->old_code_length != 0))) {
  246. previous = CONS(hp, make_atom(module_code(i)->module),
  247. previous);
  248. hp += 2;
  249. }
  250. }
  251. }
  252. BIF_RET(previous);
  253. }
  254. BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1)
  255. {
  256. Module* modp = erts_get_module(BIF_ARG_1);
  257. Eterm on_load;
  258. if (!modp || modp->code == 0) {
  259. error:
  260. BIF_ERROR(BIF_P, BADARG);
  261. }
  262. if ((on_load = modp->code[MI_ON_LOAD_FUNCTION_PTR]) == 0) {
  263. goto error;
  264. }
  265. BIF_TRAP_CODE_PTR_0(BIF_P, on_load);
  266. }
  267. BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
  268. {
  269. Module* modp = erts_get_module(BIF_ARG_1);
  270. Eterm on_load;
  271. if (!modp || modp->code == 0) {
  272. error:
  273. BIF_ERROR(BIF_P, BADARG);
  274. }
  275. if ((on_load = modp->code[MI_ON_LOAD_FUNCTION_PTR]) == 0) {
  276. goto error;
  277. }
  278. if (BIF_ARG_2 != am_false && BIF_ARG_2 != am_true) {
  279. goto error;
  280. }
  281. erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
  282. erts_smp_block_system(0);
  283. if (BIF_ARG_2 == am_true) {
  284. int i;
  285. /*
  286. * The on_load function succeded. Fix up export entries.
  287. */
  288. for (i = 0; i < export_list_size(); i++) {
  289. Export *ep = export_list(i);
  290. if (ep != NULL &&
  291. ep->code[0] == BIF_ARG_1 &&
  292. ep->code[4] != 0) {
  293. ep->address = (void *) ep->code[4];
  294. ep->code[3] = 0;
  295. ep->code[4] = 0;
  296. }
  297. }
  298. modp->code[MI_ON_LOAD_FUNCTION_PTR] = 0;
  299. set_default_trace_pattern(BIF_ARG_1);
  300. } else if (BIF_ARG_2 == am_false) {
  301. Eterm* code;
  302. Eterm* end;
  303. /*
  304. * The on_load function failed. Remove the loaded code.
  305. * This is an combination of delete and purge. We purge
  306. * the current code; the old code is not touched.
  307. */
  308. erts_total_code_size -= modp->code_length;
  309. code = modp->code;
  310. end = (Eterm *)((char *)code + modp->code_length);
  311. erts_cleanup_funs_on_purge(code, end);
  312. beam_catches_delmod(modp->catches, code, modp->code_length);
  313. erts_free(ERTS_ALC_T_CODE, (void *) code);
  314. modp->code = NULL;
  315. modp->code_length = 0;
  316. modp->catches = BEAM_CATCHES_NIL;
  317. remove_from_address_table(code);
  318. }
  319. erts_smp_release_system();
  320. erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
  321. BIF_RET(am_true);
  322. }
  323. static void
  324. set_default_trace_pattern(Eterm module)
  325. {
  326. int trace_pattern_is_on;
  327. Binary *match_spec;
  328. Binary *meta_match_spec;
  329. struct trace_pattern_flags trace_pattern_flags;
  330. Eterm meta_tracer_pid;
  331. erts_get_default_trace_pattern(&trace_pattern_is_on,
  332. &match_spec,
  333. &meta_match_spec,
  334. &trace_pattern_flags,
  335. &meta_tracer_pid);
  336. if (trace_pattern_is_on) {
  337. Eterm mfa[1];
  338. mfa[0] = module;
  339. (void) erts_set_trace_pattern(mfa, 1,
  340. match_spec,
  341. meta_match_spec,
  342. 1, trace_pattern_flags,
  343. meta_tracer_pid);
  344. }
  345. }
  346. static Eterm
  347. check_process_code(Process* rp, Module* modp)
  348. {
  349. Eterm* start;
  350. char* mod_start;
  351. Uint mod_size;
  352. Eterm* end;
  353. Eterm* sp;
  354. #ifndef HYBRID /* FIND ME! */
  355. ErlFunThing* funp;
  356. int done_gc = 0;
  357. #endif
  358. #define INSIDE(a) (start <= (a) && (a) < end)
  359. if (modp == NULL) { /* Doesn't exist. */
  360. return am_false;
  361. } else if (modp->old_code == NULL) { /* No old code. */
  362. return am_false;
  363. }
  364. /*
  365. * Pick up limits for the module.
  366. */
  367. start = modp->old_code;
  368. end = (Eterm *)((char *)start + modp->old_code_length);
  369. mod_start = (char *) start;
  370. mod_size = modp->old_code_length;
  371. /*
  372. * Check if current instruction or continuation pointer points into module.
  373. */
  374. if (INSIDE(rp->i) || INSIDE(rp->cp)) {
  375. return am_true;
  376. }
  377. /*
  378. * Check all continuation pointers stored on the stack.
  379. */
  380. for (sp = rp->stop; sp < STACK_START(rp); sp++) {
  381. if (is_CP(*sp) && INSIDE(cp_val(*sp))) {
  382. return am_true;
  383. }
  384. }
  385. /*
  386. * Check all continuation pointers stored in stackdump
  387. * and clear exception stackdump if there is a pointer
  388. * to the module.
  389. */
  390. if (rp->ftrace != NIL) {
  391. struct StackTrace *s;
  392. ASSERT(is_list(rp->ftrace));
  393. s = (struct StackTrace *) big_val(CDR(list_val(rp->ftrace)));
  394. if ((s->pc && INSIDE(s->pc)) ||
  395. (s->current && INSIDE(s->current))) {
  396. rp->freason = EXC_NULL;
  397. rp->fvalue = NIL;
  398. rp->ftrace = NIL;
  399. } else {
  400. int i;
  401. for (i = 0; i < s->depth; i++) {
  402. if (INSIDE(s->trace[i])) {
  403. rp->freason = EXC_NULL;
  404. rp->fvalue = NIL;
  405. rp->ftrace = NIL;
  406. break;
  407. }
  408. }
  409. }
  410. }
  411. /*
  412. * See if there are funs that refer to the old version of the module.
  413. */
  414. #ifndef HYBRID /* FIND ME! */
  415. rescan:
  416. for (funp = MSO(rp).funs; funp; funp = funp->next) {
  417. Eterm* fun_code;
  418. fun_code = funp->fe->address;
  419. if (INSIDE((Eterm *) funp->fe->address)) {
  420. if (done_gc) {
  421. return am_true;
  422. } else {
  423. /*
  424. * Try to get rid of this fun by garbage collecting.
  425. * Clear both fvalue and ftrace to make sure they
  426. * don't hold any funs.
  427. */
  428. rp->freason = EXC_NULL;
  429. rp->fvalue = NIL;
  430. rp->ftrace = NIL;
  431. done_gc = 1;
  432. FLAGS(rp) |= F_NEED_FULLSWEEP;
  433. (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
  434. goto rescan;
  435. }
  436. }
  437. }
  438. #endif
  439. /*
  440. * See if there are constants inside the module referenced by the process.
  441. */
  442. done_gc = 0;
  443. for (;;) {
  444. ErlMessage* mp;
  445. if (any_heap_ref_ptrs(&rp->fvalue, &rp->fvalue+1, mod_start, mod_size)) {
  446. rp->freason = EXC_NULL;
  447. rp->fvalue = NIL;
  448. rp->ftrace = NIL;
  449. }
  450. if (any_heap_ref_ptrs(rp->stop, rp->hend, mod_start, mod_size)) {
  451. goto need_gc;
  452. }
  453. if (any_heap_refs(rp->heap, rp->htop, mod_start, mod_size)) {
  454. goto need_gc;
  455. }
  456. if (any_heap_refs(rp->old_heap, rp->old_htop, mod_start, mod_size)) {
  457. goto need_gc;
  458. }
  459. if (rp->dictionary != NULL) {
  460. Eterm* start = rp->dictionary->data;
  461. Eterm* end = start + rp->dictionary->used;
  462. if (any_heap_ref_ptrs(start, end, mod_start, mod_size)) {
  463. goto need_gc;
  464. }
  465. }
  466. for (mp = rp->msg.first; mp != NULL; mp = mp->next) {
  467. if (any_heap_ref_ptrs(mp->m, mp->m+2, mod_start, mod_size)) {
  468. goto need_gc;
  469. }
  470. }
  471. break;
  472. need_gc:
  473. if (done_gc) {
  474. return am_true;
  475. } else {
  476. Eterm* literals;
  477. Uint lit_size;
  478. /*
  479. * Try to get rid of constants by by garbage collecting.
  480. * Clear both fvalue and ftrace.
  481. */
  482. rp->freason = EXC_NULL;
  483. rp->fvalue = NIL;
  484. rp->ftrace = NIL;
  485. done_gc = 1;
  486. FLAGS(rp) |= F_NEED_FULLSWEEP;
  487. (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
  488. literals = (Eterm *) modp->old_code[MI_LITERALS_START];
  489. lit_size = (Eterm *) modp->old_code[MI_LITERALS_END] - literals;
  490. erts_garbage_collect_literals(rp, literals, lit_size);
  491. }
  492. }
  493. return am_false;
  494. #undef INSIDE
  495. }
  496. #define in_area(ptr,start,nbytes) \
  497. ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes))
  498. static int
  499. any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size)
  500. {
  501. Eterm* p;
  502. Eterm val;
  503. for (p = start; p < end; p++) {
  504. val = *p;
  505. switch (primary_tag(val)) {
  506. case TAG_PRIMARY_BOXED:
  507. case TAG_PRIMARY_LIST:
  508. if (in_area(val, mod_start, mod_size)) {
  509. return 1;
  510. }
  511. break;
  512. }
  513. }
  514. return 0;
  515. }
  516. static int
  517. any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size)
  518. {
  519. Eterm* p;
  520. Eterm val;
  521. for (p = start; p < end; p++) {
  522. val = *p;
  523. switch (primary_tag(val)) {
  524. case TAG_PRIMARY_BOXED:
  525. case TAG_PRIMARY_LIST:
  526. if (in_area(val, mod_start, mod_size)) {
  527. return 1;
  528. }
  529. break;
  530. case TAG_PRIMARY_HEADER:
  531. if (!header_is_transparent(val)) {
  532. Eterm* new_p = p + thing_arityval(val);
  533. ASSERT(start <= new_p && new_p < end);
  534. p = new_p;
  535. }
  536. }
  537. }
  538. return 0;
  539. }
  540. #undef in_area
  541. static int
  542. purge_module(int module)
  543. {
  544. Eterm* code;
  545. Eterm* end;
  546. Module* modp;
  547. /*
  548. * Correct module?
  549. */
  550. if ((modp = erts_get_module(make_atom(module))) == NULL) {
  551. return -2;
  552. }
  553. /*
  554. * Any code to purge?
  555. */
  556. if (modp->old_code == 0) {
  557. if (display_loads) {
  558. erts_printf("No code to purge for %T\n", make_atom(module));
  559. }
  560. return -1;
  561. }
  562. /*
  563. * Unload any NIF library
  564. */
  565. if (modp->old_nif != NULL) {
  566. erts_unload_nif(modp->old_nif);
  567. modp->old_nif = NULL;
  568. }
  569. /*
  570. * Remove the old code.
  571. */
  572. ASSERT(erts_total_code_size >= modp->old_code_length);
  573. erts_total_code_size -= modp->old_code_length;
  574. code = modp->old_code;
  575. end = (Eterm *)((char *)code + modp->old_code_length);
  576. erts_cleanup_funs_on_purge(code, end);
  577. beam_catches_delmod(modp->old_catches, code, modp->old_code_length);
  578. erts_free(ERTS_ALC_T_CODE, (void *) code);
  579. modp->old_code = NULL;
  580. modp->old_code_length = 0;
  581. modp->old_catches = BEAM_CATCHES_NIL;
  582. remove_from_address_table(code);
  583. return 0;
  584. }
  585. static void
  586. remove_from_address_table(Eterm* code)
  587. {
  588. int i;
  589. for (i = 0; i < num_loaded_modules; i++) {
  590. if (modules[i].start == code) {
  591. num_loaded_modules--;
  592. while (i < num_loaded_modules) {
  593. modules[i] = modules[i+1];
  594. i++;
  595. }
  596. mid_module = &modules[num_loaded_modules/2];
  597. return;
  598. }
  599. }
  600. ASSERT(0); /* Not found? */
  601. }
  602. /*
  603. * Move code from current to old.
  604. */
  605. static void
  606. delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp)
  607. {
  608. #ifdef ERTS_ENABLE_LOCK_CHECK
  609. #ifdef ERTS_SMP
  610. if (c_p && c_p_locks)
  611. erts_proc_lc_chk_only_proc_main(c_p);
  612. else
  613. #endif
  614. erts_lc_check_exact(NULL, 0);
  615. #endif
  616. /*
  617. * Clear breakpoints if any
  618. */
  619. if (modp->code != NULL && modp->code[MI_NUM_BREAKPOINTS] > 0) {
  620. if (c_p && c_p_locks)
  621. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
  622. erts_smp_block_system(0);
  623. erts_clear_module_break(modp);
  624. modp->code[MI_NUM_BREAKPOINTS] = 0;
  625. erts_smp_release_system();
  626. if (c_p && c_p_locks)
  627. erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
  628. }
  629. modp->old_code = modp->code;
  630. modp->old_code_length = modp->code_length;
  631. modp->old_catches = modp->catches;
  632. modp->old_nif = modp->nif;
  633. modp->code = NULL;
  634. modp->code_length = 0;
  635. modp->catches = BEAM_CATCHES_NIL;
  636. modp->nif = NULL;
  637. }
  638. /* null all references on the export table for the module called with the
  639. atom index below */
  640. static void
  641. delete_export_references(Eterm module)
  642. {
  643. int i;
  644. ASSERT(is_atom(module));
  645. for (i = 0; i < export_list_size(); i++) {
  646. Export *ep = export_list(i);
  647. if (ep != NULL && (ep->code[0] == module)) {
  648. if (ep->address == ep->code+3 &&
  649. (ep->code[3] == (Eterm) em_apply_bif)) {
  650. continue;
  651. }
  652. ep->address = ep->code+3;
  653. ep->code[3] = (Uint) em_call_error_handler;
  654. ep->code[4] = 0;
  655. MatchSetUnref(ep->match_prog_set);
  656. ep->match_prog_set = NULL;
  657. }
  658. }
  659. }
  660. int
  661. beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module)
  662. {
  663. Module* modp = erts_put_module(module);
  664. /*
  665. * Check if the previous code has been already deleted;
  666. * if not, delete old code; error if old code already exists.
  667. */
  668. if (modp->code != NULL && modp->old_code != NULL) {
  669. return -3;
  670. } else if (modp->old_code == NULL) { /* Make the current version old. */
  671. if (display_loads) {
  672. erts_printf("saving old code\n");
  673. }
  674. delete_code(c_p, c_p_locks, modp);
  675. delete_export_references(module);
  676. }
  677. return 0;
  678. }
  679. static int
  680. is_native(Eterm* code)
  681. {
  682. return ((Eterm *)code[MI_FUNCTIONS])[1] != 0;
  683. }