PageRenderTime 70ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/erts/emulator/beam/beam_bif_load.c

https://github.com/Bwooce/otp
C | 783 lines | 604 code | 94 blank | 85 comment | 156 complexity | e41a2562347fe2f9ce71a2a75a4131c3 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-2-Clause
  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(BeamInstr* 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(BeamInstr* 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[4] = 0;
  295. }
  296. }
  297. modp->code[MI_ON_LOAD_FUNCTION_PTR] = 0;
  298. set_default_trace_pattern(BIF_ARG_1);
  299. } else if (BIF_ARG_2 == am_false) {
  300. BeamInstr* code;
  301. BeamInstr* end;
  302. /*
  303. * The on_load function failed. Remove the loaded code.
  304. * This is an combination of delete and purge. We purge
  305. * the current code; the old code is not touched.
  306. */
  307. erts_total_code_size -= modp->code_length;
  308. code = modp->code;
  309. end = (BeamInstr *)((char *)code + modp->code_length);
  310. erts_cleanup_funs_on_purge(code, end);
  311. beam_catches_delmod(modp->catches, code, modp->code_length);
  312. erts_free(ERTS_ALC_T_CODE, (void *) code);
  313. modp->code = NULL;
  314. modp->code_length = 0;
  315. modp->catches = BEAM_CATCHES_NIL;
  316. remove_from_address_table(code);
  317. }
  318. erts_smp_release_system();
  319. erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
  320. BIF_RET(am_true);
  321. }
  322. static void
  323. set_default_trace_pattern(Eterm module)
  324. {
  325. int trace_pattern_is_on;
  326. Binary *match_spec;
  327. Binary *meta_match_spec;
  328. struct trace_pattern_flags trace_pattern_flags;
  329. Eterm meta_tracer_pid;
  330. erts_get_default_trace_pattern(&trace_pattern_is_on,
  331. &match_spec,
  332. &meta_match_spec,
  333. &trace_pattern_flags,
  334. &meta_tracer_pid);
  335. if (trace_pattern_is_on) {
  336. Eterm mfa[1];
  337. mfa[0] = module;
  338. (void) erts_set_trace_pattern(mfa, 1,
  339. match_spec,
  340. meta_match_spec,
  341. 1, trace_pattern_flags,
  342. meta_tracer_pid);
  343. }
  344. }
  345. static Eterm
  346. check_process_code(Process* rp, Module* modp)
  347. {
  348. BeamInstr* start;
  349. char* mod_start;
  350. Uint mod_size;
  351. BeamInstr* end;
  352. Eterm* sp;
  353. #ifndef HYBRID /* FIND ME! */
  354. struct erl_off_heap_header* oh;
  355. int done_gc = 0;
  356. #endif
  357. #define INSIDE(a) (start <= (a) && (a) < end)
  358. if (modp == NULL) { /* Doesn't exist. */
  359. return am_false;
  360. } else if (modp->old_code == NULL) { /* No old code. */
  361. return am_false;
  362. }
  363. /*
  364. * Pick up limits for the module.
  365. */
  366. start = modp->old_code;
  367. end = (BeamInstr *)((char *)start + modp->old_code_length);
  368. mod_start = (char *) start;
  369. mod_size = modp->old_code_length;
  370. /*
  371. * Check if current instruction or continuation pointer points into module.
  372. */
  373. if (INSIDE(rp->i) || INSIDE(rp->cp)) {
  374. return am_true;
  375. }
  376. /*
  377. * Check all continuation pointers stored on the stack.
  378. */
  379. for (sp = rp->stop; sp < STACK_START(rp); sp++) {
  380. if (is_CP(*sp) && INSIDE(cp_val(*sp))) {
  381. return am_true;
  382. }
  383. }
  384. /*
  385. * Check all continuation pointers stored in stackdump
  386. * and clear exception stackdump if there is a pointer
  387. * to the module.
  388. */
  389. if (rp->ftrace != NIL) {
  390. struct StackTrace *s;
  391. ASSERT(is_list(rp->ftrace));
  392. s = (struct StackTrace *) big_val(CDR(list_val(rp->ftrace)));
  393. if ((s->pc && INSIDE(s->pc)) ||
  394. (s->current && INSIDE(s->current))) {
  395. rp->freason = EXC_NULL;
  396. rp->fvalue = NIL;
  397. rp->ftrace = NIL;
  398. } else {
  399. int i;
  400. for (i = 0; i < s->depth; i++) {
  401. if (INSIDE(s->trace[i])) {
  402. rp->freason = EXC_NULL;
  403. rp->fvalue = NIL;
  404. rp->ftrace = NIL;
  405. break;
  406. }
  407. }
  408. }
  409. }
  410. /*
  411. * See if there are funs that refer to the old version of the module.
  412. */
  413. #ifndef HYBRID /* FIND ME! */
  414. rescan:
  415. for (oh = MSO(rp).first; oh; oh = oh->next) {
  416. if (thing_subtag(oh->thing_word) == FUN_SUBTAG) {
  417. ErlFunThing* funp = (ErlFunThing*) oh;
  418. BeamInstr* fun_code;
  419. fun_code = funp->fe->address;
  420. if (INSIDE((BeamInstr *) funp->fe->address)) {
  421. if (done_gc) {
  422. return am_true;
  423. } else {
  424. /*
  425. * Try to get rid of this fun by garbage collecting.
  426. * Clear both fvalue and ftrace to make sure they
  427. * don't hold any funs.
  428. */
  429. rp->freason = EXC_NULL;
  430. rp->fvalue = NIL;
  431. rp->ftrace = NIL;
  432. done_gc = 1;
  433. FLAGS(rp) |= F_NEED_FULLSWEEP;
  434. (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
  435. goto rescan;
  436. }
  437. }
  438. }
  439. }
  440. #endif
  441. /*
  442. * See if there are constants inside the module referenced by the process.
  443. */
  444. done_gc = 0;
  445. for (;;) {
  446. ErlMessage* mp;
  447. if (any_heap_ref_ptrs(&rp->fvalue, &rp->fvalue+1, mod_start, mod_size)) {
  448. rp->freason = EXC_NULL;
  449. rp->fvalue = NIL;
  450. rp->ftrace = NIL;
  451. }
  452. if (any_heap_ref_ptrs(rp->stop, rp->hend, mod_start, mod_size)) {
  453. goto need_gc;
  454. }
  455. if (any_heap_refs(rp->heap, rp->htop, mod_start, mod_size)) {
  456. goto need_gc;
  457. }
  458. if (any_heap_refs(rp->old_heap, rp->old_htop, mod_start, mod_size)) {
  459. goto need_gc;
  460. }
  461. if (rp->dictionary != NULL) {
  462. Eterm* start = rp->dictionary->data;
  463. Eterm* end = start + rp->dictionary->used;
  464. if (any_heap_ref_ptrs(start, end, mod_start, mod_size)) {
  465. goto need_gc;
  466. }
  467. }
  468. for (mp = rp->msg.first; mp != NULL; mp = mp->next) {
  469. if (any_heap_ref_ptrs(mp->m, mp->m+2, mod_start, mod_size)) {
  470. goto need_gc;
  471. }
  472. }
  473. break;
  474. need_gc:
  475. if (done_gc) {
  476. return am_true;
  477. } else {
  478. Eterm* literals;
  479. Uint lit_size;
  480. /*
  481. * Try to get rid of constants by by garbage collecting.
  482. * Clear both fvalue and ftrace.
  483. */
  484. rp->freason = EXC_NULL;
  485. rp->fvalue = NIL;
  486. rp->ftrace = NIL;
  487. done_gc = 1;
  488. FLAGS(rp) |= F_NEED_FULLSWEEP;
  489. (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
  490. literals = (Eterm *) modp->old_code[MI_LITERALS_START];
  491. lit_size = (Eterm *) modp->old_code[MI_LITERALS_END] - literals;
  492. erts_garbage_collect_literals(rp, literals, lit_size);
  493. }
  494. }
  495. return am_false;
  496. #undef INSIDE
  497. }
  498. #define in_area(ptr,start,nbytes) \
  499. ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes))
  500. static int
  501. any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size)
  502. {
  503. Eterm* p;
  504. Eterm val;
  505. for (p = start; p < end; p++) {
  506. val = *p;
  507. switch (primary_tag(val)) {
  508. case TAG_PRIMARY_BOXED:
  509. case TAG_PRIMARY_LIST:
  510. if (in_area(EXPAND_POINTER(val), mod_start, mod_size)) {
  511. return 1;
  512. }
  513. break;
  514. }
  515. }
  516. return 0;
  517. }
  518. static int
  519. any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size)
  520. {
  521. Eterm* p;
  522. Eterm val;
  523. for (p = start; p < end; p++) {
  524. val = *p;
  525. switch (primary_tag(val)) {
  526. case TAG_PRIMARY_BOXED:
  527. case TAG_PRIMARY_LIST:
  528. if (in_area(EXPAND_POINTER(val), mod_start, mod_size)) {
  529. return 1;
  530. }
  531. break;
  532. case TAG_PRIMARY_HEADER:
  533. if (!header_is_transparent(val)) {
  534. Eterm* new_p = p + thing_arityval(val);
  535. ASSERT(start <= new_p && new_p < end);
  536. p = new_p;
  537. }
  538. }
  539. }
  540. return 0;
  541. }
  542. #undef in_area
  543. static int
  544. purge_module(int module)
  545. {
  546. BeamInstr* code;
  547. BeamInstr* end;
  548. Module* modp;
  549. /*
  550. * Correct module?
  551. */
  552. if ((modp = erts_get_module(make_atom(module))) == NULL) {
  553. return -2;
  554. }
  555. /*
  556. * Any code to purge?
  557. */
  558. if (modp->old_code == 0) {
  559. if (display_loads) {
  560. erts_printf("No code to purge for %T\n", make_atom(module));
  561. }
  562. return -1;
  563. }
  564. /*
  565. * Unload any NIF library
  566. */
  567. if (modp->old_nif != NULL) {
  568. erts_unload_nif(modp->old_nif);
  569. modp->old_nif = NULL;
  570. }
  571. /*
  572. * Remove the old code.
  573. */
  574. ASSERT(erts_total_code_size >= modp->old_code_length);
  575. erts_total_code_size -= modp->old_code_length;
  576. code = modp->old_code;
  577. end = (BeamInstr *)((char *)code + modp->old_code_length);
  578. erts_cleanup_funs_on_purge(code, end);
  579. beam_catches_delmod(modp->old_catches, code, modp->old_code_length);
  580. erts_free(ERTS_ALC_T_CODE, (void *) code);
  581. modp->old_code = NULL;
  582. modp->old_code_length = 0;
  583. modp->old_catches = BEAM_CATCHES_NIL;
  584. remove_from_address_table(code);
  585. return 0;
  586. }
  587. static void
  588. remove_from_address_table(BeamInstr* code)
  589. {
  590. int i;
  591. for (i = 0; i < num_loaded_modules; i++) {
  592. if (modules[i].start == code) {
  593. num_loaded_modules--;
  594. while (i < num_loaded_modules) {
  595. modules[i] = modules[i+1];
  596. i++;
  597. }
  598. mid_module = &modules[num_loaded_modules/2];
  599. return;
  600. }
  601. }
  602. ASSERT(0); /* Not found? */
  603. }
  604. /*
  605. * Move code from current to old.
  606. */
  607. static void
  608. delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp)
  609. {
  610. #ifdef ERTS_ENABLE_LOCK_CHECK
  611. #ifdef ERTS_SMP
  612. if (c_p && c_p_locks)
  613. erts_proc_lc_chk_only_proc_main(c_p);
  614. else
  615. #endif
  616. erts_lc_check_exact(NULL, 0);
  617. #endif
  618. /*
  619. * Clear breakpoints if any
  620. */
  621. if (modp->code != NULL && modp->code[MI_NUM_BREAKPOINTS] > 0) {
  622. if (c_p && c_p_locks)
  623. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
  624. erts_smp_block_system(0);
  625. erts_clear_module_break(modp);
  626. modp->code[MI_NUM_BREAKPOINTS] = 0;
  627. erts_smp_release_system();
  628. if (c_p && c_p_locks)
  629. erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
  630. }
  631. modp->old_code = modp->code;
  632. modp->old_code_length = modp->code_length;
  633. modp->old_catches = modp->catches;
  634. modp->old_nif = modp->nif;
  635. modp->code = NULL;
  636. modp->code_length = 0;
  637. modp->catches = BEAM_CATCHES_NIL;
  638. modp->nif = NULL;
  639. }
  640. /* null all references on the export table for the module called with the
  641. atom index below */
  642. static void
  643. delete_export_references(Eterm module)
  644. {
  645. int i;
  646. ASSERT(is_atom(module));
  647. for (i = 0; i < export_list_size(); i++) {
  648. Export *ep = export_list(i);
  649. if (ep != NULL && (ep->code[0] == module)) {
  650. if (ep->address == ep->code+3 &&
  651. (ep->code[3] == (BeamInstr) em_apply_bif)) {
  652. continue;
  653. }
  654. ep->address = ep->code+3;
  655. ep->code[3] = (BeamInstr) em_call_error_handler;
  656. ep->code[4] = 0;
  657. MatchSetUnref(ep->match_prog_set);
  658. ep->match_prog_set = NULL;
  659. }
  660. }
  661. }
  662. int
  663. beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module)
  664. {
  665. Module* modp = erts_put_module(module);
  666. /*
  667. * Check if the previous code has been already deleted;
  668. * if not, delete old code; error if old code already exists.
  669. */
  670. if (modp->code != NULL && modp->old_code != NULL) {
  671. return -3;
  672. } else if (modp->old_code == NULL) { /* Make the current version old. */
  673. if (display_loads) {
  674. erts_printf("saving old code\n");
  675. }
  676. delete_code(c_p, c_p_locks, modp);
  677. delete_export_references(module);
  678. }
  679. return 0;
  680. }
  681. static int
  682. is_native(BeamInstr* code)
  683. {
  684. return ((Eterm *)code[MI_FUNCTIONS])[1] != 0;
  685. }