diff options
Diffstat (limited to 'erts/emulator/beam/jit/asm_load.c')
-rw-r--r-- | erts/emulator/beam/jit/asm_load.c | 124 |
1 files changed, 90 insertions, 34 deletions
diff --git a/erts/emulator/beam/jit/asm_load.c b/erts/emulator/beam/jit/asm_load.c index 24fae1896c..a3594a4800 100644 --- a/erts/emulator/beam/jit/asm_load.c +++ b/erts/emulator/beam/jit/asm_load.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2021. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,15 +36,18 @@ # include <sanitizer/lsan_interface.h> #endif +#define INVALID_LAMBDA_INDEX -1 + static void init_label(Label *lp); -void beam_load_prepare_emit(LoaderState *stp) { +int beam_load_prepare_emit(LoaderState *stp) { BeamCodeHeader *hdr; int i; stp->ba = beamasm_new_assembler(stp->module, stp->beam.code.label_count, - stp->beam.code.function_count); + stp->beam.code.function_count, + &stp->beam); /* Initialize code header */ stp->codev_size = stp->beam.code.function_count + 1; @@ -64,6 +67,7 @@ void beam_load_prepare_emit(LoaderState *stp) { hdr->compile_size_on_heap = 0; hdr->literal_area = NULL; hdr->md5_ptr = NULL; + hdr->are_nifs = NULL; stp->load_hdr = hdr; @@ -73,6 +77,23 @@ void beam_load_prepare_emit(LoaderState *stp) { init_label(&stp->labels[i]); } + for (i = 0; i < stp->beam.lambdas.count; i++) { + BeamFile_LambdaEntry *lambda = &stp->beam.lambdas.entries[i]; + + if (stp->labels[lambda->label].lambda_index == INVALID_LAMBDA_INDEX) { + stp->labels[lambda->label].lambda_index = i; + } else { + beam_load_report_error(__LINE__, + stp, + "lambda already defined for label %i. To " + "fix this, please recompile this module " + "with an OTP " ERLANG_OTP_RELEASE + " compiler.", + lambda->label); + return 0; + } + } + stp->bif_imports = erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->beam.imports.count * sizeof(BifEntry **)); @@ -111,10 +132,13 @@ void beam_load_prepare_emit(LoaderState *stp) { stp->beam.code.function_count * sizeof(unsigned int)); } + + return 1; } static void init_label(Label *lp) { sys_memset(lp, 0, sizeof(*lp)); + lp->lambda_index = INVALID_LAMBDA_INDEX; } void beam_load_prepared_free(Binary *magic) { @@ -132,11 +156,6 @@ int beam_load_prepared_dtor(Binary *magic) { beamfile_free(&stp->beam); beamopallocator_dtor(&stp->op_allocator); - if (stp->bin) { - driver_free_binary(stp->bin); - stp->bin = NULL; - } - if (stp->load_hdr) { BeamCodeHeader *hdr = stp->load_hdr; @@ -144,6 +163,10 @@ int beam_load_prepared_dtor(Binary *magic) { erts_release_literal_area(hdr->literal_area); hdr->literal_area = NULL; } + if (hdr->are_nifs) { + erts_free(ERTS_ALC_T_PREPARED_CODE, hdr->are_nifs); + hdr->are_nifs = NULL; + } erts_free(ERTS_ALC_T_PREPARED_CODE, hdr); stp->load_hdr = NULL; @@ -252,7 +275,7 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { switch (*sign) { case 'n': /* Nil */ ASSERT(tag != TAG_r); - curr->type = TAG_i; + curr->type = 'I'; curr->val = NIL; BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); break; @@ -262,19 +285,20 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case 'a': /* Tagged atom */ BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); - curr->type = TAG_i; + curr->type = 'I'; break; case 'c': /* Tagged constant */ switch (tag) { case TAG_i: curr->val = make_small((Uint)curr->val); + curr->type = 'I'; break; case TAG_a: - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_n: curr->val = NIL; - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_q: break; @@ -294,12 +318,13 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case TAG_i: curr->val = (BeamInstr)make_small(curr->val); + curr->type = 'I'; break; case TAG_a: - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_n: - curr->type = TAG_i; + curr->type = 'I'; curr->val = NIL; break; case TAG_q: { @@ -354,7 +379,8 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case 'A': /* Arity value. */ BeamLoadVerifyTag(stp, tag, TAG_u); - curr->val = make_arityval(curr->val); + curr->val = curr->val == 0 ? make_arityval_zero() + : make_arityval(curr->val); break; case 'f': /* Destination label */ BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); @@ -394,13 +420,14 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { stp->last_label); } stp->labels[stp->last_label].value = 1; + curr->type = TAG_f; break; case 'e': /* Export entry */ BeamLoadVerifyTag(stp, tag, TAG_u); if (curr->val >= stp->beam.imports.count) { BeamLoadError1(stp, "invalid import table index %d", curr->val); } - curr->type = TAG_r; + curr->type = 'E'; break; case 'b': { int i = tmp_op->a[arg].val; @@ -426,10 +453,26 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case 'F': /* Fun entry */ BeamLoadVerifyTag(stp, tag, TAG_u); + curr->type = 'F'; + break; + case 'H': /* Exception handler */ + BeamLoadVerifyTag(stp, tag, TAG_f); + curr->type = 'H'; + break; + case 'M': + curr->type = 'M'; + break; + case 'i': + curr->type = 'I'; break; default: BeamLoadError1(stp, "bad argument tag: %d", *sign); } + + /* These types must have been translated to 'I' */ + ASSERT(curr->type != TAG_i && curr->type != TAG_n && + curr->type != TAG_a && curr->type != TAG_v); + sign++; arg++; } @@ -437,7 +480,7 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { /* * Verify and massage any list arguments according to the primitive tags. * - * TAG_i will denote a tagged immediate value (NIL, small integer, + * 'I' will denote a tagged immediate value (NIL, small integer, * atom, or tuple arity). TAG_n, TAG_a, and TAG_v will no longer be used. */ for (; arg < tmp_op->arity; arg++) { @@ -446,14 +489,15 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { switch (tmp_op->a[arg].type) { case TAG_i: curr->val = make_small(tmp_op->a[arg].val); + curr->type = 'I'; break; case TAG_n: curr->val = NIL; - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_a: case TAG_v: - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_u: case TAG_f: @@ -497,6 +541,17 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { } break; + case op_nif_start: + if (!stp->load_hdr->are_nifs) { + int bytes = stp->beam.code.function_count * sizeof(byte); + stp->load_hdr->are_nifs = + erts_alloc(ERTS_ALC_T_PREPARED_CODE, bytes); + sys_memzero(stp->load_hdr->are_nifs, bytes); + } + ASSERT(stp->function_number > 0); + ASSERT(stp->function_number <= stp->beam.code.function_count); + stp->load_hdr->are_nifs[stp->function_number - 1] = 1; + break; } /* Generate assembly code for the specific instruction. */ @@ -567,6 +622,7 @@ static const BeamCodeLineTab *finish_line_table(LoaderState *stp, const void **line_items_ro; void **line_items_rw; + const unsigned int num_names = stp->beam.lines.name_count; const Eterm *fname_base_ro; Eterm *fname_base_rw; @@ -611,10 +667,9 @@ static const BeamCodeLineTab *finish_line_table(LoaderState *stp, line_items_rw[i] = (void *)&module_base[module_size]; - if (stp->beam.lines.name_count) { - sys_memcpy(fname_base_rw, - stp->beam.lines.names, - stp->beam.lines.name_count * sizeof(Eterm)); + for (i = 0; i < num_names; i++) { + fname_base_rw[i] = + beamfile_get_literal(&stp->beam, stp->beam.lines.names[i]); } if (stp->beam.lines.location_size == sizeof(Uint16)) { @@ -713,15 +768,6 @@ int beam_load_finish_emit(LoaderState *stp) { stp->on_load = beamasm_get_on_load(stp->ba); - /* If there is line information, place it here. This must be done after - * code generation to make sure the addresses are correct. - * - * Ideally we'd want this to be embedded in the module itself just like the - * string table is and use offsets rather than absolute addresses, but this - * will do for now. */ - - code_hdr_rw->line_table = finish_line_table(stp, module_base, module_size); - /* * Place the literals in their own allocated heap (for fast range check) * and fix up all instructions that refer to it. @@ -765,6 +811,10 @@ int beam_load_finish_emit(LoaderState *stp) { (stp->load_hdr)->literal_area = literal_area; } + /* Line information must be added after moving literals, since source file + * names are literal lists. */ + code_hdr_rw->line_table = finish_line_table(stp, module_base, module_size); + if (stp->beam.attributes.size) { const byte *attr = beamasm_get_rodata(stp->ba, "attr"); @@ -864,7 +914,7 @@ void beam_load_finalize_code(LoaderState *stp, * code callable. */ ep->trampoline.not_loaded.deferred = (BeamInstr)address; } else { - ep->addresses[staging_ix] = address; + ep->dispatch.addresses[staging_ix] = address; } } @@ -905,7 +955,7 @@ void beam_load_finalize_code(LoaderState *stp, erts_refc_dectest(&fun_entry->refc, 1); } - fun_entry->address = beamasm_get_code(stp->ba, lambda->label); + erts_set_fun_code(fun_entry, beamasm_get_lambda(stp->ba, i)); beamasm_patch_lambda(stp->ba, stp->native_module_rw, @@ -914,8 +964,14 @@ void beam_load_finalize_code(LoaderState *stp, } } + /* Register debug / profiling info with external tools. */ + beamasm_register_metadata(stp->ba, stp->code_hdr); + + beamasm_flush_icache(inst_p->code_hdr, inst_p->code_length); + /* Prevent literals and code from being freed. */ (stp->load_hdr)->literal_area = NULL; + stp->load_hdr->are_nifs = NULL; stp->native_module_exec = NULL; stp->native_module_rw = NULL; stp->code_hdr = NULL; |