From 22d2a00aebf0eef878af95d8b7598adbfca06e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 19 Sep 2017 06:33:06 +0200 Subject: Use 32-bits pointers to C code On a 64-bit machine, we only need 32 bits to store a pointer to the C code that implements a BEAM instruction. Refactor the code to only use the lower 32 bits of each instruction word, and take care to preserve the high 32 bits. --- erts/configure.in | 33 +++++++++++++++++++++++++++++++++ erts/emulator/beam/beam_bp.c | 19 +++++++++++++------ erts/emulator/beam/beam_emu.c | 30 +++++++++++++++++++++--------- erts/emulator/beam/erl_vm.h | 11 ++++++++++- 4 files changed, 77 insertions(+), 16 deletions(-) diff --git a/erts/configure.in b/erts/configure.in index 85e167b93b..508e99a415 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -3773,6 +3773,39 @@ dnl LM_FIND_EMU_CC +dnl +dnl Test whether code pointers are always short (32 bits). +dnl + +AC_MSG_CHECKING([whether the code model is small]) +saved_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $HIPEBEAMLDFLAGS" +AC_TRY_RUN([ + #include + int main() { + if ((unsigned long long)&main < (1ull << 32)) { + exit(0); + } + exit(1); + } +], +erl_code_model_small=yes, +erl_code_model_small=no, +erl_code_model_small=no) +AC_MSG_RESULT([$erl_code_model_small]) +LDFLAGS="$saved_LDFLAGS" +case $erl_code_model_small in + yes) + AC_DEFINE(CODE_MODEL_SMALL,[1], + [Define if the code model is small (code fits below 2Gb)]) + CODE_MODEL=small + ;; + no) + CODE_MODEL=unknown + ;; +esac +AC_SUBST(CODE_MODEL) + dnl dnl DTrace & LTTNG dnl diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index c81380c14d..871670e8c3 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -419,9 +419,11 @@ erts_install_breakpoints(BpFunctions* f) for (i = 0; i < n; i++) { ErtsCodeInfo* ci = f->matching[i].ci; - BeamInstr *pc = erts_codeinfo_to_code(ci); GenericBp* g = ci->u.gen_bp; - if (*pc != br && g) { + BeamInstr volatile *pc = erts_codeinfo_to_code(ci); + BeamInstr instr = *pc; + + if (!BeamIsOpCode(instr, op_i_generic_breakpoint) && g) { Module* modp = f->matching[i].mod; /* @@ -435,11 +437,16 @@ erts_install_breakpoints(BpFunctions* f) /* * The following write is not protected by any lock. We * assume that the hardware guarantees that a write of an - * aligned word-size (or half-word) writes is atomic - * (i.e. that other processes executing this code will not - * see a half pointer). + * aligned word-size writes is atomic (i.e. that other + * processes executing this code will not see a half + * pointer). + * + * The contents of *pc is marked 'volatile' to ensure that + * the compiler will do a single full-word write, and not + * try any fancy optimizations to write a half word. */ - *pc = br; + instr = BeamSetCodeAddr(instr, br); + *pc = instr; modp->curr.num_breakpoints++; } } diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 9a77c63390..6a45087a34 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -50,14 +50,14 @@ #if defined(NO_JUMP_TABLE) # define OpCase(OpCode) case op_##OpCode # define CountCase(OpCode) case op_count_##OpCode -# define IsOpCode(InstrWord, OpCode) ((InstrWord) == (BeamInstr)op_##OpCode) -# define Goto(Rel) {Go = (Rel); goto emulator_loop;} +# define IsOpCode(InstrWord, OpCode) (BeamCodeAddr(InstrWord) == (BeamInstr)op_##OpCode) +# define Goto(Rel) {Go = BeamCodeAddr(Rel); goto emulator_loop;} #else # define OpCase(OpCode) lb_##OpCode # define CountCase(OpCode) lb_count_##OpCode -# define IsOpCode(InstrWord, OpCode) ((InstrWord) == (BeamInstr)&&lb_##OpCode) -# define Goto(Rel) goto *((void *)Rel) -# define LabelAddr(Label) &&Label +# define IsOpCode(InstrWord, OpCode) (BeamCodeAddr(InstrWord) == (BeamInstr)&&lb_##OpCode) +# define Goto(Rel) goto *((void *)BeamCodeAddr(Rel)) +# define LabelAddr(Label) &&Label #endif #ifdef ERTS_ENABLE_LOCK_CHECK @@ -131,11 +131,11 @@ do { \ /* We don't check the range if an ordinary switch is used */ #ifdef NO_JUMP_TABLE -#define VALID_INSTR(IP) ((UWord)(IP) < (NUMBER_OF_OPCODES*2+10)) +# define VALID_INSTR(IP) (BeamCodeAddr(IP) < (NUMBER_OF_OPCODES*2+10)) #else -#define VALID_INSTR(IP) \ - ((SWord)LabelAddr(emulator_loop) <= (SWord)(IP) && \ - (SWord)(IP) < (SWord)LabelAddr(end_emulator_loop)) +# define VALID_INSTR(IP) \ + ((BeamInstr)LabelAddr(emulator_loop) <= BeamCodeAddr(IP) && \ + BeamCodeAddr(IP) < (BeamInstr)LabelAddr(end_emulator_loop)) #endif /* NO_JUMP_TABLE */ #define SET_CP(p, ip) \ @@ -1006,6 +1006,18 @@ init_emulator_finish(void) int i; Export* ep; +#if defined(ARCH_64) && defined(CODE_MODEL_SMALL) + for (i = 0; i < NUMBER_OF_OPCODES; i++) { + BeamInstr instr = BeamOpCodeAddr(i); + if (instr >= (1ull << 32)) { + erts_exit(ERTS_ERROR_EXIT, + "This run-time was supposed be compiled with all code below 2Gb,\n" + "but the instruction '%s' is located at %016lx.\n", + opc[i].name, instr); + } + } +#endif + beam_apply[0] = BeamOpCodeAddr(op_i_apply); beam_apply[1] = BeamOpCodeAddr(op_normal_exit); beam_exit[0] = BeamOpCodeAddr(op_error_action_code); diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h index 661538eadd..76980b5871 100644 --- a/erts/emulator/beam/erl_vm.h +++ b/erts/emulator/beam/erl_vm.h @@ -209,6 +209,15 @@ extern void** beam_ops; # define BeamOpCodeAddr(OpCode) ((BeamInstr)beam_ops[(OpCode)]) #endif -#define BeamIsOpCode(InstrWord, OpCode) ((InstrWord) == BeamOpCodeAddr(OpCode)) +#if defined(ARCH_64) && defined(CODE_MODEL_SMALL) +# define BeamCodeAddr(InstrWord) ((BeamInstr)(Uint32)(InstrWord)) +# define BeamSetCodeAddr(InstrWord, Addr) (((InstrWord) & ~((1ull << 32)-1)) | (Addr)) +# define BeamExtraData(InstrWord) ((InstrWord) >> 32) +#else +# define BeamCodeAddr(InstrWord) ((BeamInstr)(InstrWord)) +# define BeamSetCodeAddr(InstrWord, Addr) (Addr) +#endif + +#define BeamIsOpCode(InstrWord, OpCode) (BeamCodeAddr(InstrWord) == BeamOpCodeAddr(OpCode)) #endif /* __ERL_VM_H__ */ -- cgit v1.2.3