📄 hipe_mode_switch.c
字号:
/* $Id$ * hipe_mode_switch.c */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "sys.h"#include "erl_vm.h"#include "global.h"#include "erl_process.h"#include "beam_load.h" /* which includes beam_opcodes.h */#include "beam_catches.h"#include "hipe_mode_switch.h"#include "bif.h"#include "error.h"#include "hipe_stack.h"#include "hipe_bif0.h" /* hipe_mfa_info_table_init() *//* * Internal debug support. * #define HIPE_DEBUG to the desired debug level: * 0 no checks * 1 check PCB consistency at mode-switches * 2 log commands and results at mode-switches * 3 log commands, results, and PCB contents at mode-switches * * TODO: check PCB consistency at native BIF calls */int hipe_modeswitch_debug = 0;#define HIPE_DEBUG 0#if HIPE_DEBUG > 1 /* include DPRINTF() logging */#define DPRINTF(fmt, args...) \do { \ if( hipe_modeswitch_debug > 0 ) { \ printf("%s, line %u: " fmt "\r\n", __FUNCTION__, __LINE__ , ##args); \ fflush(stdout); \ } \} while( 0 )static const char *code_str(unsigned code){ static const char *cmd_str[] = { "call from beam", "return from beam", "throw from beam", "resume from beam", "reschedule from beam", "return to beam", "call to beam", "throw to beam", "suspend to beam", "wait from native", "wait_timeout from native", "reschedule from native", "trap from native", "call closure from beam", "call closure to beam", }; unsigned cmd = code & 0xFF; if( cmd < (sizeof(cmd_str)/sizeof(cmd_str[0])) ) return cmd_str[cmd]; else return "???";}#else /* HIPE_DEBUG > 1 */#define DPRINTF(fmt, args...) do{}while(0)#endif /* HIPE_DEBUG > 1 */#if HIPE_DEBUG > 0 /* include HIPE_ASSERT and PCB checking */static void __noreturnhipe_abort(const char *expr, const char *file, unsigned line){ erl_exit(1, "ASSERTION FAILED, file %s, line %u: %s\r\n", file, line, expr);}#define HIPE_ASSERT3(expr,file,line) \do { \ if( !(expr) ) \ hipe_abort(#expr, file, line); \} while( 0 )#define HIPE_ASSERT(expr) HIPE_ASSERT3(expr,__FILE__,__LINE__)void hipe_check_pcb(Process *p, const char *file, unsigned line){#if HIPE_DEBUG > 2 if( hipe_modeswitch_debug > 0 ) { printf("%s, line %u: p %p = {htop %p, stop %p, nstack %p, nsp %p, nstend %p}\r\n", file, line, p, p->htop, p->stop, p->hipe.nstack, p->hipe.nsp, p->hipe.nstend); }#endif HIPE_ASSERT3(p != NULL, file, line); HIPE_ASSERT3(p->htop <= p->stop, file, line); HIPE_ASSERT3(p->hipe.nstack <= p->hipe.nstend, file, line); HIPE_ASSERT3(p->hipe.nsp >= p->hipe.nstack, file, line); HIPE_ASSERT3(p->hipe.nsp <= p->hipe.nstend, file, line);}#define HIPE_CHECK_PCB(P) hipe_check_pcb((P),__FILE__,__LINE__)#else /* HIPE_DEBUG > 0 */#define HIPE_ASSERT(expr) do{}while(0)#define HIPE_CHECK_PCB(P) do{}while(0)#endif /* HIPE_DEBUG > 0 *//* ensure that at least nwords words are available on the native stack */static void hipe_check_nstack(Process *p, unsigned nwords);#if defined(__sparc__)#include "hipe_sparc_glue.h"#elif defined(__i386__)#include "hipe_x86_glue.h"#elif defined(__x86_64__)#include "hipe_amd64_glue.h"#elif defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__)#include "hipe_ppc_glue.h"#elif defined(__arm__)#include "hipe_arm_glue.h"#endif#define BeamOpCode(Op) ((Uint)BeamOp(Op))Uint hipe_beam_pc_return[1]; /* needed in hipe_debug.c */Uint hipe_beam_pc_throw[1]; /* needed in hipe_debug.c */Uint hipe_beam_pc_resume[1]; /* needed by hipe_set_timeout() */static Uint hipe_beam_pc_reschedule[1];static Eterm hipe_beam_catch_throw;void hipe_mode_switch_init(void){ hipe_arch_glue_init(); hipe_beam_pc_return[0] = BeamOpCode(op_hipe_trap_return); hipe_beam_pc_throw[0] = BeamOpCode(op_hipe_trap_throw); hipe_beam_pc_resume[0] = BeamOpCode(op_hipe_trap_resume); hipe_beam_pc_reschedule[0] = BeamOpCode(op_hipe_trap_reschedule); hipe_beam_catch_throw = make_catch(beam_catches_cons(hipe_beam_pc_throw, BEAM_CATCHES_NIL)); hipe_mfa_info_table_init();}void hipe_set_call_trap(Uint *bfun, void *nfun, int is_closure){ HIPE_ASSERT(bfun[-5] == 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;}static __inline__ voidhipe_push_beam_trap_frame(Process *p, Eterm reg[], unsigned arity){ /* ensure that at least 2 words are available on the BEAM stack */ if( (p->stop - 2) < p->htop ) { DPRINTF("calling gc to increase BEAM stack size"); p->fcalls -= erts_garbage_collect(p, 2, reg, arity); } p->stop -= 2; p->stop[1] = hipe_beam_catch_throw; p->stop[0] = make_cp(p->cp); ++p->catches; p->cp = hipe_beam_pc_return;}static __inline__ void hipe_pop_beam_trap_frame(Process *p){ p->cp = cp_val(p->stop[0]); --p->catches; p->stop += 2;}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 p->i = NULL; DPRINTF("cmd == %#x (%s)", cmd, code_str(cmd)); HIPE_CHECK_PCB(p); switch( cmd & 0xFF ) { case HIPE_MODE_SWITCH_CMD_RESCHEDULE: break; default: p->arity = 0; } switch( cmd & 0xFF ) { case HIPE_MODE_SWITCH_CMD_CALL: { /* BEAM calls a native code function */ unsigned arity = cmd >> 8; /* p->hipe.ncallee set in beam_emu */ if( p->cp == hipe_beam_pc_return ) { /* Native called BEAM, which now tailcalls native. */ hipe_pop_beam_trap_frame(p); result = hipe_tailcall_to_native(p, arity, reg); break; } DPRINTF("calling %#lx/%u", (long)p->hipe.ncallee, arity); result = hipe_call_to_native(p, arity, reg); break; } case HIPE_MODE_SWITCH_CMD_CALL_CLOSURE: { /* BEAM calls a native code closure */ unsigned arity = cmd >> 8; /* #formals + #fvs (closure not counted) */ Eterm fun; ErlFunThing *funp; /* drop the fvs, move the closure, correct arity */ fun = reg[arity]; HIPE_ASSERT(is_fun(fun)); funp = (ErlFunThing*)fun_val(fun); HIPE_ASSERT(funp->num_free <= arity); arity -= funp->num_free; /* arity == #formals */ reg[arity] = fun; ++arity; /* correct for having added the closure */ /* HIPE_ASSERT(p->hipe.ncallee == (void(*)(void))funp->native_address); */ /* just like a normal call from now on */ /* p->hipe.ncallee set in beam_emu */ if( p->cp == hipe_beam_pc_return ) { /* Native called BEAM, which now tailcalls native. */ hipe_pop_beam_trap_frame(p); result = hipe_tailcall_to_native(p, arity, reg); break; } DPRINTF("calling %#lx/%u", (long)p->hipe.ncallee, arity); result = hipe_call_to_native(p, arity, reg); break; } case HIPE_MODE_SWITCH_CMD_THROW: { /* BEAM just executed hipe_beam_pc_throw[] */ /* Native called BEAM, which now throws an exception back to native. */ DPRINTF("beam throws freason %#lx fvalue %#lx", p->freason, p->fvalue); hipe_pop_beam_trap_frame(p); do_throw_to_native: p->def_arg_reg[0] = exception_tag[GET_EXC_CLASS(p->freason)]; hipe_find_handler(p); result = hipe_throw_to_native(p); break; } case HIPE_MODE_SWITCH_CMD_RETURN: { /* BEAM just executed hipe_beam_pc_return[] */ /* Native called BEAM, which now returns back to native. */ /* pop trap frame off estack */ hipe_pop_beam_trap_frame(p); p->def_arg_reg[0] = reg[0]; result = hipe_return_to_native(p); break; } do_resume: case HIPE_MODE_SWITCH_CMD_RESUME: { /* BEAM just executed hipe_beam_pc_resume[] */ /* BEAM called native, which suspended. */ if( p->flags & F_TIMO ) { /* XXX: The process will immediately execute 'clear_timeout', repeating these two statements. Remove them? */ p->flags &= ~F_TIMO; JOIN_MESSAGE(p); p->def_arg_reg[0] = 0; /* make_small(0)? */ } else { p->def_arg_reg[0] = 1; /* make_small(1)? */ } result = hipe_return_to_native(p); break; } case HIPE_MODE_SWITCH_CMD_RESCHEDULE: { /* BEAM just executed hipe_beam_pc_reschedule[] */ /* Native called a BIF which failed with RESCHEDULE. Resume it. */ /* XXX: this ought to be the same as 'resume' */ DPRINTF("rescheduling to 0x%#lx/%u", p->hipe.ncallee, p->arity); result = hipe_reschedule_to_native(p, p->arity, reg); break; } default: erl_exit(1, "hipe_mode_switch: cmd %#x\r\n", cmd); } do_return_from_native:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -