📄 hipe_mode_switch.c
字号:
DPRINTF("result == %#x (%s)", result, code_str(result)); HIPE_CHECK_PCB(p); switch( result ) { case HIPE_MODE_SWITCH_RES_RETURN: { hipe_return_from_native(p); reg[0] = p->def_arg_reg[0]; DPRINTF("returning with r(0) == %#lx", reg[0]); break; } case HIPE_MODE_SWITCH_RES_THROW: { DPRINTF("native throws freason %#lx fvalue %#lx", p->freason, p->fvalue); hipe_throw_from_native(p); break; } case HIPE_MODE_SWITCH_RES_TRAP: { /* * Native code called a BIF, which "failed" with a TRAP to BEAM. * Prior to returning, the BIF stored (see BIF_TRAP<N>): * the callee's Export* in p->def_arg_reg[3] * the callee's parameters in p->def_arg_reg[0..2] * the callee's arity in p->arity (for BEAM gc purposes) * * We need to remove the BIF's parameters from the native * stack: to this end hipe_${ARCH}_glue.S overwrites p->arity * with the BIF's arity. We will recompute the callee's * arity by fetching it from its BEAM function head. */ unsigned int i, is_recursive; /* Here p->arity still describes the original BIF's arity. Get rid of any stacked parameters in that call. */ /* XXX: hipe_call_from_native_is_recursive() copies data to reg[], which is useless in the TRAP case. Maybe write a specialised hipe_trap_from_native_is_recursive() later. */ is_recursive = hipe_call_from_native_is_recursive(p, reg); p->i = ((Export*)(p->def_arg_reg[3]))->address; p->arity = p->i[-1]; for(i = 0; i < p->arity; ++i) reg[i] = p->def_arg_reg[i]; if( is_recursive ) hipe_push_beam_trap_frame(p, reg, p->arity); result = HIPE_MODE_SWITCH_RES_CALL; break; } case HIPE_MODE_SWITCH_RES_CALL: { /* Native code calls or tailcalls BEAM. * * p->i is the callee's BEAM code * p->arity is the callee's arity * p->def_arg_reg[] contains the register parameters * p->hipe.nsp[] contains the stacked parameters */ if( hipe_call_from_native_is_recursive(p, reg) ) { /* BEAM called native, which now calls BEAM */ hipe_push_beam_trap_frame(p, reg, p->arity); } break; } case HIPE_MODE_SWITCH_RES_CALL_CLOSURE: { /* Native code calls or tailcalls a closure in BEAM * * In native code a call to a closure of arity n looks like * F(A1, ..., AN, Closure), * Beam expects to get: * F(A1, ..., AN, FV1, ..., FVM, Closure) * (Where Ai is argument i and FVi is free variable i) * * p->hipe.closure contains the closure * p->def_arg_reg[] contains the parameters (on SPARC) */ ErlFunThing *closure; unsigned num_free, arity, i, is_recursive; HIPE_ASSERT(is_fun(p->hipe.closure)); closure = (ErlFunThing*)fun_val(p->hipe.closure); num_free = closure->num_free; arity = closure->fe->address[-1] - num_free; /* Store the arity in p->arity for the stack popping. */ p->arity = arity+1; /* +1 for the closure */ /* Get parameters, don't do GC just yet. */ is_recursive = hipe_call_from_native_is_recursive(p, reg); /* Append the free vars to the actual parameters. */ for(i = 0; i < num_free; ++i) reg[arity+i] = closure->env[i]; /* Put the closure as the last argument. */ reg[arity+i] = p->hipe.closure; /* Make a call to the closure's BEAM code. */ p->i = closure->fe->address; if( is_recursive ) { /* BEAM called native, which now calls BEAM. Need to put a trap-frame on the beam stack. This may cause GC, which is safe now that the arguments, free vars, and most importantly the closure, all are in reg[]. */ hipe_push_beam_trap_frame(p, reg, arity+i); } result = HIPE_MODE_SWITCH_RES_CALL; break; } case HIPE_MODE_SWITCH_RES_RESCHEDULE: { DPRINTF("native reschedules 0x%#lx/%u\r\n", p->hipe.ncallee, p->arity); hipe_reschedule_from_native(p); p->i = hipe_beam_pc_reschedule; goto do_schedule; } case HIPE_MODE_SWITCH_RES_SUSPEND: { p->i = hipe_beam_pc_resume; p->arity = 0; erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); add_to_schedule_q(p); erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); goto do_schedule; } case HIPE_MODE_SWITCH_RES_WAIT: case HIPE_MODE_SWITCH_RES_WAIT_TIMEOUT: { /* same semantics, different debug trace messages */#ifdef ERTS_SMP /* XXX: BEAM has different entries for the locked and unlocked cases. HiPE doesn't, so we must check dynamically. */ if (p->hipe_smp.have_receive_locks) p->hipe_smp.have_receive_locks = 0; else erts_smp_proc_lock(p, ERTS_PROC_LOCKS_MSG_RECEIVE);#endif p->i = hipe_beam_pc_resume; p->arity = 0; p->status = P_WAITING; 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];#endif p = schedule(p, reds_in - p->fcalls);#ifdef ERTS_SMP p->hipe_smp.have_receive_locks = 0; reg = p->scheduler_data->save_reg;#endif } { Eterm *argp; int i; argp = p->arg_reg; for(i = p->arity; --i >= 0;) reg[i] = argp[i]; } {#if !(NR_ARG_REGS > 5) Eterm reds_in;#endif#if !(NR_ARG_REGS > 4) Eterm o_reds;#endif reds_in = p->fcalls; o_reds = 0; if( p->ct != NULL ) { o_reds = reds_in; reds_in = 0; p->fcalls = 0; } p->def_arg_reg[4] = o_reds; p->def_arg_reg[5] = reds_in; if( p->i == hipe_beam_pc_resume ) { p->i = NULL; p->arity = 0; goto do_resume; } } HIPE_CHECK_PCB(p); result = HIPE_MODE_SWITCH_RES_CALL; p->def_arg_reg[3] = result; return p; } case HIPE_MODE_SWITCH_RES_APPLY: { Eterm mfa[3], args; unsigned int arity; void *address; hipe_pop_params(p, 3, &mfa[0]); /* Unroll the arglist onto reg[]. */ args = mfa[2]; arity = 0; while( is_list(args) ) { if( arity < 255 ) { reg[arity++] = CAR(list_val(args)); args = CDR(list_val(args)); } else goto do_apply_fail; } if( is_not_nil(args) ) goto do_apply_fail; /* find a native code entry point for {M,F,A} for a remote call */ address = hipe_get_remote_na(mfa[0], mfa[1], arity); if (!address) goto do_apply_fail; p->hipe.ncallee = (void(*)(void)) address; result = hipe_tailcall_to_native(p, arity, reg); goto do_return_from_native; do_apply_fail: p->freason = BADARG; goto do_throw_to_native; } default: erl_exit(1, "hipe_mode_switch: result %#x\r\n", result); } 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 p->def_arg_reg[5] = reds_in;#endif return p;}#define HIPE_INITIAL_NSTACK_SIZE 128/* PRE: size is zero or a power of two */static unsigned hipe_next_nstack_size(unsigned size){ return size ? size * 2 : HIPE_INITIAL_NSTACK_SIZE;}#ifdef HIPE_NSTACK_GROWS_UP#define hipe_nstack_avail(p) ((p)->hipe.nstend - (p)->hipe.nsp)void hipe_inc_nstack(Process *p){ Eterm *old_nstack = p->hipe.nstack; unsigned old_size = p->hipe.nstend - old_nstack; unsigned new_size = hipe_next_nstack_size(old_size); Eterm *new_nstack = erts_realloc(ERTS_ALC_T_HIPE, (char *) old_nstack, new_size*sizeof(Eterm)); p->hipe.nstend = new_nstack + new_size; if( new_nstack != old_nstack ) { p->hipe.nsp = new_nstack + (p->hipe.nsp - old_nstack); p->hipe.nstack = new_nstack; if( p->hipe.nstgraylim ) p->hipe.nstgraylim = new_nstack + (p->hipe.nstgraylim - old_nstack); if( p->hipe.nstblacklim ) p->hipe.nstblacklim = new_nstack + (p->hipe.nstblacklim - old_nstack); }}#endif#ifdef HIPE_NSTACK_GROWS_DOWN#define hipe_nstack_avail(p) ((unsigned)((p)->hipe.nsp - (p)->hipe.nstack))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)); unsigned used_size = p->hipe.nstend - p->hipe.nsp; sys_memcpy(new_nstack+new_size-used_size, p->hipe.nsp, used_size*sizeof(Eterm)); if( p->hipe.nstgraylim ) p->hipe.nstgraylim = new_nstack + new_size - (p->hipe.nstend - p->hipe.nstgraylim); 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); p->hipe.nstack = new_nstack; p->hipe.nstend = new_nstack + new_size; p->hipe.nsp = new_nstack + new_size - used_size;}#endifstatic void hipe_check_nstack(Process *p, unsigned nwords){ while( hipe_nstack_avail(p) < nwords ) hipe_inc_nstack(p);}void hipe_set_closure_stub(ErlFunEntry *fe, unsigned num_free){ unsigned arity; arity = fe->address[-1] - num_free; fe->native_address = (Eterm*) hipe_closure_stub_address(arity);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -