diff options
Diffstat (limited to 'erts/emulator/hipe/hipe_mode_switch.c')
-rw-r--r-- | erts/emulator/hipe/hipe_mode_switch.c | 139 |
1 files changed, 96 insertions, 43 deletions
diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c index 968452a641..ba7ae1e6a8 100644 --- a/erts/emulator/hipe/hipe_mode_switch.c +++ b/erts/emulator/hipe/hipe_mode_switch.c @@ -2,7 +2,7 @@ * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2014. All Rights Reserved. + * Copyright Ericsson AB 2001-2017. 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. @@ -59,6 +59,7 @@ * TODO: check PCB consistency at native BIF calls */ int hipe_modeswitch_debug = 0; +extern BeamInstr beam_exit[]; #define HIPE_DEBUG 0 @@ -108,7 +109,7 @@ static const char *code_str(unsigned code) static void __noreturn hipe_abort(const char *expr, const char *file, unsigned line) { - erl_exit(1, "ASSERTION FAILED, file %s, line %u: %s\r\n", file, line, expr); + erts_exit(ERTS_ERROR_EXIT, "ASSERTION FAILED, file %s, line %u: %s\r\n", file, line, expr); } #define HIPE_ASSERT3(expr, file, line) \ @@ -175,14 +176,15 @@ void hipe_mode_switch_init(void) hipe_mfa_info_table_init(); } -void hipe_set_call_trap(Uint *bfun, void *nfun, int is_closure) +void hipe_set_call_trap(ErtsCodeInfo* ci, void *nfun, int is_closure) { - HIPE_ASSERT(bfun[-5] == BeamOpCode(op_i_func_info_IaaI)); + BeamInstr* bfun = erts_codeinfo_to_code(ci); + HIPE_ASSERT(ci->op == BeamOpCode(op_i_func_info_IaaI)); bfun[0] = is_closure ? BeamOpCode(op_hipe_trap_call_closure) : BeamOpCode(op_hipe_trap_call); - bfun[-4] = (Uint)nfun; + ci->u.ncallee = (void (*)(void)) nfun; } static __inline__ void @@ -196,7 +198,7 @@ hipe_push_beam_trap_frame(Process *p, Eterm reg[], unsigned arity) ASSERT(!(p->flags & F_DISABLE_GC)); if ((p->stop - 2) < p->htop) { DPRINTF("calling gc to increase BEAM stack size"); - p->fcalls -= erts_garbage_collect(p, 2, reg, arity); + erts_garbage_collect(p, 2, reg, arity); ASSERT(!((p->stop - 2) < p->htop)); } p->stop -= 2; @@ -218,15 +220,37 @@ static __inline__ void hipe_pop_beam_trap_frame(Process *p) Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) { unsigned result; -#if NR_ARG_REGS > 5 - /* When NR_ARG_REGS > 5, we need to protect the process' input - reduction count (which BEAM stores in def_arg_reg[5]) from - being clobbered by the arch glue code. */ Eterm reds_in = p->def_arg_reg[5]; -#endif -#if NR_ARG_REGS > 4 - Eterm o_reds = p->def_arg_reg[4]; -#endif + /* + * Process is in the normal case scheduled out when reduction + * count reach zero. When "save calls" is enabled reduction + * count is subtracted with CONTEXT_REDS, i.e. initial reduction + * count will be zero or less and process is scheduled out + * when -CONTEXT_REDS is reached. + * + * HiPE does not support the "save calls" feature, so we switch + * to using a positive reduction counter when executing in + * hipe mode, but need to restore the "save calls" when + * returning to beam. We also need to hide the save calls buffer + * from BIFs. We do that by moving the saved calls buf to + * suspended saved calls buf. + * + * Beam has initial reduction count in stored in p->def_arg_reg[5]. + * + * Beam expects -neg_o_reds to be found in p->def_arg_reg[4] + * on return to beam. + */ + + { + struct saved_calls *scb = ERTS_PROC_SET_SAVED_CALLS_BUF(p, NULL); + if (scb) { + reds_in += CONTEXT_REDS; + p->fcalls += CONTEXT_REDS; + ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(p, scb); + } + } + + p->flags |= F_HIPE_MODE; /* inform bifs where we are comming from... */ p->i = NULL; /* Set current_function to undefined. stdlib hibernate tests rely on it. */ @@ -316,7 +340,7 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) break; } default: - erl_exit(1, "hipe_mode_switch: cmd %#x\r\n", cmd); + erts_exit(ERTS_ERROR_EXIT, "hipe_mode_switch: cmd %#x\r\n", cmd); } do_return_from_native: DPRINTF("result == %#x (%s)", result, code_str(result)); @@ -481,12 +505,25 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_MSG_RECEIVE); do_schedule: { -#if !(NR_ARG_REGS > 5) - int reds_in = p->def_arg_reg[5]; + struct saved_calls *scb; + + scb = ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(p, NULL); + if (scb) + ERTS_PROC_SET_SAVED_CALLS_BUF(p, scb); + + /* The process may have died while it was executing, + if so we return out from native code to the interpreter */ + if (erts_smp_atomic32_read_nob(&p->state) & ERTS_PSFLG_EXITING) + p->i = beam_exit; +#ifdef DEBUG + ASSERT(p->debug_reds_in == reds_in); #endif + p->flags &= ~F_HIPE_MODE; + ERTS_SMP_UNREQ_PROC_MAIN_LOCK(p); - p = schedule(p, reds_in - p->fcalls); + p = erts_schedule(NULL, p, reds_in - p->fcalls); ERTS_SMP_REQ_PROC_MAIN_LOCK(p); + ASSERT(!(p->flags & F_HIPE_MODE)); #ifdef ERTS_SMP p->hipe_smp.have_receive_locks = 0; reg = p->scheduler_data->x_reg_array; @@ -501,28 +538,32 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) reg[i] = argp[i]; } { -#if !(NR_ARG_REGS > 5) - Eterm reds_in; -#endif -#if !(NR_ARG_REGS > 4) - Eterm o_reds; -#endif + struct saved_calls *scb; reds_in = p->fcalls; - o_reds = 0; - if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) { - o_reds = reds_in; - reds_in = 0; - p->fcalls = 0; - } - p->def_arg_reg[4] = o_reds; p->def_arg_reg[5] = reds_in; +#ifdef DEBUG + p->debug_reds_in = reds_in; +#endif if (p->i == hipe_beam_pc_resume) { + p->flags |= F_HIPE_MODE; /* inform bifs where we are comming from... */ + scb = ERTS_PROC_SET_SAVED_CALLS_BUF(p, NULL); + if (scb) + ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(p, scb); p->i = NULL; p->arity = 0; goto do_resume; } + + scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p); + if (!scb) + p->def_arg_reg[4] = 0; + else { + p->def_arg_reg[4] = CONTEXT_REDS; + p->fcalls = -CONTEXT_REDS + reds_in; + } } + HIPE_CHECK_PCB(p); result = HIPE_MODE_SWITCH_RES_CALL_BEAM; p->def_arg_reg[3] = result; @@ -560,16 +601,31 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) goto do_throw_to_native; } default: - erl_exit(1, "hipe_mode_switch: result %#x\r\n", result); + erts_exit(ERTS_ERROR_EXIT, "hipe_mode_switch: result %#x\r\n", result); + } + + { + struct saved_calls *scb = ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(p, NULL); + if (!scb) + p->def_arg_reg[4] = 0; + else { + p->def_arg_reg[4] = CONTEXT_REDS; + p->fcalls -= CONTEXT_REDS; + ERTS_PROC_SET_SAVED_CALLS_BUF(p, scb); + } } + HIPE_CHECK_PCB(p); p->def_arg_reg[3] = result; -#if NR_ARG_REGS > 4 - p->def_arg_reg[4] = o_reds; -#endif #if NR_ARG_REGS > 5 + /* + * When NR_ARG_REGS > 5, we need to protect the process' input + * reduction count (which BEAM stores in def_arg_reg[5]) from + * being clobbered by the arch glue code. + */ p->def_arg_reg[5] = reds_in; #endif + p->flags &= ~F_HIPE_MODE; return p; } @@ -609,7 +665,7 @@ void hipe_inc_nstack(Process *p) { unsigned old_size = p->hipe.nstend - p->hipe.nstack; unsigned new_size = hipe_next_nstack_size(old_size); - Eterm *new_nstack = erts_alloc(ERTS_ALC_T_HIPE, new_size*sizeof(Eterm)); + Eterm *new_nstack = erts_alloc(ERTS_ALC_T_HIPE_STK, new_size*sizeof(Eterm)); unsigned used_size = p->hipe.nstend - p->hipe.nsp; sys_memcpy(new_nstack+new_size-used_size, p->hipe.nsp, used_size*sizeof(Eterm)); @@ -618,7 +674,7 @@ void hipe_inc_nstack(Process *p) if (p->hipe.nstblacklim) p->hipe.nstblacklim = new_nstack + new_size - (p->hipe.nstend - p->hipe.nstblacklim); if (p->hipe.nstack) - erts_free(ERTS_ALC_T_HIPE, p->hipe.nstack); + erts_free(ERTS_ALC_T_HIPE_STK, p->hipe.nstack); p->hipe.nstack = new_nstack; p->hipe.nstend = new_nstack + new_size; p->hipe.nsp = new_nstack + new_size - used_size; @@ -628,7 +684,7 @@ void hipe_inc_nstack(Process *p) void hipe_empty_nstack(Process *p) { if (p->hipe.nstack) { - erts_free(ERTS_ALC_T_HIPE, p->hipe.nstack); + erts_free(ERTS_ALC_T_HIPE_STK, p->hipe.nstack); } p->hipe.nstgraylim = NULL; p->hipe.nsp = NULL; @@ -636,12 +692,9 @@ void hipe_empty_nstack(Process *p) p->hipe.nstend = NULL; } -void hipe_set_closure_stub(ErlFunEntry *fe, unsigned num_free) +void hipe_set_closure_stub(ErlFunEntry *fe) { - unsigned arity; - - arity = fe->arity; - fe->native_address = (Eterm*) hipe_closure_stub_address(arity); + fe->native_address = (Eterm*) hipe_closure_stub_address(fe->arity); } Eterm hipe_build_stacktrace(Process *p, struct StackTrace *s) |