From 8650d6d811bb99490e1a75cbbab684a673a950ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Sat, 2 Sep 2017 14:35:39 +0200 Subject: Refactor instructions to support relative jumps Introduce new macros that can be used for relative jumps and use them consistently. Test that everything works by using a non-zero constant JUMP_OFFSET. The loader subtracts JUMP_OFFSET from loaded labels, and all instructions that use 'f' operands add it back. --- erts/emulator/beam/beam_load.c | 8 ++++++-- erts/emulator/beam/beam_load.h | 2 ++ erts/emulator/beam/bif_instrs.tab | 14 +++++++------- erts/emulator/beam/instrs.tab | 32 ++++++++++++++++++++++---------- erts/emulator/beam/macros.tab | 19 +++++++++++++++++-- erts/emulator/beam/msg_instrs.tab | 10 +++++----- erts/emulator/beam/select_instrs.tab | 8 ++++---- erts/emulator/beam/trace_instrs.tab | 2 +- 8 files changed, 64 insertions(+), 31 deletions(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 7d3a19ff86..9b8f33f576 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -4840,7 +4840,11 @@ freeze_code(LoaderState* stp) ASSERT(this_patch < stp->ci); next_patch = codev[this_patch]; ASSERT(next_patch < stp->ci); - codev[this_patch] = (BeamInstr) (codev + value); + if (this_patch < stp->num_functions) { + codev[this_patch] = (BeamInstr) (codev + value); + } else { + codev[this_patch] = (BeamInstr) (codev + value - JUMP_OFFSET); + } this_patch = next_patch; } } @@ -4885,7 +4889,7 @@ final_touch(LoaderState* stp, struct erl_module_instance* inst_p) while (index != 0) { BeamInstr next = codev[index]; codev[index] = BeamOpCode(op_catch_yf); - catches = beam_catches_cons((BeamInstr *)codev[index+2], catches); + catches = beam_catches_cons((BeamInstr *)codev[index+2]+JUMP_OFFSET, catches); codev[index+2] = make_catch(catches); index = next; } diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index c088bdb751..0b6543638f 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -21,6 +21,8 @@ #ifndef _BEAM_LOAD_H # define _BEAM_LOAD_H +#define JUMP_OFFSET 0x5 + #include "beam_opcodes.h" #include "erl_process.h" diff --git a/erts/emulator/beam/bif_instrs.tab b/erts/emulator/beam/bif_instrs.tab index 3c95113907..0932b8b985 100644 --- a/erts/emulator/beam/bif_instrs.tab +++ b/erts/emulator/beam/bif_instrs.tab @@ -151,7 +151,7 @@ i_gc_bif1(Fail, Bif, Src, Live, Dst) { $NEXT0(); } if (ERTS_LIKELY($Fail != 0)) { /* Handle error in guard. */ - $NEXT($Fail); + $JUMP($Fail); } /* Handle error in body. */ @@ -202,7 +202,7 @@ i_gc_bif2(Fail, Bif, Live, Src1, Src2, Dst) { } if (ERTS_LIKELY($Fail != 0)) { /* Handle error in guard. */ - $NEXT($Fail); + $JUMP($Fail); } /* Handle error in body. */ @@ -257,7 +257,7 @@ i_gc_bif3(Fail, Bif, Live, Src2, Src3, Dst) { /* Handle error in guard. */ if (ERTS_LIKELY($Fail != 0)) { - $NEXT($Fail); + $JUMP($Fail); } /* Handle error in body. */ @@ -473,10 +473,10 @@ nif_bif.apply_bif() { /* In case we apply process_info/1,2 or load_nif/1 */ c_p->current = codemfa; - c_p->i = I; /* In case we apply check_process_code/2. */ - c_p->arity = 0; /* To allow garbage collection on ourselves - * (check_process_code/2). - */ + $SET_CP_I_ABS(I); /* In case we apply check_process_code/2. */ + c_p->arity = 0; /* To allow garbage collection on ourselves + * (check_process_code/2). + */ DTRACE_BIF_ENTRY(c_p, codemfa); SWAPOUT; diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab index 690bd3a848..7ea9dee299 100644 --- a/erts/emulator/beam/instrs.tab +++ b/erts/emulator/beam/instrs.tab @@ -78,7 +78,14 @@ move_deallocate_return(Src, Deallocate) { // Call instructions -DISPATCH(CallDest) { +DISPATCH_REL(CallDest) { + //| -no_next + $SET_I_REL($CallDest); + DTRACE_LOCAL_CALL(c_p, erts_code_to_codemfa(I)); + Dispatch(); +} + +DISPATCH_ABS(CallDest) { //| -no_next SET_I((BeamInstr *) $CallDest); DTRACE_LOCAL_CALL(c_p, erts_code_to_codemfa(I)); @@ -87,18 +94,18 @@ DISPATCH(CallDest) { i_call(CallDest) { SET_CP(c_p, $NEXT_INSTRUCTION); - $DISPATCH($CallDest); + $DISPATCH_REL($CallDest); } move_call(Src, CallDest) { x(0) = $Src; SET_CP(c_p, $NEXT_INSTRUCTION); - $DISPATCH($CallDest); + $DISPATCH_REL($CallDest); } i_call_last(CallDest, Deallocate) { $deallocate($Deallocate); - $DISPATCH($CallDest); + $DISPATCH_REL($CallDest); } move_call_last(Src, CallDest, Deallocate) { @@ -107,7 +114,7 @@ move_call_last(Src, CallDest, Deallocate) { } i_call_only(CallDest) { - $DISPATCH($CallDest); + $DISPATCH_REL($CallDest); } move_call_only(Src, CallDest) { @@ -168,7 +175,8 @@ i_apply() { BeamInstr *next; $APPLY(NULL, 0, next); if (ERTS_LIKELY(next != NULL)) { - $i_call(next); + SET_CP(c_p, $NEXT_INSTRUCTION); + $DISPATCH_ABS(next); } $HANDLE_APPLY_ERROR(); } @@ -177,7 +185,8 @@ i_apply_last(Deallocate) { BeamInstr *next; $APPLY(I, $Deallocate, next); if (ERTS_LIKELY(next != NULL)) { - $i_call_last(next, $Deallocate); + $deallocate($Deallocate); + $DISPATCH_ABS(next); } $HANDLE_APPLY_ERROR(); } @@ -186,7 +195,7 @@ i_apply_only() { BeamInstr *next; $APPLY(I, 0, next); if (ERTS_LIKELY(next != NULL)) { - $i_call_only(next); + $DISPATCH_ABS(next); } $HANDLE_APPLY_ERROR(); } @@ -202,7 +211,8 @@ apply(Arity) { BeamInstr *next; $FIXED_APPLY($Arity, NULL, 0, next); if (ERTS_LIKELY(next != NULL)) { - $i_call(next); + SET_CP(c_p, $NEXT_INSTRUCTION); + $DISPATCH_ABS(next); } $HANDLE_APPLY_ERROR(); } @@ -211,7 +221,8 @@ apply_last(Arity, Deallocate) { BeamInstr *next; $FIXED_APPLY($Arity, I, $Deallocate, next); if (ERTS_LIKELY(next != NULL)) { - $i_call_last(next, $Deallocate); + $deallocate($Deallocate); + $DISPATCH_ABS(next); } $HANDLE_APPLY_ERROR(); } @@ -560,6 +571,7 @@ i_put_tuple.fill(Arity) { } } while (--arity != 0); HTOP = hp; + ASSERT(VALID_INSTR(* (Eterm *)I)); Goto(*I); } diff --git a/erts/emulator/beam/macros.tab b/erts/emulator/beam/macros.tab index bac96be7d3..959f7b28df 100644 --- a/erts/emulator/beam/macros.tab +++ b/erts/emulator/beam/macros.tab @@ -28,15 +28,30 @@ REFRESH_GEN_DEST() { dst_ptr = REG_TARGET_PTR(dst); } +SET_I_REL(Offset) { + ASSERT(VALID_INSTR(* (Eterm *)((BeamInstr *) ($Offset) + JUMP_OFFSET))); + I = (BeamInstr *) $Offset + JUMP_OFFSET; +} + +SET_CP_I_ABS(Target) { + c_p->i = $Target; + ASSERT(VALID_INSTR(* (Eterm *)c_p->i)); +} + +SET_REL_I(Dst, Offset) { + $Dst = (BeamInstr *) ($Offset) + JUMP_OFFSET; + ASSERT(VALID_INSTR(*$Dst)); +} + FAIL(Fail) { //| -no_prefetch - SET_I((BeamInstr *) $Fail); + $SET_I_REL($Fail); Goto(*I); } JUMP(Fail) { //| -no_next - SET_I((BeamInstr *) $Fail); + $SET_I_REL($Fail); Goto(*I); } diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab index 093d48c64c..8055a8616f 100644 --- a/erts/emulator/beam/msg_instrs.tab +++ b/erts/emulator/beam/msg_instrs.tab @@ -49,7 +49,7 @@ recv_mark(Dest) { * the label for the loop_rec/2 instruction for the * the receive statement. */ - c_p->msg.mark = (BeamInstr *) $Dest; + $SET_REL_I(c_p->msg.mark, $Dest); c_p->msg.saved_last = c_p->msg.last; } @@ -116,7 +116,7 @@ i_loop_rec(Dest) { erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); } else { c_p->flags &= ~F_DELAY_GC; - SET_I((BeamInstr *) $Dest); + $SET_I_REL($Dest); Goto(*I); /* Jump to a wait or wait_timeout instruction */ } } @@ -253,7 +253,7 @@ loop_rec_end(Dest) { ASSERT(c_p->flags & F_DELAY_GC); - SET_I((BeamInstr *) $Dest); + $SET_I_REL($Dest); SAVE_MESSAGE(c_p); if (FCALLS > 0 || FCALLS > neg_o_reds) { FCALLS--; @@ -261,7 +261,7 @@ loop_rec_end(Dest) { } c_p->flags &= ~F_DELAY_GC; - c_p->i = I; + $SET_CP_I_ABS(I); SWAPOUT; c_p->arity = 0; c_p->current = NULL; @@ -374,7 +374,7 @@ wait.src(Src) { // wait.execute(JumpTarget) { - c_p->i = (BeamInstr *) $JumpTarget; /* L1 */ + $SET_REL_I(c_p->i, $JumpTarget); /* L1 */ SWAPOUT; c_p->arity = 0; diff --git a/erts/emulator/beam/select_instrs.tab b/erts/emulator/beam/select_instrs.tab index e85ed2c304..88049bbcf0 100644 --- a/erts/emulator/beam/select_instrs.tab +++ b/erts/emulator/beam/select_instrs.tab @@ -68,10 +68,10 @@ select_val_bins.select(Fail, NumElements) { } else if (select_val > mid->val) { low = mid + 1; } else { - $NEXT(mid->addr); + $JUMP(mid->addr); } } - $NEXT($Fail); + $JUMP($Fail); } i_select_tuple_arity2 := select_val2.src.ta_fail.execute; @@ -150,8 +150,8 @@ select_val_lin.execute(N) { } if (vs[ix] == select_val) { - I = $NEXT_INSTRUCTION + $N + ix; - $JUMP(*I); + Eterm offset = *($NEXT_INSTRUCTION + $N + ix); + $JUMP(offset); } else { $JUMP(*select_fail); } diff --git a/erts/emulator/beam/trace_instrs.tab b/erts/emulator/beam/trace_instrs.tab index c28bc8ebcb..b10442c5e7 100644 --- a/erts/emulator/beam/trace_instrs.tab +++ b/erts/emulator/beam/trace_instrs.tab @@ -94,7 +94,7 @@ i_yield() { c_p->arg_reg[0] = am_true; c_p->arity = 1; /* One living register (the 'true' return value) */ SWAPOUT; - c_p->i = $NEXT_INSTRUCTION; + $SET_CP_I_ABS($NEXT_INSTRUCTION); c_p->current = NULL; goto do_schedule; //| -no_next -- cgit v1.2.3