hipe_arm_glue.s
来自「OTP是开放电信平台的简称」· S 代码 · 共 433 行
S
433 行
/* $Id$ */#include "hipe_arm_asm.h"#include "hipe_literals.h"#define ASM#include "hipe_mode_switch.h" .text .p2align 2/* * Enter Erlang from C. * Create a new frame on the C stack. * Save C callee-save registers in the frame. * Do not clobber the C argument registers. * Retrieve the process pointer from the C argument registers. * * Our C frame includes: * - 9*4 == 36 bytes for saving r4-r11 and lr * - 2*4 == 8 bytes for calls to hipe_bs_put_{big_integer,small_float}. * They take 5-6 parameter words: 4 in registers and 1-2 on the stack. * (They take 5 regular parameters, and an additional P parameter on SMP.) * - 4 bytes to pad the frame size to a multiple of 8 */#define ENTER_FROM_C \ stmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,lr}; \ sub sp, sp, #12; \ mov P, r0; \ RESTORE_CACHED_STATE/* * Return to the calling C function. * The return value is in r0. * * .nosave_exit saves no state * .flush_exit saves NSP and other cached P state. * .suspend_exit also saves RA. */.suspend_exit: /* save RA, so we can be resumed */ str lr, [P, #P_NRA].flush_exit: /* flush cached P state */ SAVE_CACHED_STATE.nosave_exit: /* restore callee-save registers, drop frame, return */ add sp, sp, #12 ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,pc}/* * int hipe_arm_call_to_native(Process *p); * Emulated code recursively calls native code. */ .global hipe_arm_call_to_nativehipe_arm_call_to_native: ENTER_FROM_C /* get argument registers */ LOAD_ARG_REGS /* call the target */ mov lr, pc ldr pc, [P, #P_NCALLEE]/* FALLTHROUGH * * We export this return address so that hipe_mode_switch() can discover * when native code tailcalls emulated code. * * This is where native code returns to emulated code. */ .global nbif_returnnbif_return: str r0, [P, #P_ARG0] /* save retval */ mov r0, #HIPE_MODE_SWITCH_RES_RETURN b .flush_exit/* * int hipe_arm_return_to_native(Process *p); * Emulated code returns to its native code caller. */ .global hipe_arm_return_to_nativehipe_arm_return_to_native: ENTER_FROM_C /* get return value */ ldr r0, [P, #P_ARG0] /* * Return using the current return address. * The parameters were popped at the original native-to-emulated * call (hipe_call_from_native_is_recursive), so a plain ret suffices. */ ldr pc, [P, #P_NRA]/* * int hipe_arm_tailcall_to_native(Process *p); * Emulated code tailcalls native code. */ .global hipe_arm_tailcall_to_nativehipe_arm_tailcall_to_native: ENTER_FROM_C /* get argument registers */ LOAD_ARG_REGS /* restore return address */ ldr lr, [P, #P_NRA] /* call the target */ ldr pc, [P, #P_NCALLEE]/* * int hipe_arm_throw_to_native(Process *p); * Emulated code throws an exception to its native code caller. */ .global hipe_arm_throw_to_nativehipe_arm_throw_to_native: ENTER_FROM_C /* invoke the handler */ ldr pc, [P, #P_NCALLEE] /* set by hipe_find_handler() *//* * Native code calls emulated code via a stub * which should look as follows: * * stub for f/N: * <set r8 to f's BEAM code address> * <set r0 to N> * b nbif_callemu * * XXX: Different stubs for different number of register parameters? */ .global nbif_callemunbif_callemu: str r8, [P, #P_BEAM_IP] str r0, [P, #P_ARITY] STORE_ARG_REGS mov r0, #HIPE_MODE_SWITCH_RES_CALL b .suspend_exit/* * nbif_apply */ .global nbif_applynbif_apply: STORE_ARG_REGS mov r0, #HIPE_MODE_SWITCH_RES_APPLY b .suspend_exit/* * Native code calls an emulated-mode closure via a stub defined below. * * The closure is appended as the last actual parameter, and parameters * beyond the first few passed in registers are pushed onto the stack in * left-to-right order. * Hence, the location of the closure parameter only depends on the number * of parameters in registers, not the total number of parameters. */#if NR_ARG_REGS >= 6 .global nbif_ccallemu6nbif_ccallemu6: str ARG5, [P, #P_ARG5]#if NR_ARG_REGS > 6 mov ARG5, ARG6#else ldr ARG5, [NSP, #0]#endif /*FALLTHROUGH*/#endif#if NR_ARG_REGS >= 5 .global nbif_ccallemu5nbif_ccallemu5: str ARG4, [P, #P_ARG4]#if NR_ARG_REGS > 5 mov ARG4, ARG5#else ldr ARG4, [NSP, #0]#endif /*FALLTHROUGH*/#endif#if NR_ARG_REGS >= 4 .global nbif_ccallemu4nbif_ccallemu4: str ARG3, [P, #P_ARG3]#if NR_ARG_REGS > 4 mov ARG3, ARG4#else ldr ARG3, [NSP, #0]#endif /*FALLTHROUGH*/#endif#if NR_ARG_REGS >= 3 .global nbif_ccallemu3nbif_ccallemu3: str ARG2, [P, #P_ARG2]#if NR_ARG_REGS > 3 mov ARG2, ARG3#else ldr ARG2, [NSP, #0]#endif /*FALLTHROUGH*/#endif#if NR_ARG_REGS >= 2 .global nbif_ccallemu2nbif_ccallemu2: str ARG1, [P, #P_ARG1]#if NR_ARG_REGS > 2 mov ARG1, ARG2#else ldr ARG1, [NSP, #0]#endif /*FALLTHROUGH*/#endif#if NR_ARG_REGS >= 1 .global nbif_ccallemu1nbif_ccallemu1: str ARG0, [P, #P_ARG0]#if NR_ARG_REGS > 1 mov ARG0, ARG1#else ldr ARG0, [NSP, #0]#endif /*FALLTHROUGH*/#endif .global nbif_ccallemu0nbif_ccallemu0: /* We use r1 not ARG0 here because ARG0 is not defined when NR_ARG_REGS == 0. */#if NR_ARG_REGS == 0 ldr r1, [NSP, #0] /* get the closure */#endif str r1, [P, #P_CLOSURE] /* save the closure */ mov r0, #HIPE_MODE_SWITCH_RES_CALL_CLOSURE b .suspend_exit/* * This is where native code suspends. */ .global nbif_suspend_0nbif_suspend_0: mov r0, #HIPE_MODE_SWITCH_RES_SUSPEND b .suspend_exit/* * Suspend from a receive (waiting for a message) */ .global nbif_suspend_msgnbif_suspend_msg: mov r0, #HIPE_MODE_SWITCH_RES_WAIT b .suspend_exit/* * Suspend from a receive with a timeout (waiting for a message) * if (!(p->flags & F_TIMO)) { suspend } * else { return 0; } */ .global nbif_suspend_msg_timeoutnbif_suspend_msg_timeout: ldr r1, [P, #P_FLAGS] mov r0, #HIPE_MODE_SWITCH_RES_WAIT_TIMEOUT /* this relies on F_TIMO (1<<2) fitting in a uimm16 */ tst r1, #F_TIMO beq .suspend_exit /* timeout has occurred */ mov r0, #0 mov pc, lr/* * This is the default exception handler for native code. */ .global nbif_failnbif_fail: mov r0, #HIPE_MODE_SWITCH_RES_THROW b .flush_exit /* no need to save RA */#if defined(HEAP_FRAG_ELIM_TEST) .global nbif_0_gc_after_bif .global nbif_1_gc_after_bif .global nbif_2_gc_after_bif .global nbif_3_gc_after_bifnbif_0_gc_after_bif: mov r1, #0 b .gc_after_bifnbif_1_gc_after_bif: mov r1, #1 b .gc_after_bifnbif_2_gc_after_bif: mov r1, #2 b .gc_after_bifnbif_3_gc_after_bif: mov r1, #3 /*FALLTHROUGH*/.gc_after_bif: str r1, [P, #P_NARITY] str TEMP_LR, [P, #P_NRA] str NSP, [P, #P_NSP] mov TEMP_LR, lr mov r1, r0 mov r0, P bl erts_gc_after_bif_call mov lr, TEMP_LR ldr TEMP_LR, [P, #P_NRA] mov r1, #0 str r1, [P, #P_NARITY] mov pc, lr#endif/* * We end up here when a BIF called from native signals an * exceptional condition, and RESCHEDULE cannot occur. * HP was just read from P. * NSP has not been saved in P. * TEMP_LR contains a copy of LR */ .global nbif_1_simple_exceptionnbif_1_simple_exception: mov r1, #1 b .nbif_simple_exception .global nbif_2_simple_exceptionnbif_2_simple_exception: mov r1, #2 b .nbif_simple_exception .global nbif_3_simple_exceptionnbif_3_simple_exception: mov r1, #3 /*FALLTHROUGH*/.nbif_simple_exception: ldr r0, [P, #P_FREASON].nbif_simple_exception2: cmp r0, #FREASON_TRAP beq .handle_trap /* * Find and invoke catch handler (it must exist). * HP was just read from P. * NSP has not been saved in P. * TEMP_LR should contain the current call's return address. * r1 should contain the current call's arity. */ str NSP, [P, #P_NSP] str TEMP_LR, [P, #P_NRA] str r1, [P, #P_NARITY] /* find and prepare to invoke the handler */ mov r0, P bl hipe_handle_exception /* Note: hipe_handle_exception() conses */ RESTORE_CACHED_STATE /* NSP updated by hipe_find_handler() */ /* now invoke the handler */ ldr pc, [P, #P_NCALLEE] /* set by hipe_find_handler() */ /* * A BIF failed with freason TRAP: * - the BIF stored the callee's Export* in p->def_arg_reg[3] * - the BIF stored the callee's parameters in p->def_arg_reg[0..2] * - the BIF's arity is in r1 * - the native RA was saved in TEMP_LR before the BIF call * - HP was just read from P * - NSP has not been saved in P */.handle_trap: mov r0, #HIPE_MODE_SWITCH_RES_TRAP.bif_exit: str NSP, [P, #P_NSP] str r1, [P, #P_ARITY] str TEMP_LR, [P, #P_NRA] b .nosave_exit/* * We end up here when a BIF called from native signals an * exceptional condition, and RESCHEDULE can occur. * r2 contains the address of the nbif which failed. * HP was just read from P. * NSP has not been saved in P. * TEMP_ARG0 is the first actual parameter, if NR_ARG_REGS > 0. * TEMP_ARG1 is the second actual parameter (if defined), if NR_ARG_REGS > 1. */ .global nbif_1_hairy_exceptionnbif_1_hairy_exception: mov r1, #1 b .nbif_hairy_exception .global nbif_2_hairy_exceptionnbif_2_hairy_exception: mov r1, #2 /*FALLTHROUGH*/.nbif_hairy_exception: ldr r0, [P, #P_FREASON] cmp r0, #FREASON_RESCHEDULE bne .nbif_simple_exception2 /* handle reschedule */ str r2, [P, #P_NCALLEE]#if NR_ARG_REGS == 0 mov r1, #0 /* arity unused -- args on nstack */#elif NR_ARG_REGS == 1 mov r1, #1 /* 1 even if arity is 2 */ str TEMP_ARG0, [P, #P_ARG0]#else str TEMP_ARG0, [P, #P_ARG0] str TEMP_ARG1, [P, #P_ARG1]#endif mov r0, #HIPE_MODE_SWITCH_RES_RESCHEDULE b .bif_exit/* * nbif_stack_trap_ra: trap return address for maintaining * the gray/white stack boundary */ .global nbif_stack_trap_ranbif_stack_trap_ra: /* a return address, not a function */ # This only handles a single return value. # If we have more, we need to save them in the PCB. mov TEMP_RV, r0 /* save retval */ str NSP, [P, #P_NSP] mov r0, P bl hipe_handle_stack_trap /* must not cons */ mov lr, r0 /* original RA */ mov r0, TEMP_RV /* restore retval */ mov pc, lr /* resume at original RA *//* * hipe_arm_inc_stack * Caller saved its LR in TEMP_LR (== TEMP1) before calling us. */ .global hipe_arm_inc_stackhipe_arm_inc_stack: STORE_ARG_REGS mov TEMP_ARG0, lr str NSP, [P, #P_NSP] mov r0, P # hipe_inc_nstack reads and writes NSP and NSP_LIMIT, # but does not access LR/RA, HP, or FCALLS. bl hipe_inc_nstack ldr NSP, [P, #P_NSP] LOAD_ARG_REGS # this relies on LOAD_ARG_REGS not clobbering TEMP_ARG0 mov pc, TEMP_ARG0
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?