aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2017-09-02 14:35:39 +0200
committerBjörn Gustavsson <[email protected]>2017-09-13 12:20:56 +0200
commit8650d6d811bb99490e1a75cbbab684a673a950ba (patch)
tree39924f5d0b31516b7e1d54e0755a6e7cc47c2b78
parentbffbd4fb504e9551fc7feb9177ef0a2394c00cae (diff)
downloadotp-8650d6d811bb99490e1a75cbbab684a673a950ba.tar.gz
otp-8650d6d811bb99490e1a75cbbab684a673a950ba.tar.bz2
otp-8650d6d811bb99490e1a75cbbab684a673a950ba.zip
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.
-rw-r--r--erts/emulator/beam/beam_load.c8
-rw-r--r--erts/emulator/beam/beam_load.h2
-rw-r--r--erts/emulator/beam/bif_instrs.tab14
-rw-r--r--erts/emulator/beam/instrs.tab32
-rw-r--r--erts/emulator/beam/macros.tab19
-rw-r--r--erts/emulator/beam/msg_instrs.tab10
-rw-r--r--erts/emulator/beam/select_instrs.tab8
-rw-r--r--erts/emulator/beam/trace_instrs.tab2
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