diff options
-rw-r--r-- | erts/emulator/hipe/hipe_amd64_asm.m4 | 22 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_amd64_bifs.m4 | 3 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_amd64_glue.S | 2 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_arm_asm.m4 | 32 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_arm_bifs.m4 | 33 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_arm_glue.S | 4 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_bif_list.m4 | 47 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_gc.c | 4 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_mkliterals.c | 6 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_ppc_bifs.m4 | 36 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_process.h | 6 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_sparc_bifs.m4 | 34 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_x86_bifs.m4 | 3 |
13 files changed, 198 insertions, 34 deletions
diff --git a/erts/emulator/hipe/hipe_amd64_asm.m4 b/erts/emulator/hipe/hipe_amd64_asm.m4 index 2c0fbbee2d..409fd0ef89 100644 --- a/erts/emulator/hipe/hipe_amd64_asm.m4 +++ b/erts/emulator/hipe/hipe_amd64_asm.m4 @@ -121,6 +121,22 @@ define(NSP,%rsp)dnl /* + * Debugging macros + * + * Keeps track of whether context has been saved in the debug build, allowing us + * to detect when the garbage collector is called when it shouldn't. + */ +`#ifdef DEBUG +# define SET_GC_UNSAFE \ + movq $1, P_GCUNSAFE(P) +# define SET_GC_SAFE \ + movq $0, P_GCUNSAFE(P) +#else +# define SET_GC_UNSAFE +# define SET_GC_SAFE +#endif' + +/* * Context switching macros. */ `#define SWITCH_C_TO_ERLANG_QUICK \ @@ -133,12 +149,14 @@ define(NSP,%rsp)dnl `#define SAVE_CACHED_STATE \ SAVE_HP; \ - SAVE_FCALLS' + SAVE_FCALLS; \ + SET_GC_SAFE' `#define RESTORE_CACHED_STATE \ RESTORE_HP; \ RESTORE_HEAP_LIMIT; \ - RESTORE_FCALLS' + RESTORE_FCALLS; \ + SET_GC_UNSAFE' `#define SWITCH_C_TO_ERLANG \ RESTORE_CACHED_STATE; \ diff --git a/erts/emulator/hipe/hipe_amd64_bifs.m4 b/erts/emulator/hipe/hipe_amd64_bifs.m4 index 9cf3bf74fd..21739726bb 100644 --- a/erts/emulator/hipe/hipe_amd64_bifs.m4 +++ b/erts/emulator/hipe/hipe_amd64_bifs.m4 @@ -600,10 +600,11 @@ noproc_primop_interface_0(nbif_handle_fp_exception, erts_restore_fpu) define(gc_bif_interface_0,`nofail_primop_interface_0($1, $2)') /* - * Implement gc_bif_interface_N as standard_bif_interface_N (N=1,2). + * Implement gc_bif_interface_N as standard_bif_interface_N (N=1,2,3). */ define(gc_bif_interface_1,`standard_bif_interface_1($1, $2)') define(gc_bif_interface_2,`standard_bif_interface_2($1, $2)') +define(gc_bif_interface_3,`standard_bif_interface_3($1, $2)') /* * Implement gc_nofail_primop_interface_1 as nofail_primop_interface_1. diff --git a/erts/emulator/hipe/hipe_amd64_glue.S b/erts/emulator/hipe/hipe_amd64_glue.S index b37ed3c68a..f3404888d5 100644 --- a/erts/emulator/hipe/hipe_amd64_glue.S +++ b/erts/emulator/hipe/hipe_amd64_glue.S @@ -94,6 +94,7 @@ ASYM(nbif_return): .nosave_exit: /* switch to C stack */ SWITCH_ERLANG_TO_C_QUICK + SET_GC_SAFE /* restore C callee-save registers, drop frame, return */ movq (%rsp), %rbp # kills P movq 8(%rsp), %rbx @@ -398,6 +399,7 @@ nbif_4_simple_exception: movl %eax, P_NARITY(P) # Note: narity is a 32-bit field /* find and prepare to invoke the handler */ SWITCH_ERLANG_TO_C_QUICK # The cached state is clean and need not be saved. + SET_GC_SAFE movq P, %rdi call CSYM(hipe_handle_exception) # Note: hipe_handle_exception() conses SWITCH_C_TO_ERLANG # %rsp updated by hipe_find_handler() diff --git a/erts/emulator/hipe/hipe_arm_asm.m4 b/erts/emulator/hipe/hipe_arm_asm.m4 index ae9ec752bb..68a6faa70b 100644 --- a/erts/emulator/hipe/hipe_arm_asm.m4 +++ b/erts/emulator/hipe/hipe_arm_asm.m4 @@ -48,6 +48,24 @@ define(NR_ARG_REGS,3)dnl admissible values are 0 to 6, inclusive `#define TEMP_LR r8' /* + * Debugging macros + * + * Keeps track of whether context has been saved in the debug build, allowing us + * to detect when the garbage collector is called when it shouldn't. + */ +`#ifdef DEBUG +# define SET_GC_UNSAFE(SCRATCH) \ + mov SCRATCH, #1; \ + str SCRATCH, [P, #P_GCUNSAFE] +# define SET_GC_SAFE(SCRATCH) \ + mov SCRATCH, #0; \ + str SCRATCH, [P, #P_GCUNSAFE] +#else +# define SET_GC_UNSAFE(SCRATCH) +# define SET_GC_SAFE(SCRATCH) +#endif' + +/* * Context switching macros. * * RESTORE_CONTEXT and RESTORE_CONTEXT_QUICK do not affect @@ -59,12 +77,14 @@ define(NR_ARG_REGS,3)dnl admissible values are 0 to 6, inclusive `#define RESTORE_CONTEXT_QUICK \ mov lr, TEMP_LR' -`#define SAVE_CACHED_STATE \ - str HP, [P, #P_HP]; \ - str NSP, [P, #P_NSP]' +`#define SAVE_CACHED_STATE \ + str HP, [P, #P_HP]; \ + str NSP, [P, #P_NSP]; \ + SET_GC_SAFE(HP)' -`#define RESTORE_CACHED_STATE \ - ldr HP, [P, #P_HP]; \ +`#define RESTORE_CACHED_STATE \ + SET_GC_UNSAFE(HP); \ + ldr HP, [P, #P_HP]; \ ldr NSP, [P, #P_NSP]' `#define SAVE_CONTEXT_BIF \ @@ -75,12 +95,14 @@ define(NR_ARG_REGS,3)dnl admissible values are 0 to 6, inclusive ldr HP, [P, #P_HP]' `#define SAVE_CONTEXT_GC \ + SET_GC_SAFE(TEMP_LR); \ mov TEMP_LR, lr; \ str lr, [P, #P_NRA]; \ str NSP, [P, #P_NSP]; \ str HP, [P, #P_HP]' `#define RESTORE_CONTEXT_GC \ + SET_GC_UNSAFE(HP); \ ldr HP, [P, #P_HP]' /* diff --git a/erts/emulator/hipe/hipe_arm_bifs.m4 b/erts/emulator/hipe/hipe_arm_bifs.m4 index d9c9952dbf..d7a2fec04a 100644 --- a/erts/emulator/hipe/hipe_arm_bifs.m4 +++ b/erts/emulator/hipe/hipe_arm_bifs.m4 @@ -198,8 +198,9 @@ $1: * gc_bif_interface_0(nbif_name, cbif_name) * gc_bif_interface_1(nbif_name, cbif_name) * gc_bif_interface_2(nbif_name, cbif_name) + * gc_bif_interface_3(nbif_name, cbif_name) * - * Generate native interface for a BIF with 0-2 parameters and + * Generate native interface for a BIF with 0-3 parameters and * standard failure mode. * The BIF may do a GC. */ @@ -279,6 +280,36 @@ $1: .type $1, %function #endif') +define(gc_bif_interface_3, +` +#ifndef HAVE_$1 +#`define' HAVE_$1 + .global $1 +$1: + /* Set up C argument registers. */ + mov r0, P + NBIF_ARG(r1,3,0) + NBIF_ARG(r2,3,1) + NBIF_ARG(r3,3,2) + + /* Save caller-save registers and call the C function. */ + SAVE_CONTEXT_GC + str r1, [r0, #P_ARG0] /* Store BIF__ARGS in def_arg_reg[] */ + str r2, [r0, #P_ARG1] + str r3, [r0, #P_ARG2] + add r1, r0, #P_ARG0 + CALL_BIF($2) + TEST_GOT_MBUF(3) + + /* Restore registers. Check for exception. */ + cmp r0, #THE_NON_VALUE + RESTORE_CONTEXT_GC + beq nbif_3_simple_exception + NBIF_RET(3) + .size $1, .-$1 + .type $1, %function +#endif') + /* * gc_nofail_primop_interface_1(nbif_name, cbif_name) * diff --git a/erts/emulator/hipe/hipe_arm_glue.S b/erts/emulator/hipe/hipe_arm_glue.S index 49ffa8b1d8..5b7f8ad52d 100644 --- a/erts/emulator/hipe/hipe_arm_glue.S +++ b/erts/emulator/hipe/hipe_arm_glue.S @@ -342,6 +342,7 @@ nbif_4_gc_after_bif: str r1, [P, #P_NARITY] str TEMP_LR, [P, #P_NRA] str NSP, [P, #P_NSP] + SET_GC_SAFE(TEMP_LR) mov TEMP_LR, lr mov r3, #0 /* Pass 0 in arity */ mov r2, #0 /* Pass NULL in regs */ @@ -349,6 +350,7 @@ nbif_4_gc_after_bif: mov r0, P bl erts_gc_after_bif_call mov lr, TEMP_LR + SET_GC_UNSAFE(TEMP_LR) ldr TEMP_LR, [P, #P_NRA] mov r1, #0 str r1, [P, #P_NARITY] @@ -404,6 +406,7 @@ nbif_4_simple_exception: str NSP, [P, #P_NSP] str TEMP_LR, [P, #P_NRA] str r1, [P, #P_NARITY] + SET_GC_SAFE(r0) /* find and prepare to invoke the handler */ mov r0, P bl hipe_handle_exception /* Note: hipe_handle_exception() conses */ @@ -423,6 +426,7 @@ nbif_4_simple_exception: str NSP, [P, #P_NSP] str r1, [P, #P_NARITY] str TEMP_LR, [P, #P_NRA] + SET_GC_SAFE(NSP) b .nosave_exit /* diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4 index 29095a5389..dcf3447af9 100644 --- a/erts/emulator/hipe/hipe_bif_list.m4 +++ b/erts/emulator/hipe/hipe_bif_list.m4 @@ -96,6 +96,7 @@ * gc_bif_interface_0(nbif_name, cbif_name) * gc_bif_interface_1(nbif_name, cbif_name) * gc_bif_interface_2(nbif_name, cbif_name) + * gc_bif_interface_3(nbif_name, cbif_name) * * A BIF which may do a GC or walk the native stack. * May read NSP, NSP_LIMIT, NRA, HP, HP_LIMIT, and FCALLS. @@ -263,32 +264,34 @@ noproc_primop_interface_1(nbif_atomic_inc, hipe_atomic_inc) ',)dnl /* - * Standard BIFs. - * BIF_LIST(ModuleAtom,FunctionAtom,Arity,CFun,Index) + * BIFs that disable GC while trapping are called via a wrapper + * to reserve stack space for the "trap frame". + * They occasionally need to call the garbage collector in order to make room + * for the trap frame on the BEAM stack. */ +gc_bif_interface_1(nbif_term_to_binary_1, hipe_wrapper_term_to_binary_1) +gc_bif_interface_2(nbif_term_to_binary_2, hipe_wrapper_term_to_binary_2) +gc_bif_interface_1(nbif_binary_to_term_1, hipe_wrapper_binary_to_term_1) +gc_bif_interface_2(nbif_binary_to_term_2, hipe_wrapper_binary_to_term_2) +gc_bif_interface_1(nbif_binary_to_list_1, hipe_wrapper_binary_to_list_1) +gc_bif_interface_3(nbif_binary_to_list_3, hipe_wrapper_binary_to_list_3) +gc_bif_interface_1(nbif_bitstring_to_list_1, hipe_wrapper_bitstring_to_list_1) +gc_bif_interface_1(nbif_list_to_binary_1, hipe_wrapper_list_to_binary_1) +gc_bif_interface_1(nbif_iolist_to_binary_1, hipe_wrapper_iolist_to_binary_1) +gc_bif_interface_1(nbif_binary_list_to_bin_1, hipe_wrapper_binary_list_to_bin_1) +gc_bif_interface_1(nbif_list_to_bitstring_1, hipe_wrapper_list_to_bitstring_1) +gc_bif_interface_2(nbif_send_2, hipe_wrapper_send_2) +gc_bif_interface_3(nbif_send_3, hipe_wrapper_send_3) +gc_bif_interface_2(nbif_ebif_bang_2, hipe_wrapper_ebif_bang_2) +gc_bif_interface_2(nbif_maps_merge_2, hipe_wrapper_maps_merge_2) -/* BIFs that disable GC while trapping are called via a wrapper - * to reserve stack space for the "trap frame". + +/* + * Standard BIFs. + * BIF_LIST(ModuleAtom,FunctionAtom,Arity,CFun,Index) */ -define(CFUN,`ifelse( -$1, term_to_binary_1, hipe_wrapper_$1, -$1, term_to_binary_2, hipe_wrapper_$1, -$1, binary_to_term_1, hipe_wrapper_$1, -$1, binary_to_term_2, hipe_wrapper_$1, -$1, binary_to_list_1, hipe_wrapper_$1, -$1, binary_to_list_3, hipe_wrapper_$1, -$1, bitstring_to_list_1, hipe_wrapper_$1, -$1, list_to_binary_1, hipe_wrapper_$1, -$1, iolist_to_binary_1, hipe_wrapper_$1, -$1, binary_list_to_bin_1, hipe_wrapper_$1, -$1, list_to_bitstring_1, hipe_wrapper_$1, -$1, send_2, hipe_wrapper_$1, -$1, send_3, hipe_wrapper_$1, -$1, ebif_bang_2, hipe_wrapper_$1, -$1, maps_merge_2, hipe_wrapper_$1, -$1)') -define(BIF_LIST,`standard_bif_interface_$3(nbif_$4, CFUN($4))') +define(BIF_LIST,`standard_bif_interface_$3(nbif_$4, $4)') include(TARGET/`erl_bif_list.h') /* diff --git a/erts/emulator/hipe/hipe_gc.c b/erts/emulator/hipe/hipe_gc.c index d0619a0609..566c65882e 100644 --- a/erts/emulator/hipe/hipe_gc.c +++ b/erts/emulator/hipe/hipe_gc.c @@ -46,6 +46,8 @@ Eterm *fullsweep_nstack(Process *p, Eterm *n_htop) /* arch-specific nstack walk state */ struct nstack_walk_state walk_state; + ASSERT(!p->hipe.gc_is_unsafe); + if (!p->hipe.nstack) { ASSERT(!p->hipe.nsp && !p->hipe.nstend); return n_htop; @@ -136,6 +138,8 @@ void gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop) char *mature; Uint mature_size; + ASSERT(!p->hipe.gc_is_unsafe); + if (!p->hipe.nstack) { ASSERT(!p->hipe.nsp && !p->hipe.nstend); return; diff --git a/erts/emulator/hipe/hipe_mkliterals.c b/erts/emulator/hipe/hipe_mkliterals.c index 0d3493ec6c..b9d4226705 100644 --- a/erts/emulator/hipe/hipe_mkliterals.c +++ b/erts/emulator/hipe/hipe_mkliterals.c @@ -525,6 +525,12 @@ static const struct rts_param rts_params[] = { { 51, "P_CALLEE_EXP", 1, offsetof(struct process, hipe.u.callee_exp) }, { 52, "THE_NON_VALUE", 1, (int)THE_NON_VALUE }, + + { 53, "P_GCUNSAFE", +#ifdef DEBUG + 1, offsetof(struct process, hipe.gc_is_unsafe) +#endif + }, }; #define NR_PARAMS ARRAY_SIZE(rts_params) diff --git a/erts/emulator/hipe/hipe_ppc_bifs.m4 b/erts/emulator/hipe/hipe_ppc_bifs.m4 index 57b4208bee..b540562185 100644 --- a/erts/emulator/hipe/hipe_ppc_bifs.m4 +++ b/erts/emulator/hipe/hipe_ppc_bifs.m4 @@ -212,8 +212,9 @@ ASYM($1): * gc_bif_interface_0(nbif_name, cbif_name) * gc_bif_interface_1(nbif_name, cbif_name) * gc_bif_interface_2(nbif_name, cbif_name) + * gc_bif_interface_3(nbif_name, cbif_name) * - * Generate native interface for a BIF with 0-2 parameters and + * Generate native interface for a BIF with 0-3 parameters and * standard failure mode. * The BIF may do a GC. */ @@ -300,6 +301,39 @@ ASYM($1): TYPE_FUNCTION(ASYM($1)) #endif') +define(gc_bif_interface_3, +` +#ifndef HAVE_$1 +#`define' HAVE_$1 + GLOBAL(ASYM($1)) +ASYM($1): + /* Set up C argument registers. */ + mr r3, P + NBIF_ARG(r4,3,0) + NBIF_ARG(r5,3,1) + NBIF_ARG(r6,3,2) + + /* Save caller-save registers and call the C function. */ + SAVE_CONTEXT_GC + STORE r4, P_ARG0(r3) /* Store BIF__ARGS in def_arg_reg[] */ + STORE r5, P_ARG1(r3) + STORE r6, P_ARG2(r3) + addi r4, r3, P_ARG0 + CALL_BIF($2) + TEST_GOT_MBUF + + /* Restore registers. Check for exception. */ + CMPI r3, THE_NON_VALUE + RESTORE_CONTEXT_GC + beq- 1f + NBIF_RET(3) +1: /* workaround for bc:s small offset operand */ + b CSYM(nbif_3_simple_exception) + HANDLE_GOT_MBUF(3) + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) +#endif') + /* * gc_nofail_primop_interface_1(nbif_name, cbif_name) * diff --git a/erts/emulator/hipe/hipe_process.h b/erts/emulator/hipe/hipe_process.h index 21c4239753..a8d5972280 100644 --- a/erts/emulator/hipe/hipe_process.h +++ b/erts/emulator/hipe/hipe_process.h @@ -52,6 +52,9 @@ struct hipe_process_state { #if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP) void (*bif_callee)(void); /* When calling BIF's via debug wrapper */ #endif +#ifdef DEBUG + UWord gc_is_unsafe; /* Nonzero when GC-required state is on stack */ +#endif }; extern void hipe_arch_print_pcb(struct hipe_process_state *p); @@ -68,6 +71,9 @@ static __inline__ void hipe_init_process(struct hipe_process_state *p) p->nra = NULL; #endif p->narity = 0; +#ifdef DEBUG + p->gc_is_unsafe = 0; +#endif } static __inline__ void hipe_delete_process(struct hipe_process_state *p) diff --git a/erts/emulator/hipe/hipe_sparc_bifs.m4 b/erts/emulator/hipe/hipe_sparc_bifs.m4 index 2e886ec1d1..1389beaa61 100644 --- a/erts/emulator/hipe/hipe_sparc_bifs.m4 +++ b/erts/emulator/hipe/hipe_sparc_bifs.m4 @@ -210,8 +210,9 @@ $1: * gc_bif_interface_0(nbif_name, cbif_name) * gc_bif_interface_1(nbif_name, cbif_name) * gc_bif_interface_2(nbif_name, cbif_name) + * gc_bif_interface_3(nbif_name, cbif_name) * - * Generate native interface for a BIF with 0-2 parameters and + * Generate native interface for a BIF with 0-3 parameters and * standard failure mode. * The BIF may do a GC. */ @@ -295,6 +296,37 @@ $1: .type $1, #function #endif') +define(gc_bif_interface_3, +` +#ifndef HAVE_$1 +#`define' HAVE_$1 + .global $1 +$1: + /* Set up C argument registers. */ + mov P, %o0 + NBIF_ARG(%o1,3,0) + NBIF_ARG(%o2,3,1) + NBIF_ARG(%o3,3,2) + + /* Save caller-save registers and call the C function. */ + SAVE_CONTEXT_GC + st %o1, [%o0+P_ARG0] ! Store BIF__ARGS in def_arg_reg + st %o2, [%o0+P_ARG1] + st %o3, [%o0+P_ARG2] + add %o0, P_ARG0, %o1 + CALL_BIF($2) + nop + TEST_GOT_MBUF + + /* Restore registers. Check for exception. */ + TEST_GOT_EXN(3) + RESTORE_CONTEXT_GC + NBIF_RET(3) + HANDLE_GOT_MBUF(3) + .size $1, .-$1 + .type $1, #function +#endif') + /* * gc_nofail_primop_interface_1(nbif_name, cbif_name) * diff --git a/erts/emulator/hipe/hipe_x86_bifs.m4 b/erts/emulator/hipe/hipe_x86_bifs.m4 index b8ac5046d5..c0c149733c 100644 --- a/erts/emulator/hipe/hipe_x86_bifs.m4 +++ b/erts/emulator/hipe/hipe_x86_bifs.m4 @@ -671,10 +671,11 @@ noproc_primop_interface_0(nbif_handle_fp_exception, erts_restore_fpu) define(gc_bif_interface_0,`nofail_primop_interface_0($1, $2)') /* - * Implement gc_bif_interface_N as standard_bif_interface_N (N=1,2). + * Implement gc_bif_interface_N as standard_bif_interface_N (N=1,2,3). */ define(gc_bif_interface_1,`standard_bif_interface_1($1, $2)') define(gc_bif_interface_2,`standard_bif_interface_2($1, $2)') +define(gc_bif_interface_3,`standard_bif_interface_3($1, $2)') /* * Implement gc_nofail_primop_interface_1 as nofail_primop_interface_1. |