diff options
Diffstat (limited to 'erts/emulator/beam/erl_arith.c')
-rw-r--r-- | erts/emulator/beam/erl_arith.c | 970 |
1 files changed, 22 insertions, 948 deletions
diff --git a/erts/emulator/beam/erl_arith.c b/erts/emulator/beam/erl_arith.c index 144fb56ea5..68d1cd989e 100644 --- a/erts/emulator/beam/erl_arith.c +++ b/erts/emulator/beam/erl_arith.c @@ -52,19 +52,11 @@ static ERTS_INLINE void maybe_shrink(Process* p, Eterm* hp, Eterm res, Uint allo Uint actual; if (is_immed(res)) { - if (p->heap <= hp && hp < p->htop) { - p->htop = hp; - } - else { - erts_heap_frag_shrink(p, hp); - } + ASSERT(!(p->heap <= hp && hp < p->htop)); + erts_heap_frag_shrink(p, hp); } else if ((actual = bignum_header_arity(*hp)+1) < alloc) { - if (p->heap <= hp && hp < p->htop) { - p->htop = hp+actual; - } - else { - erts_heap_frag_shrink(p, hp+actual); - } + ASSERT(!(p->heap <= hp && hp < p->htop)); + erts_heap_frag_shrink(p, hp+actual); } } @@ -246,7 +238,7 @@ shift(Process* p, Eterm arg1, Eterm arg2, int right) BIF_ERROR(p, SYSTEM_LIMIT); } need = BIG_NEED_SIZE(ires+1); - bigp = HAlloc(p, need); + bigp = HeapFragOnlyAlloc(p, need); arg1 = big_lshift(arg1, i, bigp); maybe_shrink(p, bigp, arg1, need); if (is_nil(arg1)) { @@ -298,7 +290,7 @@ BIF_RETTYPE bnot_1(BIF_ALIST_1) ret = make_small(~signed_val(BIF_ARG_1)); } else if (is_big(BIF_ARG_1)) { Uint need = BIG_NEED_SIZE(big_size(BIF_ARG_1)+1); - Eterm* bigp = HAlloc(BIF_P, need); + Eterm* bigp = HeapFragOnlyAlloc(BIF_P, need); ret = big_bnot(BIF_ARG_1, bigp); maybe_shrink(BIF_P, bigp, ret, need); @@ -343,7 +335,7 @@ erts_mixed_plus(Process* p, Eterm arg1, Eterm arg2) if (IS_SSMALL(ires)) { return make_small(ires); } else { - hp = HAlloc(p, 2); + hp = HeapFragOnlyAlloc(p, 2); res = small_to_big(ires, hp); return res; } @@ -400,7 +392,7 @@ erts_mixed_plus(Process* p, Eterm arg1, Eterm arg2) sz2 = big_size(arg2); sz = MAX(sz1, sz2)+1; need_heap = BIG_NEED_SIZE(sz); - hp = HAlloc(p, need_heap); + hp = HeapFragOnlyAlloc(p, need_heap); res = big_plus(arg1, arg2, hp); maybe_shrink(p, hp, res, need_heap); if (is_nil(res)) { @@ -446,7 +438,7 @@ erts_mixed_plus(Process* p, Eterm arg1, Eterm arg2) do_float: f1.fd = f1.fd + f2.fd; ERTS_FP_ERROR(p, f1.fd, goto badarith); - hp = HAlloc(p, FLOAT_SIZE_OBJECT); + hp = HeapFragOnlyAlloc(p, FLOAT_SIZE_OBJECT); res = make_float(hp); PUT_DOUBLE(f1, hp); return res; @@ -488,7 +480,7 @@ erts_mixed_minus(Process* p, Eterm arg1, Eterm arg2) if (IS_SSMALL(ires)) { return make_small(ires); } else { - hp = HAlloc(p, 2); + hp = HeapFragOnlyAlloc(p, 2); res = small_to_big(ires, hp); return res; } @@ -534,7 +526,7 @@ erts_mixed_minus(Process* p, Eterm arg1, Eterm arg2) sz2 = big_size(arg2); sz = MAX(sz1, sz2)+1; need_heap = BIG_NEED_SIZE(sz); - hp = HAlloc(p, need_heap); + hp = HeapFragOnlyAlloc(p, need_heap); res = big_minus(arg1, arg2, hp); maybe_shrink(p, hp, res, need_heap); if (is_nil(res)) { @@ -589,7 +581,7 @@ erts_mixed_minus(Process* p, Eterm arg1, Eterm arg2) do_float: f1.fd = f1.fd - f2.fd; ERTS_FP_ERROR(p, f1.fd, goto badarith); - hp = HAlloc(p, FLOAT_SIZE_OBJECT); + hp = HeapFragOnlyAlloc(p, FLOAT_SIZE_OBJECT); res = make_float(hp); PUT_DOUBLE(f1, hp); return res; @@ -657,7 +649,7 @@ erts_mixed_times(Process* p, Eterm arg1, Eterm arg2) hdr = big_res[0]; arity = bignum_header_arity(hdr); ASSERT(arity == 1 || arity == 2); - hp = HAlloc(p, arity+1); + hp = HeapFragOnlyAlloc(p, arity+1); res = make_big(hp); *hp++ = hdr; *hp++ = big_res[1]; @@ -726,7 +718,7 @@ erts_mixed_times(Process* p, Eterm arg1, Eterm arg2) do_big: need_heap = BIG_NEED_SIZE(sz); - hp = HAlloc(p, need_heap); + hp = HeapFragOnlyAlloc(p, need_heap); res = big_times(arg1, arg2, hp); /* @@ -779,7 +771,7 @@ erts_mixed_times(Process* p, Eterm arg1, Eterm arg2) do_float: f1.fd = f1.fd * f2.fd; ERTS_FP_ERROR(p, f1.fd, goto badarith); - hp = HAlloc(p, FLOAT_SIZE_OBJECT); + hp = HeapFragOnlyAlloc(p, FLOAT_SIZE_OBJECT); res = make_float(hp); PUT_DOUBLE(f1, hp); return res; @@ -905,7 +897,7 @@ erts_mixed_div(Process* p, Eterm arg1, Eterm arg2) do_float: f1.fd = f1.fd / f2.fd; ERTS_FP_ERROR(p, f1.fd, goto badarith); - hp = HAlloc(p, FLOAT_SIZE_OBJECT); + hp = HeapFragOnlyAlloc(p, FLOAT_SIZE_OBJECT); PUT_DOUBLE(f1, hp); return make_float(hp); default: @@ -957,7 +949,7 @@ erts_int_div(Process* p, Eterm arg1, Eterm arg2) ires = big_size(arg2); need = BIG_NEED_SIZE(i-ires+1) + BIG_NEED_SIZE(i); - hp = HAlloc(p, need); + hp = HeapFragOnlyAlloc(p, need); arg1 = big_div(arg1, arg2, hp); maybe_shrink(p, hp, arg1, need); if (is_nil(arg1)) { @@ -1004,7 +996,7 @@ erts_int_rem(Process* p, Eterm arg1, Eterm arg2) arg1 = SMALL_ZERO; } else if (ires > 0) { Uint need = BIG_NEED_SIZE(big_size(arg1)); - Eterm* hp = HAlloc(p, need); + Eterm* hp = HeapFragOnlyAlloc(p, need); arg1 = big_rem(arg1, arg2, hp); maybe_shrink(p, hp, arg1, need); @@ -1041,7 +1033,7 @@ Eterm erts_band(Process* p, Eterm arg1, Eterm arg2) return THE_NON_VALUE; } need = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1); - hp = HAlloc(p, need); + hp = HeapFragOnlyAlloc(p, need); arg1 = big_band(arg1, arg2, hp); ASSERT(is_not_nil(arg1)); maybe_shrink(p, hp, arg1, need); @@ -1069,7 +1061,7 @@ Eterm erts_bor(Process* p, Eterm arg1, Eterm arg2) return THE_NON_VALUE; } need = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1); - hp = HAlloc(p, need); + hp = HeapFragOnlyAlloc(p, need); arg1 = big_bor(arg1, arg2, hp); ASSERT(is_not_nil(arg1)); maybe_shrink(p, hp, arg1, need); @@ -1097,7 +1089,7 @@ Eterm erts_bxor(Process* p, Eterm arg1, Eterm arg2) return THE_NON_VALUE; } need = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1); - hp = HAlloc(p, need); + hp = HeapFragOnlyAlloc(p, need); arg1 = big_bxor(arg1, arg2, hp); ASSERT(is_not_nil(arg1)); maybe_shrink(p, hp, arg1, need); @@ -1110,7 +1102,7 @@ Eterm erts_bnot(Process* p, Eterm arg) if (is_big(arg)) { Uint need = BIG_NEED_SIZE(big_size(arg)+1); - Eterm* bigp = HAlloc(p, need); + Eterm* bigp = HeapFragOnlyAlloc(p, need); ret = big_bnot(arg, bigp); maybe_shrink(p, bigp, ret, need); @@ -1125,924 +1117,6 @@ Eterm erts_bnot(Process* p, Eterm arg) return ret; } -#define ERTS_NEED_GC(p, need) ((HEAP_LIMIT((p)) - HEAP_TOP((p))) <= (need)) - -static ERTS_INLINE void -trim_heap(Process* p, Eterm* hp, Eterm res) -{ - if (is_immed(res)) { - ASSERT(p->heap <= hp && hp <= p->htop); - p->htop = hp; - } else { - Eterm* new_htop; - ASSERT(is_big(res)); - new_htop = hp + bignum_header_arity(*hp) + 1; - ASSERT(p->heap <= new_htop && new_htop <= p->htop); - p->htop = new_htop; - } - ASSERT(p->heap <= p->htop && p->htop <= p->stop); -} - -/* - * The functions that follow are called from the emulator loop. - * They are not allowed to allocate heap fragments, but must do - * a garbage collection if there is insufficient heap space. - */ - -#define erts_heap_frag_shrink horrible error -#define maybe_shrink horrible error - -Eterm -erts_gc_mixed_plus(Process* p, Eterm* reg, Uint live) -{ - Eterm arg1; - Eterm arg2; - DECLARE_TMP(tmp_big1,0,p); - DECLARE_TMP(tmp_big2,1,p); - Eterm res; - Eterm hdr; - FloatDef f1, f2; - dsize_t sz1, sz2, sz; - int need_heap; - Eterm* hp; - Sint ires; - - arg1 = reg[live]; - arg2 = reg[live+1]; - ERTS_FP_CHECK_INIT(p); - switch (arg1 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - ires = signed_val(arg1) + signed_val(arg2); - if (IS_SSMALL(ires)) { - return make_small(ires); - } else { - if (ERTS_NEED_GC(p, 2)) { - erts_garbage_collect(p, 2, reg, live); - } - hp = p->htop; - p->htop += 2; - res = small_to_big(ires, hp); - return res; - } - default: - badarith: - p->freason = BADARITH; - return THE_NON_VALUE; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - if (arg1 == SMALL_ZERO) { - return arg2; - } - arg1 = small_to_big(signed_val(arg1), tmp_big1); - goto do_big; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - f1.fd = signed_val(arg1); - GET_DOUBLE(arg2, f2); - goto do_float; - default: - goto badarith; - } - } - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg1); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - if (arg2 == SMALL_ZERO) { - return arg1; - } - arg2 = small_to_big(signed_val(arg2), tmp_big2); - goto do_big; - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - do_big: - sz1 = big_size(arg1); - sz2 = big_size(arg2); - sz = MAX(sz1, sz2)+1; - need_heap = BIG_NEED_SIZE(sz); - if (ERTS_NEED_GC(p, need_heap)) { - erts_garbage_collect(p, need_heap, reg, live+2); - if (ARG_IS_NOT_TMP(arg1,tmp_big1)) { - arg1 = reg[live]; - } - if (ARG_IS_NOT_TMP(arg2,tmp_big2)) { - arg2 = reg[live+1]; - } - } - hp = p->htop; - p->htop += need_heap; - res = big_plus(arg1, arg2, hp); - trim_heap(p, hp, res); - if (is_nil(res)) { - p->freason = SYSTEM_LIMIT; - return THE_NON_VALUE; - } - return res; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - if (big_to_double(arg1, &f1.fd) < 0) { - goto badarith; - } - GET_DOUBLE(arg2, f2); - goto do_float; - default: - goto badarith; - } - } - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - f2.fd = signed_val(arg2); - goto do_float; - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - if (big_to_double(arg2, &f2.fd) < 0) { - goto badarith; - } - goto do_float; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - GET_DOUBLE(arg2, f2); - - do_float: - f1.fd = f1.fd + f2.fd; - ERTS_FP_ERROR(p, f1.fd, goto badarith); - if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) { - erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live); - } - hp = p->htop; - p->htop += FLOAT_SIZE_OBJECT; - res = make_float(hp); - PUT_DOUBLE(f1, hp); - return res; - default: - goto badarith; - } - default: - goto badarith; - } - } - default: - goto badarith; - } -} - -Eterm -erts_gc_mixed_minus(Process* p, Eterm* reg, Uint live) -{ - Eterm arg1; - Eterm arg2; - DECLARE_TMP(tmp_big1,0,p); - DECLARE_TMP(tmp_big2,1,p); - Eterm hdr; - Eterm res; - FloatDef f1, f2; - dsize_t sz1, sz2, sz; - int need_heap; - Eterm* hp; - Sint ires; - - arg1 = reg[live]; - arg2 = reg[live+1]; - ERTS_FP_CHECK_INIT(p); - switch (arg1 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - ires = signed_val(arg1) - signed_val(arg2); - if (IS_SSMALL(ires)) { - return make_small(ires); - } else { - if (ERTS_NEED_GC(p, 2)) { - erts_garbage_collect(p, 2, reg, live); - } - hp = p->htop; - p->htop += 2; - res = small_to_big(ires, hp); - return res; - } - default: - badarith: - p->freason = BADARITH; - return THE_NON_VALUE; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - arg1 = small_to_big(signed_val(arg1), tmp_big1); - goto do_big; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - f1.fd = signed_val(arg1); - GET_DOUBLE(arg2, f2); - goto do_float; - default: - goto badarith; - } - } - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg1); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - if (arg2 == SMALL_ZERO) { - return arg1; - } - arg2 = small_to_big(signed_val(arg2), tmp_big2); - - do_big: - sz1 = big_size(arg1); - sz2 = big_size(arg2); - sz = MAX(sz1, sz2)+1; - need_heap = BIG_NEED_SIZE(sz); - if (ERTS_NEED_GC(p, need_heap)) { - erts_garbage_collect(p, need_heap, reg, live+2); - if (ARG_IS_NOT_TMP(arg1,tmp_big1)) { - arg1 = reg[live]; - } - if (ARG_IS_NOT_TMP(arg2,tmp_big2)) { - arg2 = reg[live+1]; - } - } - hp = p->htop; - p->htop += need_heap; - res = big_minus(arg1, arg2, hp); - trim_heap(p, hp, res); - if (is_nil(res)) { - p->freason = SYSTEM_LIMIT; - return THE_NON_VALUE; - } - return res; - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - goto do_big; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - if (big_to_double(arg1, &f1.fd) < 0) { - goto badarith; - } - GET_DOUBLE(arg2, f2); - goto do_float; - default: - goto badarith; - } - } - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - f2.fd = signed_val(arg2); - goto do_float; - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - if (big_to_double(arg2, &f2.fd) < 0) { - goto badarith; - } - goto do_float; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - GET_DOUBLE(arg2, f2); - - do_float: - f1.fd = f1.fd - f2.fd; - ERTS_FP_ERROR(p, f1.fd, goto badarith); - if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) { - erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live); - } - hp = p->htop; - p->htop += FLOAT_SIZE_OBJECT; - res = make_float(hp); - PUT_DOUBLE(f1, hp); - return res; - default: - goto badarith; - } - default: - goto badarith; - } - } - default: - goto badarith; - } -} - -Eterm -erts_gc_mixed_times(Process* p, Eterm* reg, Uint live) -{ - Eterm arg1; - Eterm arg2; - DECLARE_TMP(tmp_big1,0,p); - DECLARE_TMP(tmp_big2,1,p); - Eterm hdr; - Eterm res; - FloatDef f1, f2; - dsize_t sz1, sz2, sz; - int need_heap; - Eterm* hp; - - arg1 = reg[live]; - arg2 = reg[live+1]; - ERTS_FP_CHECK_INIT(p); - switch (arg1 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - if ((arg1 == SMALL_ZERO) || (arg2 == SMALL_ZERO)) { - return(SMALL_ZERO); - } else if (arg1 == SMALL_ONE) { - return(arg2); - } else if (arg2 == SMALL_ONE) { - return(arg1); - } else { - DeclareTmpHeap(big_res,3,p); - UseTmpHeap(3,p); - - /* - * The following code is optimized for the case that - * result is small (which should be the most common case - * in practice). - */ - res = small_times(signed_val(arg1), signed_val(arg2), - big_res); - if (is_small(res)) { - UnUseTmpHeap(3,p); - return res; - } else { - /* - * The result is a a big number. - * Allocate a heap fragment and copy the result. - * Be careful to allocate exactly what we need - * to not leave any holes. - */ - Uint arity; - Uint need; - - ASSERT(is_big(res)); - hdr = big_res[0]; - arity = bignum_header_arity(hdr); - ASSERT(arity == 1 || arity == 2); - need = arity + 1; - if (ERTS_NEED_GC(p, need)) { - erts_garbage_collect(p, need, reg, live); - } - hp = p->htop; - p->htop += need; - res = make_big(hp); - *hp++ = hdr; - *hp++ = big_res[1]; - if (arity > 1) { - *hp = big_res[2]; - } - UnUseTmpHeap(3,p); - return res; - } - } - default: - badarith: - p->freason = BADARITH; - return THE_NON_VALUE; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - if (arg1 == SMALL_ZERO) - return(SMALL_ZERO); - if (arg1 == SMALL_ONE) - return(arg2); - arg1 = small_to_big(signed_val(arg1), tmp_big1); - sz = 2 + big_size(arg2); - goto do_big; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - f1.fd = signed_val(arg1); - GET_DOUBLE(arg2, f2); - goto do_float; - default: - goto badarith; - } - } - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg1); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - if (arg2 == SMALL_ZERO) - return(SMALL_ZERO); - if (arg2 == SMALL_ONE) - return(arg1); - arg2 = small_to_big(signed_val(arg2), tmp_big2); - sz = 2 + big_size(arg1); - goto do_big; - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - sz1 = big_size(arg1); - sz2 = big_size(arg2); - sz = sz1 + sz2; - - do_big: - need_heap = BIG_NEED_SIZE(sz); - if (ERTS_NEED_GC(p, need_heap)) { - erts_garbage_collect(p, need_heap, reg, live+2); - if (ARG_IS_NOT_TMP(arg1,tmp_big1)) { - arg1 = reg[live]; - } - if (ARG_IS_NOT_TMP(arg2,tmp_big2)) { - arg2 = reg[live+1]; - } - } - hp = p->htop; - p->htop += need_heap; - res = big_times(arg1, arg2, hp); - trim_heap(p, hp, res); - - /* - * Note that the result must be big in this case, since - * at least one operand was big to begin with, and - * the absolute value of the other is > 1. - */ - - if (is_nil(res)) { - p->freason = SYSTEM_LIMIT; - return THE_NON_VALUE; - } - return res; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - if (big_to_double(arg1, &f1.fd) < 0) { - goto badarith; - } - GET_DOUBLE(arg2, f2); - goto do_float; - default: - goto badarith; - } - } - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - f2.fd = signed_val(arg2); - goto do_float; - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - if (big_to_double(arg2, &f2.fd) < 0) { - goto badarith; - } - goto do_float; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - GET_DOUBLE(arg2, f2); - - do_float: - f1.fd = f1.fd * f2.fd; - ERTS_FP_ERROR(p, f1.fd, goto badarith); - if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) { - erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live); - } - hp = p->htop; - p->htop += FLOAT_SIZE_OBJECT; - res = make_float(hp); - PUT_DOUBLE(f1, hp); - return res; - default: - goto badarith; - } - default: - goto badarith; - } - } - default: - goto badarith; - } -} - -Eterm -erts_gc_mixed_div(Process* p, Eterm* reg, Uint live) -{ - Eterm arg1; - Eterm arg2; - FloatDef f1, f2; - Eterm* hp; - Eterm hdr; - - arg1 = reg[live]; - arg2 = reg[live+1]; - ERTS_FP_CHECK_INIT(p); - switch (arg1 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - f1.fd = signed_val(arg1); - f2.fd = signed_val(arg2); - goto do_float; - default: - badarith: - p->freason = BADARITH; - return THE_NON_VALUE; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - f1.fd = signed_val(arg1); - if (big_to_double(arg2, &f2.fd) < 0) { - goto badarith; - } - goto do_float; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - f1.fd = signed_val(arg1); - GET_DOUBLE(arg2, f2); - goto do_float; - default: - goto badarith; - } - } - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg1); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - if (big_to_double(arg1, &f1.fd) < 0) { - goto badarith; - } - f2.fd = signed_val(arg2); - goto do_float; - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - if (big_to_double(arg1, &f1.fd) < 0 || - big_to_double(arg2, &f2.fd) < 0) { - goto badarith; - } - goto do_float; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - if (big_to_double(arg1, &f1.fd) < 0) { - goto badarith; - } - GET_DOUBLE(arg2, f2); - goto do_float; - default: - goto badarith; - } - } - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - switch (arg2 & _TAG_PRIMARY_MASK) { - case TAG_PRIMARY_IMMED1: - switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - f2.fd = signed_val(arg2); - goto do_float; - default: - goto badarith; - } - case TAG_PRIMARY_BOXED: - hdr = *boxed_val(arg2); - switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { - case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): - case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - if (big_to_double(arg2, &f2.fd) < 0) { - goto badarith; - } - goto do_float; - case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - GET_DOUBLE(arg1, f1); - GET_DOUBLE(arg2, f2); - - do_float: - f1.fd = f1.fd / f2.fd; - ERTS_FP_ERROR(p, f1.fd, goto badarith); - if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) { - erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live); - } - hp = p->htop; - p->htop += FLOAT_SIZE_OBJECT; - PUT_DOUBLE(f1, hp); - return make_float(hp); - default: - goto badarith; - } - default: - goto badarith; - } - } - default: - goto badarith; - } -} - -Eterm -erts_gc_int_div(Process* p, Eterm* reg, Uint live) -{ - Eterm arg1; - Eterm arg2; - DECLARE_TMP(tmp_big1,0,p); - DECLARE_TMP(tmp_big2,1,p); - int ires; - - arg1 = reg[live]; - arg2 = reg[live+1]; - switch (NUMBER_CODE(arg1, arg2)) { - case SMALL_SMALL: - /* This case occurs if the most negative fixnum is divided by -1. */ - ASSERT(arg2 == make_small(-1)); - arg1 = small_to_big(signed_val(arg1), tmp_big1); - /*FALLTHROUGH*/ - case BIG_SMALL: - arg2 = small_to_big(signed_val(arg2), tmp_big2); - goto L_big_div; - case SMALL_BIG: - if (arg1 != make_small(MIN_SMALL)) { - return SMALL_ZERO; - } - arg1 = small_to_big(signed_val(arg1), tmp_big1); - /*FALLTHROUGH*/ - case BIG_BIG: - L_big_div: - ires = big_ucomp(arg1, arg2); - if (ires < 0) { - arg1 = SMALL_ZERO; - } else if (ires == 0) { - arg1 = (big_sign(arg1) == big_sign(arg2)) ? - SMALL_ONE : SMALL_MINUS_ONE; - } else { - Eterm* hp; - int i = big_size(arg1); - Uint need; - - ires = big_size(arg2); - need = BIG_NEED_SIZE(i-ires+1) + BIG_NEED_SIZE(i); - if (ERTS_NEED_GC(p, need)) { - erts_garbage_collect(p, need, reg, live+2); - if (ARG_IS_NOT_TMP(arg1,tmp_big1)) { - arg1 = reg[live]; - } - if (ARG_IS_NOT_TMP(arg2,tmp_big2)) { - arg2 = reg[live+1]; - } - } - hp = p->htop; - p->htop += need; - arg1 = big_div(arg1, arg2, hp); - trim_heap(p, hp, arg1); - if (is_nil(arg1)) { - p->freason = SYSTEM_LIMIT; - return THE_NON_VALUE; - } - } - return arg1; - default: - p->freason = BADARITH; - return THE_NON_VALUE; - } -} - -Eterm -erts_gc_int_rem(Process* p, Eterm* reg, Uint live) -{ - Eterm arg1; - Eterm arg2; - DECLARE_TMP(tmp_big1,0,p); - DECLARE_TMP(tmp_big2,1,p); - int ires; - - arg1 = reg[live]; - arg2 = reg[live+1]; - switch (NUMBER_CODE(arg1, arg2)) { - case BIG_SMALL: - arg2 = small_to_big(signed_val(arg2), tmp_big2); - goto L_big_rem; - case SMALL_BIG: - if (arg1 != make_small(MIN_SMALL)) { - return arg1; - } else { - Eterm tmp; - tmp = small_to_big(signed_val(arg1), tmp_big1); - if ((ires = big_ucomp(tmp, arg2)) == 0) { - return SMALL_ZERO; - } else { - ASSERT(ires < 0); - return arg1; - } - } - /* All paths returned */ - case BIG_BIG: - L_big_rem: - ires = big_ucomp(arg1, arg2); - if (ires == 0) { - arg1 = SMALL_ZERO; - } else if (ires > 0) { - Eterm* hp; - Uint need = BIG_NEED_SIZE(big_size(arg1)); - - if (ERTS_NEED_GC(p, need)) { - erts_garbage_collect(p, need, reg, live+2); - if (ARG_IS_NOT_TMP(arg1,tmp_big1)) { - arg1 = reg[live]; - } - if (ARG_IS_NOT_TMP(arg2,tmp_big2)) { - arg2 = reg[live+1]; - } - } - hp = p->htop; - p->htop += need; - arg1 = big_rem(arg1, arg2, hp); - trim_heap(p, hp, arg1); - if (is_nil(arg1)) { - p->freason = SYSTEM_LIMIT; - return THE_NON_VALUE; - } - } - return arg1; - default: - p->freason = BADARITH; - return THE_NON_VALUE; - } -} - -#define DEFINE_GC_LOGIC_FUNC(func) \ -Eterm erts_gc_##func(Process* p, Eterm* reg, Uint live) \ -{ \ - Eterm arg1; \ - Eterm arg2; \ - DECLARE_TMP(tmp_big1,0,p); \ - DECLARE_TMP(tmp_big2,1,p); \ - Eterm* hp; \ - int need; \ - \ - arg1 = reg[live]; \ - arg2 = reg[live+1]; \ - switch (NUMBER_CODE(arg1, arg2)) { \ - case SMALL_BIG: \ - arg1 = small_to_big(signed_val(arg1), tmp_big1); \ - need = BIG_NEED_SIZE(big_size(arg2) + 1); \ - if (ERTS_NEED_GC(p, need)) { \ - erts_garbage_collect(p, need, reg, live+2); \ - arg2 = reg[live+1]; \ - } \ - break; \ - case BIG_SMALL: \ - arg2 = small_to_big(signed_val(arg2), tmp_big2); \ - need = BIG_NEED_SIZE(big_size(arg1) + 1); \ - if (ERTS_NEED_GC(p, need)) { \ - erts_garbage_collect(p, need, reg, live+2); \ - arg1 = reg[live]; \ - } \ - break; \ - case BIG_BIG: \ - need = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1); \ - if (ERTS_NEED_GC(p, need)) { \ - erts_garbage_collect(p, need, reg, live+2); \ - arg1 = reg[live]; \ - arg2 = reg[live+1]; \ - } \ - break; \ - default: \ - p->freason = BADARITH; \ - return THE_NON_VALUE; \ - } \ - hp = p->htop; \ - p->htop += need; \ - arg1 = big_##func(arg1, arg2, hp); \ - trim_heap(p, hp, arg1); \ - return arg1; \ -} - -DEFINE_GC_LOGIC_FUNC(band) -DEFINE_GC_LOGIC_FUNC(bor) -DEFINE_GC_LOGIC_FUNC(bxor) - -Eterm erts_gc_bnot(Process* p, Eterm* reg, Uint live) -{ - Eterm result; - Eterm arg; - Uint need; - Eterm* bigp; - - arg = reg[live]; - if (is_not_big(arg)) { - p->freason = BADARITH; - return NIL; - } else { - need = BIG_NEED_SIZE(big_size(arg)+1); - if (ERTS_NEED_GC(p, need)) { - erts_garbage_collect(p, need, reg, live+1); - arg = reg[live]; - } - bigp = p->htop; - p->htop += need; - result = big_bnot(arg, bigp); - trim_heap(p, bigp, result); - if (is_nil(result)) { - p->freason = SYSTEM_LIMIT; - return NIL; - } - } - return result; -} - /* Needed to remove compiler optimization */ double erts_get_positive_zero_float() { return 0.0f; |