diff options
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r-- | erts/emulator/beam/atom.names | 1 | ||||
-rw-r--r-- | erts/emulator/beam/bif.c | 14 | ||||
-rw-r--r-- | erts/emulator/beam/bif_instrs.tab | 81 | ||||
-rw-r--r-- | erts/emulator/beam/big.c | 7 | ||||
-rw-r--r-- | erts/emulator/beam/erl_bif_atomics.c | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_bif_guard.c | 122 | ||||
-rw-r--r-- | erts/emulator/beam/erl_db_util.c | 23 | ||||
-rw-r--r-- | erts/emulator/beam/erl_gc.c | 26 | ||||
-rw-r--r-- | erts/emulator/beam/erl_init.c | 1 | ||||
-rw-r--r-- | erts/emulator/beam/erl_proc_sig_queue.c | 1 | ||||
-rw-r--r-- | erts/emulator/beam/erl_proc_sig_queue.h | 3 | ||||
-rw-r--r-- | erts/emulator/beam/erl_vm.h | 4 | ||||
-rw-r--r-- | erts/emulator/beam/global.h | 5 | ||||
-rw-r--r-- | erts/emulator/beam/instrs.tab | 3 | ||||
-rw-r--r-- | erts/emulator/beam/ops.tab | 11 |
15 files changed, 254 insertions, 50 deletions
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 3f7aa0983c..f81082a698 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -546,6 +546,7 @@ atom reload atom rem atom report_errors atom reset +atom reset_seq_trace atom restart atom return_from atom return_to diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 4741d7451d..764298bac8 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -4485,11 +4485,12 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) ERTS_TRACER_CLEAR(&old_seq_tracer); BIF_RET(ret); - } else if (BIF_ARG_1 == make_small(1)) { + } else if (BIF_ARG_1 == am_reset_seq_trace) { int i, max; - erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_thr_progress_block(); + erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_thr_progress_block(); + max = erts_ptab_max(&erts_proc); for (i = 0; i < max; i++) { Process *p = erts_pix2proc(i); @@ -4501,13 +4502,14 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) #endif p->seq_trace_clock = 0; p->seq_trace_lastcnt = 0; - + erts_proc_lock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ); erts_proc_sig_clear_seq_trace_tokens(p); + erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ); } } - erts_thr_progress_unblock(); - erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_thr_progress_unblock(); + erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); BIF_RET(am_true); } else if (BIF_ARG_1 == am_scheduler_wall_time) { diff --git a/erts/emulator/beam/bif_instrs.tab b/erts/emulator/beam/bif_instrs.tab index 99abe662d5..418bbe2b23 100644 --- a/erts/emulator/beam/bif_instrs.tab +++ b/erts/emulator/beam/bif_instrs.tab @@ -128,6 +128,87 @@ i_bif_body.call(Bif, Dst) { } // +// length/1 is the only guard BIF that does not execute in constant +// time. Here follows special instructions to allow the calculation of +// the list length to be broken in several chunks to avoid hogging +// the scheduler for a long time. +// + +i_length_setup(Live, Src) { + Uint live = $Live; + Eterm src = $Src; + + reg[live] = src; + reg[live+1] = make_small(0); + reg[live+2] = src; + + /* This instruction is always followed by i_length */ + SET_I($NEXT_INSTRUCTION); + goto i_length_start__; + //| -no_next +} + +// +// This instruction can be executed one or more times. When entering +// this instruction, the X registers have the following contents: +// +// reg[live+0] The remainder of the list. +// reg[live+1] The length so far (tagged integer). +// reg[live+2] The original list. Only used if an error is generated +// (if the final tail of the list is not []). +// + +i_length := i_length.start.execute; + +i_length.start() { + i_length_start__: + ; +} + +i_length.execute(Fail, Live, Dst) { + Eterm result; + Uint live; + + ERTS_DBG_CHK_REDS(c_p, FCALLS); + c_p->fcalls = FCALLS; + PROCESS_MAIN_CHK_LOCKS(c_p); + ASSERT(!ERTS_PROC_IS_EXITING(c_p)); + ERTS_CHK_MBUF_SZ(c_p); + DEBUG_SWAPOUT; + + live = $Live; + result = erts_trapping_length_1(c_p, reg+live); + + DEBUG_SWAPIN; + ERTS_CHK_MBUF_SZ(c_p); + ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result)); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + PROCESS_MAIN_CHK_LOCKS(c_p); + ERTS_HOLE_CHECK(c_p); + FCALLS = c_p->fcalls; + ERTS_DBG_CHK_REDS(c_p, FCALLS); + if (ERTS_LIKELY(is_value(result))) { + /* Successful calculation of the list length. */ + $REFRESH_GEN_DEST(); + $Dst = result; + $NEXT0(); + } else if (c_p->freason == TRAP) { + /* + * Good so far, but there is more work to do. Yield. + */ + $SET_CP_I_ABS(I); + SWAPOUT; + c_p->arity = live + 3; + c_p->current = NULL; + goto context_switch3; + } else { + /* Error. */ + $BIF_ERROR_ARITY_1($Fail, BIF_length_1, reg[live+2]); + } + //| -no_next +} + +// // The most general BIF call. The BIF may build any amount of data // on the heap. The result is always returned in r(0). // diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c index dac9574fa5..7e0be2a2a7 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -1157,8 +1157,11 @@ static dsize_t I_band(ErtsDigit* x, dsize_t xl, short xsgn, *r++ = ~c1 & ~c2; x++; y++; } - while(xl--) - *r++ = ~*x++; + while(xl--) { + DSUBb(*x,0,b1,c1); + *r++ = ~c1; + x++; + } } } return I_btrail(r0, r, sign); diff --git a/erts/emulator/beam/erl_bif_atomics.c b/erts/emulator/beam/erl_bif_atomics.c index 092dbb3bd3..029831bd95 100644 --- a/erts/emulator/beam/erl_bif_atomics.c +++ b/erts/emulator/beam/erl_bif_atomics.c @@ -133,7 +133,7 @@ static ERTS_INLINE Eterm bld_atomic(Process* proc, AtomicsRef* p, if ((Uint64)val <= MAX_SMALL) return make_small((Sint) val); else { - Uint hsz = ERTS_UINT64_HEAP_SIZE(val); + Uint hsz = ERTS_UINT64_HEAP_SIZE((Uint64)val); Eterm* hp = HAlloc(proc, hsz); return erts_uint64_to_big(val, &hp); } diff --git a/erts/emulator/beam/erl_bif_guard.c b/erts/emulator/beam/erl_bif_guard.c index 84783e71a0..c921b66a7e 100644 --- a/erts/emulator/beam/erl_bif_guard.c +++ b/erts/emulator/beam/erl_bif_guard.c @@ -42,6 +42,15 @@ #include "erl_map.h" static Eterm double_to_integer(Process* p, double x); +static BIF_RETTYPE erlang_length_trap(BIF_ALIST_3); +static Export erlang_length_export; + +void erts_init_bif_guard(void) +{ + erts_init_trap_export(&erlang_length_export, + am_erlang, am_length, 3, + &erlang_length_trap); +} BIF_RETTYPE abs_1(BIF_ALIST_1) { @@ -192,26 +201,113 @@ BIF_RETTYPE round_1(BIF_ALIST_1) BIF_RET(res); } +/* + * This version of length/1 is called from native code and apply/3. + */ + BIF_RETTYPE length_1(BIF_ALIST_1) { + Eterm args[3]; + + /* + * Arrange argument registers the way expected by + * erts_trapping_length_1(). We save the original argument in + * args[2] in case an error should signaled. + */ + + args[0] = BIF_ARG_1; + args[1] = make_small(0); + args[2] = BIF_ARG_1; + return erlang_length_trap(BIF_P, args, A__I); +} + +static BIF_RETTYPE erlang_length_trap(BIF_ALIST_3) +{ + Eterm res; + + res = erts_trapping_length_1(BIF_P, BIF__ARGS); + if (is_value(res)) { /* Success. */ + BIF_RET(res); + } else { /* Trap or error. */ + if (BIF_P->freason == TRAP) { + /* + * The available reductions were exceeded. Trap. + */ + BIF_TRAP3(&erlang_length_export, BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + } else { + /* + * Signal an error. The original argument was tucked away in BIF_ARG_3. + */ + ERTS_BIF_ERROR_TRAPPED1(BIF_P, BIF_P->freason, + bif_export[BIF_length_1], BIF_ARG_3); + } + } +} + +/* + * Trappable helper function for calculating length/1. + * + * When calling this function, entries in args[] should be set up as + * follows: + * + * args[0] = List to calculate length for. + * args[1] = Length accumulator (tagged integer). + * + * If the return value is a tagged integer, the length was calculated + * successfully. + * + * Otherwise, if return value is THE_NON_VALUE and p->freason is TRAP, + * the available reductions were exceeded and this function must be called + * again after rescheduling. args[0] and args[1] have been updated to + * contain the next part of the list and length so far, respectively. + * + * Otherwise, if return value is THE_NON_VALUE, the list did not end + * in an empty list (and p->freason is BADARG). + */ + +Eterm erts_trapping_length_1(Process* p, Eterm* args) +{ Eterm list; Uint i; - - if (is_nil(BIF_ARG_1)) - BIF_RET(SMALL_ZERO); - if (is_not_list(BIF_ARG_1)) { - BIF_ERROR(BIF_P, BADARG); - } - list = BIF_ARG_1; - i = 0; - while (is_list(list)) { - i++; + Uint max_iter; + Uint saved_max_iter; + +#if defined(DEBUG) || defined(VALGRIND) + max_iter = 50; +#else + max_iter = ERTS_BIF_REDS_LEFT(p) * 16; +#endif + saved_max_iter = max_iter; + ASSERT(max_iter > 0); + + list = args[0]; + i = unsigned_val(args[1]); + while (is_list(list) && max_iter != 0) { list = CDR(list_val(list)); + i++, max_iter--; } - if (is_not_nil(list)) { - BIF_ERROR(BIF_P, BADARG); + + if (is_list(list)) { + /* + * We have exceeded the alloted number of iterations. + * Save the result so far and signal a trap. + */ + args[0] = list; + args[1] = make_small(i); + p->freason = TRAP; + BUMP_ALL_REDS(p); + return THE_NON_VALUE; + } else if (is_not_nil(list)) { + /* Error. Should be NIL. */ + BIF_ERROR(p, BADARG); } - BIF_RET(make_small(i)); + + /* + * We reached the end of the list successfully. Bump reductions + * and return result. + */ + BUMP_REDS(p, saved_max_iter / 16); + return make_small(i); } /* returns the size of a tuple or a binary */ diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index a78623f490..957762d4b0 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -497,6 +497,7 @@ static erts_atomic32_t trace_control_word; /* This needs to be here, before the bif table... */ static Eterm db_set_trace_control_word_fake_1(BIF_ALIST_1); +static Eterm db_length_1(BIF_ALIST_1); /* ** The table of callable bif's, i e guard bif's and @@ -603,7 +604,7 @@ static DMCGuardBif guard_tab[] = }, { am_length, - &length_1, + &db_length_1, 1, DBIF_ALL }, @@ -971,6 +972,26 @@ BIF_RETTYPE db_set_trace_control_word_1(BIF_ALIST_1) BIF_RET(db_set_trace_control_word(BIF_P, BIF_ARG_1)); } +/* + * Implementation of length/1 for match specs (non-trapping). + */ +static Eterm db_length_1(BIF_ALIST_1) +{ + Eterm list; + Uint i; + + list = BIF_ARG_1; + i = 0; + while (is_list(list)) { + i++; + list = CDR(list_val(list)); + } + if (is_not_nil(list)) { + BIF_ERROR(BIF_P, BADARG); + } + BIF_RET(make_small(i)); +} + static Eterm db_set_trace_control_word_fake_1(BIF_ALIST_1) { Process *p = BIF_P; diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index d5dfb096b1..3a50b294d1 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -2438,27 +2438,9 @@ erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap, cpy_words: ASSERT(sz >= cpy_sz); sz -= cpy_sz; - while (cpy_sz >= 8) { - cpy_sz -= 8; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - } - switch (cpy_sz) { - case 7: *hp++ = *fhp++; - case 6: *hp++ = *fhp++; - case 5: *hp++ = *fhp++; - case 4: *hp++ = *fhp++; - case 3: *hp++ = *fhp++; - case 2: *hp++ = *fhp++; - case 1: *hp++ = *fhp++; - default: break; - } + sys_memcpy(hp, fhp, cpy_sz * sizeof(Eterm)); + hp += cpy_sz; + fhp += cpy_sz; if (oh) { /* Add to offheap list */ oh->next = off_heap->first; @@ -2477,7 +2459,7 @@ erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap, *hpp = hp; for (i = 0; i < nrefs; i++) { - if (is_not_immed(refs[i]) && !erts_is_literal(refs[i],boxed_val(refs[i]))) + if (is_not_immed(refs[i]) && !erts_is_literal(refs[i],ptr_val(refs[i]))) refs[i] = offset_ptr(refs[i], offs); } bp->off_heap.first = NULL; diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 08c9125840..2b19d2cfd3 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -353,6 +353,7 @@ erl_init(int ncpu, erts_init_bif(); erts_init_bif_chksum(); erts_init_bif_binary(); + erts_init_bif_guard(); erts_init_bif_persistent_term(); erts_init_bif_re(); erts_init_unicode(); /* after RE to get access to PCRE unicode */ diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c index f343e984f7..18418a76e1 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.c +++ b/erts/emulator/beam/erl_proc_sig_queue.c @@ -3812,7 +3812,6 @@ clear_seq_trace_token(ErtsMessage *sig) void erts_proc_sig_clear_seq_trace_tokens(Process *c_p) { - ASSERT(erts_thr_progress_is_blocking()); erts_proc_sig_fetch(c_p); ERTS_FOREACH_SIG_PRIVQS(c_p, sig, clear_seq_trace_token(sig)); } diff --git a/erts/emulator/beam/erl_proc_sig_queue.h b/erts/emulator/beam/erl_proc_sig_queue.h index 3fc2d06b2d..6b065a7add 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.h +++ b/erts/emulator/beam/erl_proc_sig_queue.h @@ -989,8 +989,7 @@ erts_proc_sig_fetch(Process *proc) Sint res = 0; ErtsSignal *sig; - ERTS_LC_ASSERT(erts_thr_progress_is_blocking() - || ERTS_PROC_IS_EXITING(proc) + ERTS_LC_ASSERT(ERTS_PROC_IS_EXITING(proc) || ((erts_proc_lc_my_proc_locks(proc) & (ERTS_PROC_LOCK_MAIN | ERTS_PROC_LOCK_MSGQ)) diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h index fd46a804d3..35eae18394 100644 --- a/erts/emulator/beam/erl_vm.h +++ b/erts/emulator/beam/erl_vm.h @@ -41,8 +41,8 @@ #define MAX_REG 1024 /* Max number of x(N) registers used */ /* - * The new arithmetic operations need some extra X registers in the register array. - * so does the gc_bif's (i_gc_bif3 need 3 extra). + * The new trapping length/1 implementation need 3 extra registers in the + * register array. */ #define ERTS_X_REGS_ALLOCATED (MAX_REG+3) diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 322981ca1d..77b5a3ca05 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -891,6 +891,11 @@ void erts_init_bif(void); Eterm erl_send(Process *p, Eterm to, Eterm msg); int erts_set_group_leader(Process *proc, Eterm new_gl); +/* erl_bif_guard.c */ + +void erts_init_bif_guard(void); +Eterm erts_trapping_length_1(Process* p, Eterm* args); + /* erl_bif_op.c */ Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2); diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab index da1dd3dc45..df60e889f3 100644 --- a/erts/emulator/beam/instrs.tab +++ b/erts/emulator/beam/instrs.tab @@ -238,6 +238,7 @@ HANDLE_APPLY_FUN_ERROR() { } DISPATCH_FUN(I) { + //| -no_next SET_I($I); Dispatchfun(); } @@ -299,6 +300,7 @@ i_call_fun_last(Fun, Deallocate) { } return() { + //| -no_next SET_I(c_p->cp); DTRACE_RETURN_FROM_PC(c_p); @@ -951,6 +953,7 @@ build_stacktrace() { } raw_raise() { + //| -no_prefetch Eterm class = x(0); Eterm value = x(1); Eterm stacktrace = x(2); diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index c657e9a1f9..ee99c9e563 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -1588,6 +1588,17 @@ bif1 Fail u$bif:erlang:round/1 s d => too_old_compiler bif1 Fail u$bif:erlang:trunc/1 s d => too_old_compiler # +# Handle the length/1 guard BIF specially to make it trappable. +# + +gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => \ + i_length_setup Live Src | i_length Fail Live Dst + +i_length_setup t xyc + +i_length j? t d + +# # Guard BIFs. # gc_bif1 p Live Bif Src Dst => i_bif1_body Src Bif Dst |