diff --git a/erts/emulator/beam/jit/arm/beam_asm.hpp b/erts/emulator/beam/jit/arm/beam_asm.hpp index 27e3affdac9e..26415a2ae6da 100644 --- a/erts/emulator/beam/jit/arm/beam_asm.hpp +++ b/erts/emulator/beam/jit/arm/beam_asm.hpp @@ -1401,6 +1401,10 @@ class BeamModuleAssembler : public BeamAssembler, * the current code position is unreachable. */ void flush_pending_labels(); + /* Move past the `last_error_offset` if necessary for the next instruction + * to be properly aligned (e.g. for line mappings). */ + void flush_last_error(); + /* Calls the given shared fragment, ensuring that the redzone is unused and * that the return address forms a valid CP. */ template diff --git a/erts/emulator/beam/jit/arm/beam_asm_module.cpp b/erts/emulator/beam/jit/arm/beam_asm_module.cpp index caec6c0eb890..f940783460a1 100644 --- a/erts/emulator/beam/jit/arm/beam_asm_module.cpp +++ b/erts/emulator/beam/jit/arm/beam_asm_module.cpp @@ -376,6 +376,11 @@ void BeamModuleAssembler::emit_aligned_label(const ArgLabel &Label, emit_label(Label); } +void BeamModuleAssembler::emit_i_func_label(const ArgLabel &Label) { + flush_last_error(); + emit_aligned_label(Label, ArgVal(ArgVal::Word, sizeof(UWord))); +} + void BeamModuleAssembler::emit_on_load() { on_load = current_label; } @@ -430,22 +435,12 @@ void BeamModuleAssembler::emit_int_code_end() { void BeamModuleAssembler::emit_line(const ArgWord &Loc) { /* There is no need to align the line instruction. In the loaded code, the * type of the pointer will be void* and that pointer will only be used in - * comparisons. - * - * We only need to do something when there's a possibility of raising an - * exception at the very end of the preceding instruction (and thus - * pointing at the start of this one). If we were to do nothing, the error - * would erroneously refer to this instead of the preceding line. - * - * Since line addresses are taken _after_ line instructions we can avoid - * this by adding a nop when we detect this condition. */ - if (a.offset() == last_error_offset) { - a.nop(); - } + * comparisons. */ + + flush_last_error(); } void BeamModuleAssembler::emit_func_line(const ArgWord &Loc) { - emit_line(Loc); } void BeamModuleAssembler::emit_empty_func_line() { @@ -823,3 +818,16 @@ void BeamModuleAssembler::emit_constant(const Constant &constant) { } } } + +void BeamModuleAssembler::flush_last_error() { + /* When there's a possibility of raising an exception at the very end of the + * preceding instruction (and thus pointing at the start of this one) and + * this instruction has a new line registered, the error would erroneously + * refer to this instead of the preceding line. + * + * By adding a nop when we detect this condition, the error will correctly + * refer to the preceding line. */ + if (a.offset() == last_error_offset) { + a.nop(); + } +} diff --git a/erts/emulator/beam/jit/arm/ops.tab b/erts/emulator/beam/jit/arm/ops.tab index 73266ec4a0a0..3b0333a83db1 100644 --- a/erts/emulator/beam/jit/arm/ops.tab +++ b/erts/emulator/beam/jit/arm/ops.tab @@ -42,12 +42,15 @@ label L # An label aligned to a certain boundary. This is used in two cases: # -# * When the label points to the start of a function, as the ErtsCodeInfo -# struct must be word-aligned. +# * When the label points to the start of a function. See `i_func_label`. # * When the address is stored on the stack or otherwise needs to be properly # tagged as a continuation pointer. aligned_label L t +# A label indicating the start of a function. The label is word-aligned as is +# required by the ErtsCodeInfo struct. +i_func_label L + i_func_info I a a I int_code_end nif_start @@ -903,8 +906,8 @@ int_func_start Func_Label Func_Line M F A | func_prologue Entry_Label Entry_Line | is_mfa_bif(M, F, A) => i_flush_stubs | + i_func_label Func_Label | func_line Func_Line | - aligned_label Func_Label u=8 | i_func_info Func_Label M F A | aligned_label Entry_Label u=4 | i_breakpoint_trampoline | @@ -914,8 +917,8 @@ int_func_start Func_Label Func_Line M F A | int_func_start Func_Label Func_Line M F A | func_prologue Entry_Label Entry_Line => i_flush_stubs | + i_func_label Func_Label | func_line Func_Line | - aligned_label Func_Label u=8 | i_func_info Func_Label M F A | aligned_label Entry_Label u=4 | i_breakpoint_trampoline | diff --git a/erts/emulator/beam/jit/asm_load.c b/erts/emulator/beam/jit/asm_load.c index dd337a5d34a3..91ce7285c24f 100644 --- a/erts/emulator/beam/jit/asm_load.c +++ b/erts/emulator/beam/jit/asm_load.c @@ -505,7 +505,8 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case 'L': /* Define label */ ASSERT(stp->specific_op == op_label_L || - stp->specific_op == op_aligned_label_Lt); + stp->specific_op == op_aligned_label_Lt || + stp->specific_op == op_i_func_label_L); BeamLoadVerifyTag(stp, tag, TAG_u); stp->last_label = curr->val; if (stp->last_label < 0 || diff --git a/erts/emulator/beam/jit/x86/beam_asm.hpp b/erts/emulator/beam/jit/x86/beam_asm.hpp index 4a2c965b2196..105c9aa41a64 100644 --- a/erts/emulator/beam/jit/x86/beam_asm.hpp +++ b/erts/emulator/beam/jit/x86/beam_asm.hpp @@ -1424,6 +1424,10 @@ class BeamModuleAssembler : public BeamAssembler, * appropriate address before jumping there. */ const Label &resolve_fragment(void (*fragment)()); + /* Move past the `last_error_offset` if necessary for the next instruction + * to be properly aligned (e.g. for line mappings). */ + void flush_last_error(); + void safe_fragment_call(void (*fragment)()) { emit_assert_redzone_unused(); a.call(resolve_fragment(fragment)); diff --git a/erts/emulator/beam/jit/x86/beam_asm_module.cpp b/erts/emulator/beam/jit/x86/beam_asm_module.cpp index 5ad3672c185e..36b20842a0cb 100644 --- a/erts/emulator/beam/jit/x86/beam_asm_module.cpp +++ b/erts/emulator/beam/jit/x86/beam_asm_module.cpp @@ -342,6 +342,11 @@ void BeamModuleAssembler::emit_aligned_label(const ArgLabel &Label, emit_label(Label); } +void BeamModuleAssembler::emit_i_func_label(const ArgLabel &Label) { + flush_last_error(); + emit_aligned_label(Label, ArgVal(ArgVal::Word, sizeof(UWord))); +} + void BeamModuleAssembler::emit_on_load() { on_load = current_label; } @@ -362,22 +367,12 @@ void BeamModuleAssembler::emit_int_code_end() { void BeamModuleAssembler::emit_line(const ArgWord &Loc) { /* There is no need to align the line instruction. In the loaded code, the * type of the pointer will be void* and that pointer will only be used in - * comparisons. - * - * We only need to do something when there's a possibility of raising an - * exception at the very end of the preceding instruction (and thus - * pointing at the start of this one). If we were to do nothing, the error - * would erroneously refer to this instead of the preceding line. - * - * Since line addresses are taken _after_ line instructions we can avoid - * this by adding a nop when we detect this condition. */ - if (a.offset() == last_error_offset) { - a.nop(); - } + * comparisons. */ + + flush_last_error(); } void BeamModuleAssembler::emit_func_line(const ArgWord &Loc) { - emit_line(Loc); } void BeamModuleAssembler::emit_empty_func_line() { @@ -416,3 +411,16 @@ const Label &BeamModuleAssembler::resolve_fragment(void (*fragment)()) { return it->second; } + +void BeamModuleAssembler::flush_last_error() { + /* When there's a possibility of raising an exception at the very end of the + * preceding instruction (and thus pointing at the start of this one) and + * this instruction has a new line registered, the error would erroneously + * refer to this instead of the preceding line. + * + * By adding a nop when we detect this condition, the error will correctly + * refer to the preceding line. */ + if (a.offset() == last_error_offset) { + a.nop(); + } +} diff --git a/erts/emulator/beam/jit/x86/ops.tab b/erts/emulator/beam/jit/x86/ops.tab index f8a46e145334..5d1c3ff42c6b 100644 --- a/erts/emulator/beam/jit/x86/ops.tab +++ b/erts/emulator/beam/jit/x86/ops.tab @@ -42,12 +42,15 @@ label L # An label aligned to a certain boundary. This is used in two cases: # -# * When the label points to the start of a function, as the ErtsCodeInfo -# struct must be word-aligned. +# * When the label points to the start of a function. See `i_func_label`. # * When the address is stored on the stack or otherwise needs to be properly # tagged as a continuation pointer. aligned_label L t +# A label indicating the start of a function. The label is word-aligned as is +# required by the ErtsCodeInfo struct. +i_func_label L + i_func_info I a a I int_code_end nif_start @@ -827,8 +830,8 @@ int_func_start Func_Label Func_Line M F A | int_func_start Func_Label Func_Line M F A | func_prologue Entry_Label Entry_Line | is_mfa_bif(M, F, A) => + i_func_label Func_Label | func_line Func_Line | - aligned_label Func_Label u=8 | i_func_info Func_Label M F A | aligned_label Entry_Label u=4 | i_breakpoint_trampoline | @@ -837,8 +840,8 @@ int_func_start Func_Label Func_Line M F A | int_func_start Func_Label Func_Line M F A | func_prologue Entry_Label Entry_Line => + i_func_label Func_Label | func_line Func_Line | - aligned_label Func_Label u=8 | i_func_info Func_Label M F A | aligned_label Entry_Label u=4 | i_breakpoint_trampoline |