📄 erl_arith.c
字号:
} 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]; } 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 (arg1 != make_big(tmp_big1)) { arg1 = reg[live]; } if (arg2 != make_big(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; }}Etermerts_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; }}Etermerts_gc_int_div(Process* p, Eterm* reg, Uint live){ Eterm arg1; Eterm arg2; Eterm tmp_big1[2]; Eterm tmp_big2[2]; 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 (arg1 != make_big(tmp_big1)) { arg1 = reg[live]; } if (arg2 != make_big(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; }}Etermerts_gc_int_rem(Process* p, Eterm* reg, Uint live){ Eterm arg1; Eterm arg2; Eterm tmp_big1[2]; Eterm tmp_big2[2]; 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; } arg1 = small_to_big(signed_val(arg1), tmp_big1); /*FALLTHROUGH*/ 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 (arg1 != make_big(tmp_big1)) { arg1 = reg[live]; } if (arg2 != make_big(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; \ Eterm tmp_big1[2]; \ Eterm tmp_big2[2]; \ 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;} #endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -