diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index 8bbb99c54488..fa366686f26b 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -690,15 +690,6 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr) print_byte_string(to, to_arg, str, bytes); } break; - case op_bs_put_string_WW: - if (ap - first_arg == 0) { - erts_print(to, to_arg, "%d", *ap); - } else { - Uint bytes = ap[-1]; - byte* str = (byte *) ap[0]; - print_byte_string(to, to_arg, str, bytes); - } - break; default: #ifdef ARCH_64 erts_print(to, to_arg, "%ld", *ap); diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index af2747a77e2d..488c4990b1d5 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -194,8 +194,13 @@ erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, * * We know that because OTP 23/24/25/26 artifically set the * highest used op code to the op code for the `swap` - * instruction introduced in OTP 23. (OTP 27 artificially sets - * the highest op code to `make_fun3` introduced in OTP 24.) + * instruction introduced in OTP 23. + * + * OTP 27 artificially sets the highest op code to `make_fun3` + * introduced in OTP 24. + * + * OTP 28 artificially sets the highest op code to `bs_create_bin` + * introduced in OTP 25. * * Old BEAM files produced by OTP R12 and earlier may be * incompatible with the current runtime system. We used to @@ -207,7 +212,7 @@ erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, "This BEAM file was compiled for an old version of " "the runtime system.\n" " To fix this, please re-compile this module with " - "Erlang/OTP 24 or later.\n"); + "Erlang/OTP 25 or later.\n"); } if (!load_code(stp)) { diff --git a/erts/emulator/beam/emu/beam_emu.c b/erts/emulator/beam/emu/beam_emu.c index bdc0173bedca..f08c2caddc92 100644 --- a/erts/emulator/beam/emu/beam_emu.c +++ b/erts/emulator/beam/emu/beam_emu.c @@ -320,8 +320,6 @@ void process_main(ErtsSchedulerData *esdp) ERTS_MSACC_DECLARE_CACHE_X() /* a cached value of the tsd pointer for msacc */ - ERL_BITS_DECLARE_STATEP; /* Has to be last declaration */ - /* * Note: In this function, we attempt to place rarely executed code towards * the end of the function, in the hope that the cache hit rate will be better. @@ -379,7 +377,6 @@ void process_main(ErtsSchedulerData *esdp) start_time_i = c_p->i; } - ERL_BITS_RELOAD_STATEP(c_p); { int reds; BeamInstr next; diff --git a/erts/emulator/beam/emu/bs_instrs.tab b/erts/emulator/beam/emu/bs_instrs.tab index 57d9ab256cb8..1150b1172781 100644 --- a/erts/emulator/beam/emu/bs_instrs.tab +++ b/erts/emulator/beam/emu/bs_instrs.tab @@ -291,513 +291,12 @@ i_bs_skip_bits_imm2(Fail, Ms, Bits) { } } -i_new_bs_put_binary(Fail, Sz, Flags, Src) { - Eterm sz = $Sz; - Sint _size; - $BS_GET_UNCHECKED_FIELD_SIZE(sz, (($Flags) >> 3), $BADARG($Fail), _size); - c_p->fcalls = FCALLS; - if (!erts_new_bs_put_binary(c_p, $Src, _size)) { - $BADARG($Fail); - } - FCALLS = c_p->fcalls; -} - -i_new_bs_put_binary_all := i_new_bs_put_binary_all.fetch.execute; - -i_new_bs_put_binary_all.head() { - Eterm src; -} - -i_new_bs_put_binary_all.fetch(Src) { - src = $Src; -} - -i_new_bs_put_binary_all.execute(Fail, Unit) { - c_p->fcalls = FCALLS; - if (!erts_new_bs_put_binary_all(c_p, src, ($Unit))) { - $BADARG($Fail); - } - FCALLS = c_p->fcalls; -} - -i_new_bs_put_binary_imm(Fail, Sz, Src) { - c_p->fcalls = FCALLS; - if (!erts_new_bs_put_binary(c_p, ($Src), ($Sz))) { - $BADARG($Fail); - } - FCALLS = c_p->fcalls; -} - -i_new_bs_put_float(Fail, Sz, Flags, Src) { - Eterm sz = $Sz; - Eterm flags = $Flags; - Sint _size; - $BS_GET_UNCHECKED_FIELD_SIZE(sz, (flags >> 3), $BADARG($Fail), _size); - if (is_value(erts_new_bs_put_float(c_p, ($Src), _size, flags))) { - $BADARG($Fail); - } -} - -i_new_bs_put_float_imm(Fail, Sz, Flags, Src) { - if (is_value(erts_new_bs_put_float(c_p, ($Src), ($Sz), ($Flags)))) { - $BADARG($Fail); - } -} - -i_new_bs_put_integer(Fail, Sz, Flags, Src) { - Eterm sz = $Sz; - Eterm flags = $Flags; - Sint _size; - $BS_GET_UNCHECKED_FIELD_SIZE(sz, (flags >> 3), $BADARG($Fail), _size); - if (!erts_new_bs_put_integer(ERL_BITS_ARGS_3(($Src), _size, flags))) { - $BADARG($Fail); - } -} - -i_new_bs_put_integer_imm := i_new_bs_put_integer_imm.fetch.execute; - -i_new_bs_put_integer_imm.head() { - Eterm src; -} - -i_new_bs_put_integer_imm.fetch(Src) { - src = $Src; -} - -i_new_bs_put_integer_imm.execute(Fail, Sz, Flags) { - if (!erts_new_bs_put_integer(ERL_BITS_ARGS_3(src, ($Sz), ($Flags)))) { - $BADARG($Fail); - } -} - -# -# i_bs_init* -# - -i_bs_init_fail_heap := bs_init.fail_heap.verify.execute; -i_bs_init_fail := bs_init.fail.verify.execute; -i_bs_init := bs_init.plain.execute; -i_bs_init_heap := bs_init.heap.execute; - -bs_init.head() { - Eterm BsOp1; - Eterm BsOp2; -} - -bs_init.fail_heap(Size, HeapAlloc) { - BsOp1 = $Size; - BsOp2 = $HeapAlloc; -} - -bs_init.fail(Size) { - BsOp1 = $Size; - BsOp2 = 0; -} - -bs_init.plain(Size) { - BsOp1 = $Size; - BsOp2 = 0; -} - -bs_init.heap(Size, HeapAlloc) { - BsOp1 = $Size; - BsOp2 = $HeapAlloc; -} - -bs_init.verify(Fail) { - if (is_small(BsOp1)) { - Sint size = signed_val(BsOp1); - if (size < 0) { - $BADARG($Fail); - } - BsOp1 = (Eterm) size; - } else { - Uint bytes; - - if (!term_to_Uint(BsOp1, &bytes)) { - c_p->freason = bytes; - $FAIL_HEAD_OR_BODY($Fail); - } - if ((bytes >> (8*sizeof(Uint)-3)) != 0) { - $SYSTEM_LIMIT($Fail); - } - BsOp1 = (Eterm) bytes; - } -} - -bs_init.execute(Live, Dst) { - Uint num_bits, heap_extra; - Eterm new_binary; - - erts_bin_offset = 0; - - num_bits = BsOp1 * CHAR_BIT; - heap_extra = BsOp2; - - if (num_bits <= ERL_ONHEAP_BITS_LIMIT) { - ErlHeapBits *hb; - Uint bin_need; - - bin_need = heap_bits_size(num_bits); - $GC_TEST(0, bin_need + heap_extra + ERL_SUB_BITS_SIZE, $Live); - - hb = (ErlHeapBits*)HTOP; - HTOP += bin_need; - - hb->thing_word = header_heap_bits(num_bits); - hb->size = num_bits; - erts_current_bin = (byte *) hb->data; - - new_binary = make_bitstring(hb); - } else { - Binary* bptr; - - $TEST_BIN_VHEAP(NBYTES(num_bits) / sizeof(Eterm), - heap_extra + ERL_REFC_BITS_SIZE, - $Live); - - bptr = erts_bin_nrml_alloc(NBYTES(num_bits)); - erts_current_bin = (byte *) bptr->orig_bytes; - - LIGHT_SWAPOUT; - - new_binary = erts_wrap_refc_bitstring(&MSO(c_p).first, - &MSO(c_p).overhead, - &HEAP_TOP(c_p), - bptr, - erts_current_bin, - 0, - num_bits); - - LIGHT_SWAPIN; - } - - $Dst = new_binary; -} - -# -# i_bs_init_bits* -# - -i_bs_init_bits := bs_init_bits.plain.execute; -i_bs_init_bits_heap := bs_init_bits.heap.execute; -i_bs_init_bits_fail := bs_init_bits.fail.verify.execute; -i_bs_init_bits_fail_heap := bs_init_bits.fail_heap.verify.execute; - -bs_init_bits.head() { - Eterm num_bits_term; - Uint num_bits; - Uint alloc; -} - -bs_init_bits.plain(NumBits) { - num_bits = $NumBits; - alloc = 0; -} - -bs_init_bits.heap(NumBits, Alloc) { - num_bits = $NumBits; - alloc = $Alloc; -} - -bs_init_bits.fail(NumBitsTerm) { - num_bits_term = $NumBitsTerm; - alloc = 0; -} - -bs_init_bits.fail_heap(NumBitsTerm, Alloc) { - num_bits_term = $NumBitsTerm; - alloc = $Alloc; -} - -bs_init_bits.verify(Fail) { - if (is_small(num_bits_term)) { - Sint size = signed_val(num_bits_term); - if (size < 0) { - $BADARG($Fail); - } - num_bits = (Uint) size; - } else { - Uint bits; - - if (!term_to_Uint(num_bits_term, &bits)) { - c_p->freason = bits; - $FAIL_HEAD_OR_BODY($Fail); - } - num_bits = (Uint) bits; - } -} - -bs_init_bits.execute(Live, Dst) { - Eterm new_binary; - - if (num_bits <= ERL_ONHEAP_BITS_LIMIT) { - alloc += heap_bits_size(num_bits); - } else { - alloc += ERL_REFC_BITS_SIZE; - } - - erts_bin_offset = 0; - - /* num_bits = Number of bits to build - * num_bytes = Number of bytes to allocate in the binary - * alloc = Total number of words to allocate on heap - * Operands: NotUsed NotUsed Dst - */ - if (num_bits <= ERL_ONHEAP_BITS_LIMIT) { - ErlHeapBits *hb; - - $test_heap(alloc, $Live); - - hb = (ErlHeapBits*) HTOP; - HTOP += heap_bits_size(num_bits); - hb->thing_word = header_heap_bits(num_bits); - - hb->size = num_bits; - - erts_current_bin = (byte*)hb->data; - new_binary = make_bitstring(hb); - } else { - Binary *bptr; - - $TEST_BIN_VHEAP(NBYTES(num_bits) / sizeof(Eterm), - alloc + ERL_REFC_BITS_SIZE, - $Live); - - bptr = erts_bin_nrml_alloc(NBYTES(num_bits)); - erts_current_bin = (byte *) bptr->orig_bytes; - - LIGHT_SWAPOUT; - - new_binary = erts_wrap_refc_bitstring(&MSO(c_p).first, - &MSO(c_p).overhead, - &HEAP_TOP(c_p), - bptr, - erts_current_bin, - 0, - num_bits); - - LIGHT_SWAPIN; - } - - HEAP_SPACE_VERIFIED(0); - $Dst = new_binary; -} - -bs_add(Fail, Src1, Src2, Unit, Dst) { - Eterm Op1 = $Src1; - Eterm Op2 = $Src2; - Uint unit = $Unit; - - if (is_both_small(Op1, Op2)) { - Sint Arg1 = signed_val(Op1); - Sint Arg2 = signed_val(Op2); - - if (Arg1 >= 0 && Arg2 >= 0) { - $BS_SAFE_MUL(Arg2, unit, $SYSTEM_LIMIT($Fail), Op1); - Op1 += Arg1; - -#ifdef ARCH_32 - store_bs_add_result: -#endif - if (Op1 <= MAX_SMALL) { - Op1 = make_small(Op1); - } else { - /* - * May generate a heap fragment, but in this - * particular case it is OK, since the value will be - * stored into an x register (the GC will scan x - * registers for references to heap fragments) and - * there is no risk that value can be stored into a - * location that is not scanned for heap-fragment - * references (such as the heap). - */ - SWAPOUT; - Op1 = erts_make_integer(Op1, c_p); - HTOP = HEAP_TOP(c_p); - } - $Dst = Op1; - $NEXT0(); - } - $BADARG($Fail); - } else { -#ifdef ARCH_64 - /* The size must fit into a small on 64-bit platforms, which can't - * happen if either operand is a bignum. */ - if (((is_small(Op1) && signed_val(Op1) >= 0) || - (is_big(Op1) && !big_sign(Op1))) && - ((is_small(Op2) && signed_val(Op2) >= 0) || - (is_big(Op2) && !big_sign(Op2)))) { - $SYSTEM_LIMIT($Fail); - } else { - $BADARG($Fail); - } -#else - Uint a; - Uint b; - Uint c; - - /* - * Now we know that one of the arguments is - * not a small. We must convert both arguments - * to Uints and check for errors at the same time. - * - * Error checking is tricky. - * - * If one of the arguments is not numeric or - * not positive, the error reason is BADARG. - * - * Otherwise if both arguments are numeric, - * but at least one argument does not fit in - * an Uint, the reason is SYSTEM_LIMIT. - */ - - if (!term_to_Uint(Op1, &a)) { - if (a == BADARG) { - c_p->freason = a; - $FAIL_HEAD_OR_BODY($Fail); - } - if (!term_to_Uint(Op2, &b)) { - c_p->freason = b; - $FAIL_HEAD_OR_BODY($Fail); - } - $SYSTEM_LIMIT($Fail); - } else if (!term_to_Uint(Op2, &b)) { - c_p->freason = b; - $FAIL_HEAD_OR_BODY($Fail); - } - - /* - * The arguments are now correct and stored in a and b. - */ - - $BS_SAFE_MUL(b, unit, $SYSTEM_LIMIT($Fail), c); - Op1 = a + c; - if (Op1 < a) { - /* - * If the result is less than one of the - * arguments, there must have been an overflow. - */ - $SYSTEM_LIMIT($Fail); - } - goto store_bs_add_result; -#endif - } - /* No fallthrough */ - ASSERT(0); -} - -bs_put_string(Len, Ptr) { - erts_new_bs_put_string(ERL_BITS_ARGS_2((byte *) $Ptr, $Len)); -} - -i_bs_append(Fail, ExtraHeap, Live, Unit, Size, Dst) { - Uint live = $Live; - Uint res; - - HEAVY_SWAPOUT; - reg[live] = x(SCRATCH_X_REG); - res = erts_bs_append(c_p, reg, live, $Size, $ExtraHeap, $Unit); - HEAVY_SWAPIN; - if (is_non_value(res)) { - $MAYBE_EXIT_AFTER_GC(); - - /* c_p->freason is already set (to BADARG or SYSTEM_LIMIT). */ - $FAIL_HEAD_OR_BODY($Fail); - } - $Dst = res; -} - -i_bs_private_append(Fail, Unit, Size, Src, Dst) { - Eterm res; - - c_p->fcalls = FCALLS; - res = erts_bs_private_append(c_p, $Src, $Size, $Unit); - if (is_non_value(res)) { - /* c_p->freason is already set (to BADARG or SYSTEM_LIMIT). */ - $FAIL_HEAD_OR_BODY($Fail); - } - FCALLS = c_p->fcalls; - $Dst = res; -} - bs_init_writable() { HEAVY_SWAPOUT; x(0) = erts_bs_init_writable(c_p, x(0)); HEAVY_SWAPIN; } -i_bs_utf8_size(Src, Dst) { - Eterm arg = $Src; - Eterm result; - - /* - * Calculate the number of bytes needed to encode the source - * operand to UTF-8. If the source operand is invalid (e.g. wrong - * type or range) we return a nonsense integer result (0 or 4). We - * can get away with that because we KNOW that bs_put_utf8 will do - * full error checking. - */ - - if (arg < make_small(0x80UL)) { - result = make_small(1); - } else if (arg < make_small(0x800UL)) { - result = make_small(2); - } else if (arg < make_small(0x10000UL)) { - result = make_small(3); - } else { - result = make_small(4); - } - $Dst = result; -} - -i_bs_put_utf8(Fail, Src) { - if (!erts_bs_put_utf8(ERL_BITS_ARGS_1($Src))) { - $BADARG($Fail); - } -} - -i_bs_utf16_size(Src, Dst) { - Eterm arg = $Src; - Eterm result = make_small(2); - - /* - * Calculate the number of bytes needed to encode the source - * operarand to UTF-16. If the source operand is invalid (e.g. wrong - * type or range) we return a nonsense integer result (2 or 4). We - * can get away with that because we KNOW that bs_put_utf16 will do - * full error checking. - */ - - if (arg >= make_small(0x10000UL)) { - result = make_small(4); - } - $Dst = result; -} - -i_bs_put_utf16(Fail, Flags, Src) { - if (!erts_bs_put_utf16(ERL_BITS_ARGS_2($Src, $Flags))) { - $BADARG($Fail); - } -} - -// Validate a value about to be stored in a binary. -i_bs_validate_unicode(Fail, Src) { - Eterm val = $Src; - - /* - * There is no need to untag the integer, but it IS necessary - * to make sure it is small (if the term is a bignum, it could - * slip through the test, and there is no further test that - * would catch it, since bit syntax construction silently masks - * too big numbers). - */ - if (is_not_small(val) || val > make_small(0x10FFFFUL) || - (make_small(0xD800UL) <= val && val <= make_small(0xDFFFUL))) { - $BADARG($Fail); - } -} - // Validate a value that has been matched out. i_bs_validate_unicode_retract(Fail, Src, Ms) { /* @@ -874,6 +373,7 @@ i_bs_create_bin(Fail, Alloc, Live, Dst, N) { const BeamInstr* p; Uint alloc = $Alloc; Eterm new_binary; + ERL_BITS_DECLARE_STATEP; /* Has to be last declaration */ /* We count the total number of bits in an unsigned integer. To avoid * having to check for overflow when adding to `num_bits`, we ensure that @@ -1046,6 +546,7 @@ i_bs_create_bin(Fail, Alloc, Live, Dst, N) { } /* Allocate binary. */ + ERL_BITS_RELOAD_STATEP(c_p); p = p_start; if (p[0] == BSC_APPEND) { Uint live = $Live; diff --git a/erts/emulator/beam/emu/emu_load.c b/erts/emulator/beam/emu/emu_load.c index 7ca930eb5815..c0eabe61843e 100644 --- a/erts/emulator/beam/emu/emu_load.c +++ b/erts/emulator/beam/emu/emu_load.c @@ -1434,7 +1434,6 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { /* Remember offset for the on_load function. */ stp->on_load = ci; break; - case op_bs_put_string_WW: case op_i_bs_match_string_xfWW: case op_i_bs_match_string_yfWW: new_string_patch(stp, ci-1); diff --git a/erts/emulator/beam/emu/ops.tab b/erts/emulator/beam/emu/ops.tab index f80785269782..50dec2828f6b 100644 --- a/erts/emulator/beam/emu/ops.tab +++ b/erts/emulator/beam/emu/ops.tab @@ -1293,160 +1293,14 @@ bs_create_bin Fail Alloc=u Live=u Unit=u Dst=xy N=u Segments=* => i_bs_create_bin j I W d W * -# ================================================================ -# Old instruction for constructing binaries (up to OTP 24). -# ================================================================ - -%warm - -bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail - -bs_init2 Fail Sz Words Regs Flags Dst=y => - bs_init2 Fail Sz Words Regs Flags x | move x Dst - -bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst - -bs_init2 Fail Sz=u Words Regs Flags Dst => - i_bs_init_heap Sz Words Regs Dst - -bs_init2 Fail Sz Words=u==0 Regs Flags Dst => - i_bs_init_fail Sz Fail Regs Dst -bs_init2 Fail Sz Words Regs Flags Dst => - i_bs_init_fail_heap Sz Words Fail Regs Dst - -i_bs_init_fail xy j? t? x - -i_bs_init_fail_heap s I j? t? x - -i_bs_init W t? x - -i_bs_init_heap W I t? x - - -bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail -bs_init_bits Fail Sz Words Regs Flags Dst=y => - bs_init_bits Fail Sz Words Regs Flags x | move x Dst - -bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => - i_bs_init_bits Sz Regs Dst -bs_init_bits Fail Sz=u Words Regs Flags Dst => - i_bs_init_bits_heap Sz Words Regs Dst - -bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => - i_bs_init_bits_fail Sz Fail Regs Dst -bs_init_bits Fail Sz Words Regs Flags Dst => - i_bs_init_bits_fail_heap Sz Words Fail Regs Dst - -i_bs_init_bits_fail xy j? t? x - -i_bs_init_bits_fail_heap s I j? t? x - -i_bs_init_bits W t? x -i_bs_init_bits_heap W I t? x - -bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D - -bs_add j? s s t? x - -bs_append Fail Size Extra Live Unit Bin Flags Dst => - move Bin x | i_bs_append Fail Extra Live Unit Size Dst - -bs_private_append Fail Size Unit Bin Flags Dst => - i_bs_private_append Fail Unit Size Bin Dst - -i_bs_private_append Fail Unit Size Bin Dst=y => - i_bs_private_append Fail Unit Size Bin x | move x Dst - bs_init_writable -i_bs_append j? I t? t s xy -i_bs_private_append j? t s S x - -# -# Storing integers into binaries. -# - -bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => - put_integer(Fail, Sz, Unit, Flags, Src) - -i_new_bs_put_integer j? S t s -i_new_bs_put_integer_imm xyc j? W t - -# -# Utf8/utf16/utf32 support. (R12B-5) -# - -bs_utf8_size j Src Dst=d => i_bs_utf8_size Src Dst -bs_utf16_size j Src Dst=d => i_bs_utf16_size Src Dst - -bs_put_utf8 Fail u Src => i_bs_put_utf8 Fail Src - -bs_put_utf16 Fail Flags Src => put_utf16(Fail, Flags, Src) - -bs_put_utf32 Fail=j Flags=u Src=s => - i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src - -i_bs_utf8_size S x -i_bs_utf16_size S x - -i_bs_put_utf8 j? S -i_bs_put_utf16 j? t S - -i_bs_validate_unicode j? S - -# Handle unoptimized code and the 'native' flag for utf16 segments. -i_bs_utf8_size Src=c Dst => move Src x | i_bs_utf8_size x Dst -i_bs_utf16_size Src=c Dst => move Src x | i_bs_utf16_size x Dst -i_bs_put_utf8 Fail Src=c => move Src x | i_bs_put_utf8 Fail x -i_bs_put_utf16 Fail Flags Src=c => move Src x | i_bs_put_utf16 Fail Flags x -i_bs_validate_unicode Fail Src=c => move Src x | i_bs_validate_unicode Fail x - -# -# Storing floats into binaries. -# - -# Will fail. No need to keep the instruction, because bs_add or -# bs_init* would already have raised an exception. -bs_put_float Fail Sz=q Unit Flags Val => _ - -bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => - put_float(Fail, Sz, Unit, Flags, Src) - -i_new_bs_put_float j? S t s -i_new_bs_put_float_imm j? W t s - -# -# Storing binaries into binaries. -# - -bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => - put_binary(Fail, Sz, Unit, Flags, Src) - -# In unoptimized code, the binary argument could be a literal. (In optimized -# code, there would be a bs_put_string instruction.) -i_new_bs_put_binary Fail Size Unit Lit=c => - move Lit x | i_new_bs_put_binary Fail Size Unit x -i_new_bs_put_binary_imm Fail Size Lit=c => - move Lit x | i_new_bs_put_binary_imm Fail Size x -i_new_bs_put_binary_all Lit=c Fail Unit => - move Lit x | i_new_bs_put_binary_all x Fail Unit - -i_new_bs_put_binary j? S t S -i_new_bs_put_binary_imm j? W S -i_new_bs_put_binary_all xy j? t - -# -# Warning: The i_bs_put_string and i_new_bs_put_string instructions -# are specially treated in the loader. -# Don't change the instruction format unless you change the loader too. -# - -bs_put_string W W - # # New floating point instructions (R8). # +%warm + fadd p FR1 FR2 FR3 => i_fadd FR1 FR2 FR3 fsub p FR1 FR2 FR3 => i_fsub FR1 FR2 FR3 fmul p FR1 FR2 FR3 => i_fmul FR1 FR2 FR3 diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c index 62bfe4eb3ad1..75413225b9cf 100644 --- a/erts/emulator/beam/erl_bits.c +++ b/erts/emulator/beam/erl_bits.c @@ -923,6 +923,7 @@ erts_new_bs_put_integer(ERL_BITS_PROTO_3(Eterm arg, Uint num_bits, unsigned flag return 1; } +#if !defined(BEAMASM) int erts_bs_put_utf8(ERL_BITS_PROTO_1(Eterm arg)) { @@ -981,6 +982,7 @@ erts_bs_put_utf8(ERL_BITS_PROTO_1(Eterm arg)) return 1; } +#endif int erts_bs_put_utf16(ERL_BITS_PROTO_2(Eterm arg, Uint flags)) @@ -1475,36 +1477,6 @@ build_writable_bitstring(Process *p, * raise an exception. */ Eterm -erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, - Uint extra_words, Uint unit) -{ - Uint unsigned_bits; - Uint build_size_in_bits; - - /* - * Check and untag the requested build size. - */ - if (is_small(build_size_term)) { - Sint signed_bits = signed_val(build_size_term); - if (signed_bits < 0) { - c_p->freason = BADARG; - return THE_NON_VALUE; - } - build_size_in_bits = (Uint) signed_bits; - } else if (term_to_Uint(build_size_term, &unsigned_bits)) { - build_size_in_bits = unsigned_bits; - } else { - c_p->freason = unsigned_bits; - return THE_NON_VALUE; - } - return erts_bs_append_checked(c_p, reg, live, build_size_in_bits, - extra_words, unit); -} - -/* - * See erts_bs_append(). - */ -Eterm erts_bs_append_checked(Process* c_p, Eterm* reg, Uint live, Uint build_size_in_bits, Uint extra_words, Uint unit) @@ -1698,31 +1670,6 @@ erts_bs_append_checked(Process* c_p, Eterm* reg, Uint live, } } -Eterm -erts_bs_private_append(Process* p, Eterm bin, Eterm build_size_term, Uint unit) -{ - Uint unsigned_bits; - Uint build_size_in_bits; - - /* - * Check and untag the requested build size. - */ - if (is_small(build_size_term)) { - Sint signed_bits = signed_val(build_size_term); - if (signed_bits < 0) { - p->freason = BADARG; - return THE_NON_VALUE; - } - build_size_in_bits = (Uint) signed_bits; - } else if (term_to_Uint(build_size_term, &unsigned_bits)) { - build_size_in_bits = unsigned_bits; - } else { - p->freason = unsigned_bits; - return THE_NON_VALUE; - } - return erts_bs_private_append_checked(p, bin, build_size_in_bits, unit); -} - Eterm erts_bs_private_append_checked(Process* p, Eterm bin, Uint build_size_in_bits, Uint unit) { diff --git a/erts/emulator/beam/erl_bits.h b/erts/emulator/beam/erl_bits.h index 38bcb7781b41..619f6157e4ec 100644 --- a/erts/emulator/beam/erl_bits.h +++ b/erts/emulator/beam/erl_bits.h @@ -232,7 +232,9 @@ Eterm erts_bs_get_binary_all_2(Process *p, ErlSubBits* sb); /* Binary construction, new instruction set. */ int erts_new_bs_put_integer(ERL_BITS_PROTO_3(Eterm Integer, Uint num_bits, unsigned flags)); +#if !defined(BEAMASM) int erts_bs_put_utf8(ERL_BITS_PROTO_1(Eterm Integer)); +#endif int erts_bs_put_utf16(ERL_BITS_PROTO_2(Eterm Integer, Uint flags)); int erts_new_bs_put_binary(Process *c_p, Eterm Bin, Uint num_bits); int erts_new_bs_put_binary_all(Process *c_p, Eterm Bin, Uint unit); @@ -242,11 +244,8 @@ void erts_new_bs_put_string(ERL_BITS_PROTO_2(byte* iptr, Uint num_bytes)); Uint32 erts_bs_get_unaligned_uint32(ErlSubBits* sb); Eterm erts_bs_get_utf8(ErlSubBits* sb); Eterm erts_bs_get_utf16(ErlSubBits* sb, Uint flags); -Eterm erts_bs_append(Process* p, Eterm* reg, Uint live, Eterm build_size_term, - Uint extra_words, Uint unit); Eterm erts_bs_append_checked(Process* p, Eterm* reg, Uint live, Uint size, Uint extra_words, Uint unit); -Eterm erts_bs_private_append(Process* p, Eterm bin, Eterm sz, Uint unit); Eterm erts_bs_private_append_checked(Process* p, Eterm bin, Uint size, Uint unit); Eterm erts_bs_init_writable(Process* p, Eterm sz); diff --git a/erts/emulator/beam/generators.tab b/erts/emulator/beam/generators.tab index bdae340b68c9..e48393f2d7e3 100644 --- a/erts/emulator/beam/generators.tab +++ b/erts/emulator/beam/generators.tab @@ -81,159 +81,6 @@ gen.get_utf16(Fail, Ms, Flags, Dst) { return op; } -gen.put_binary(Fail, Size, Unit, Flags, Src) { - BeamOp* op; - $NewBeamOp(S, op); - - $NativeEndian(Flags); - if (Size.type == TAG_a && Size.val == am_all) { - $BeamOpNameArity(op, i_new_bs_put_binary_all, 3); - op->a[0] = Src; - op->a[1] = Fail; - op->a[2] = Unit; - } else if (Size.type == TAG_i) { - $BeamOpNameArity(op, i_new_bs_put_binary_imm, 3); - op->a[0] = Fail; - op->a[1].type = TAG_u; - if (beam_load_safe_mul(Size.val, Unit.val, &op->a[1].val)) { - op->a[2] = Src; - } else { - error: - /* - * Invalid size. This instruction can't possibly be - * reached, because bs_add or bs_init* would already - * have raised a system_limit exception. - */ - $BeamOpNameArity(op, delete_me, 0); - } - } else if (Size.type == TAG_q) { -#ifdef ARCH_64 - /* - * There is no way that this binary would fit in memory. - */ - goto error; -#else - Eterm big = beamfile_get_literal(&S->beam, Size.val); - Uint bigval; - Uint size; - - if (!term_to_Uint(big, &bigval) || - !beam_load_safe_mul(bigval, Unit.val, &size)) { - goto error; - } - $BeamOpNameArity(op, i_new_bs_put_binary_imm, 3); - op->a[0] = Fail; - op->a[1].type = TAG_u; - op->a[1].val = size; - op->a[2] = Src; -#endif - } else { - $BeamOpNameArity(op, i_new_bs_put_binary, 4); - op->a[0] = Fail; - op->a[1] = Size; - op->a[2].type = TAG_u; - op->a[2].val = (Unit.val << 3) | (Flags.val & 7); - op->a[3] = Src; - } - - return op; -} - -gen.put_integer(Fail, Size, Unit, Flags, Src) { - BeamOp* op; - $NewBeamOp(S, op); - - $NativeEndian(Flags); - /* Negative size must fail */ - if (Size.type == TAG_i) { - Uint size; - if (!beam_load_safe_mul(Size.val, Unit.val, &size)) { - error: - /* - * Invalid size. This instruction can't possibly be - * reached, because bs_add or bs_init* would already - * have raised a system_limit exception. - */ - $BeamOpNameArity(op, delete_me, 0); - return op; - } - $BeamOpNameArity(op, i_new_bs_put_integer_imm, 4); - op->a[0] = Src; - op->a[1] = Fail; - op->a[2].type = TAG_u; - op->a[2].val = size; - op->a[3].type = Flags.type; - op->a[3].val = (Flags.val & 7); - } else if (Size.type == TAG_q) { - Eterm big = beamfile_get_literal(&S->beam, Size.val); - Uint bigval; - Uint size; - - if (!term_to_Uint(big, &bigval) || - !beam_load_safe_mul(bigval, Unit.val, &size)) { - goto error; - } - $BeamOpNameArity(op, i_new_bs_put_integer_imm, 4); - op->a[0] = Src; - op->a[1] = Fail; - op->a[2].type = TAG_u; - op->a[2].val = size; - op->a[3].type = Flags.type; - op->a[3].val = (Flags.val & 7); - } else { - $BeamOpNameArity(op, i_new_bs_put_integer, 4); - op->a[0] = Fail; - op->a[1] = Size; - op->a[2].type = TAG_u; - op->a[2].val = (Unit.val << 3) | (Flags.val & 7); - op->a[3] = Src; - } - return op; -} - -gen.put_float(Fail, Size, Unit, Flags, Src) { - BeamOp* op; - $NewBeamOp(S, op); - - $NativeEndian(Flags); - if (Size.type == TAG_i) { - $BeamOpNameArity(op, i_new_bs_put_float_imm, 4); - op->a[0] = Fail; - op->a[1].type = TAG_u; - if (!beam_load_safe_mul(Size.val, Unit.val, &op->a[1].val)) { - /* - * Size overflow. This instruction can't possibly be reached, because - * bs_add or bs_init* would already have raised a system_limit - * exception. - */ - $BeamOpNameArity(op, delete_me, 0); - } else { - op->a[2] = Flags; - op->a[3] = Src; - } - } else { - $BeamOpNameArity(op, i_new_bs_put_float, 4); - op->a[0] = Fail; - op->a[1] = Size; - op->a[2].type = TAG_u; - op->a[2].val = (Unit.val << 3) | (Flags.val & 7); - op->a[3] = Src; - } - return op; -} - -gen.put_utf16(Fail, Flags, Src) { - BeamOp* op; - $NewBeamOp(S, op); - - $NativeEndian(Flags); - $BeamOpNameArity(op, i_bs_put_utf16, 3); - op->a[0] = Fail; - op->a[1] = Flags; - op->a[2] = Src; - return op; -} - // Generate the fastest instruction for bs_skip_bits. gen.skip_bits2(Fail, Ms, Size, Unit, Flags) { BeamOp* op; diff --git a/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl b/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl index 2bce940a7131..758303c1d312 100644 --- a/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl +++ b/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl @@ -34,8 +34,6 @@ bif_is_ne_exact_shared bif_tuple_size_body bif_tuple_size_guard - bs_add_guard_shared - bs_add_body_shared bs_create_bin_error_shared bs_get_tail_shared bs_get_utf8_shared diff --git a/erts/emulator/beam/jit/arm/instr_bs.cpp b/erts/emulator/beam/jit/arm/instr_bs.cpp index 0bdaad1744ce..f6a84591c998 100644 --- a/erts/emulator/beam/jit/arm/instr_bs.cpp +++ b/erts/emulator/beam/jit/arm/instr_bs.cpp @@ -112,13 +112,6 @@ int BeamModuleAssembler::emit_bs_get_field_size(const ArgSource &Size, } } -void BeamModuleAssembler::emit_i_bs_init_heap(const ArgWord &Size, - const ArgWord &Heap, - const ArgWord &Live, - const ArgRegister &Dst) { - emit_i_bs_init_bits_heap(ArgWord(Size.get() * 8), Heap, Live, Dst); -} - /* Set the error reason when a size check has failed. */ void BeamGlobalAssembler::emit_bs_size_check_shared() { emit_enter_runtime_frame(); @@ -134,349 +127,6 @@ void BeamGlobalAssembler::emit_bs_size_check_shared() { a.b(labels[raise_exception]); } -void BeamModuleAssembler::emit_i_bs_init_fail_heap(const ArgSource &Size, - const ArgWord &Heap, - const ArgLabel &Fail, - const ArgWord &Live, - const ArgRegister &Dst) { - Label fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail, dispUnknown); - } else { - fail = a.newLabel(); - } - - if (emit_bs_get_field_size(Size, 1, fail, ARG4) >= 0) { - a.lsl(ARG4, ARG4, imm(3)); - mov_arg(ARG5, Heap); - mov_arg(ARG6, Live); - fragment_call(ga->get_bs_init_bits_shared()); - mov_arg(Dst, ARG1); - } - - if (Fail.get() == 0) { - Label next = a.newLabel(); - - a.b(next); - - a.bind(fail); - { - mov_arg(ARG2, Size); - fragment_call(ga->get_bs_size_check_shared()); - } - - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_bs_init(const ArgWord &Size, - const ArgWord &Live, - const ArgRegister &Dst) { - const ArgVal Heap(ArgVal::Word, 0); - emit_i_bs_init_heap(Size, Heap, Live, Dst); -} - -void BeamModuleAssembler::emit_i_bs_init_fail(const ArgRegister &Size, - const ArgLabel &Fail, - const ArgWord &Live, - const ArgRegister &Dst) { - const ArgVal Heap(ArgVal::Word, 0); - emit_i_bs_init_fail_heap(Size, Heap, Fail, Live, Dst); -} - -void BeamModuleAssembler::emit_i_bs_init_bits(const ArgWord &NumBits, - const ArgWord &Live, - const ArgRegister &Dst) { - const ArgVal heap(ArgVal::Word, 0); - emit_i_bs_init_bits_heap(NumBits, heap, Live, Dst); -} - -void BeamModuleAssembler::emit_i_bs_init_bits_heap(const ArgWord &NumBits, - const ArgWord &Alloc, - const ArgWord &Live, - const ArgRegister &Dst) { - mov_arg(ARG4, NumBits); - mov_arg(ARG5, Alloc); - mov_arg(ARG6, Live); - fragment_call(ga->get_bs_init_bits_shared()); - mov_arg(Dst, ARG1); -} - -void BeamModuleAssembler::emit_i_bs_init_bits_fail(const ArgRegister &NumBits, - const ArgLabel &Fail, - const ArgWord &Live, - const ArgRegister &Dst) { - const ArgVal Heap(ArgVal::Word, 0); - - emit_i_bs_init_bits_fail_heap(NumBits, Heap, Fail, Live, Dst); -} - -void BeamModuleAssembler::emit_i_bs_init_bits_fail_heap( - const ArgSource &NumBits, - const ArgWord &Alloc, - const ArgLabel &Fail, - const ArgWord &Live, - const ArgRegister &Dst) { - Label fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail, dispUnknown); - } else { - fail = a.newLabel(); - } - - if (emit_bs_get_field_size(NumBits, 1, fail, ARG4) >= 0) { - mov_arg(ARG5, Alloc); - mov_arg(ARG6, Live); - fragment_call(ga->get_bs_init_bits_shared()); - mov_arg(Dst, ARG1); - } - - if (Fail.get() == 0) { - Label next = a.newLabel(); - - a.b(next); - a.bind(fail); - { - mov_arg(ARG2, NumBits); - fragment_call(ga->get_bs_size_check_shared()); - } - - a.bind(next); - } -} - -void BeamModuleAssembler::emit_bs_put_string(const ArgWord &Size, - const ArgBytePtr &Ptr) { - mov_arg(ARG2, Ptr); - mov_arg(ARG3, Size); - - emit_enter_runtime(); - - load_erl_bits_state(ARG1); - runtime_call<3>(erts_new_bs_put_string); - - emit_leave_runtime(); -} - -void BeamModuleAssembler::emit_i_new_bs_put_integer_imm(const ArgSource &Src, - const ArgLabel &Fail, - const ArgWord &Sz, - const ArgWord &Flags) { - mov_arg(ARG2, Src); - mov_arg(ARG3, Sz); - mov_arg(ARG4, Flags); - - emit_enter_runtime(); - - load_erl_bits_state(ARG1); - runtime_call<4>(erts_new_bs_put_integer); - - emit_leave_runtime(); - - if (Fail.get() != 0) { - a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); - } else { - Label next = a.newLabel(); - - a.cbnz(ARG1, next); - emit_error(BADARG); - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_integer(const ArgLabel &Fail, - const ArgRegister &Sz, - const ArgWord &Flags, - const ArgSource &Src) { - int unit = Flags.get() >> 3; - Label next, fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail, dispUnknown); - } else { - fail = a.newLabel(); - next = a.newLabel(); - } - - /* Clobbers RET + ARG3 */ - if (emit_bs_get_field_size(Sz, unit, fail, ARG3) >= 0) { - mov_arg(ARG2, Src); - mov_arg(ARG4, Flags); - - emit_enter_runtime(); - - load_erl_bits_state(ARG1); - runtime_call<4>(erts_new_bs_put_integer); - - emit_leave_runtime(); - - if (Fail.get() != 0) { - a.cbz(ARG1, fail); - } else { - a.cbnz(ARG1, next); - } - } - - if (Fail.get() == 0) { - a.bind(fail); - emit_error(BADARG); - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_binary(const ArgLabel &Fail, - const ArgSource &Sz, - const ArgWord &Flags, - const ArgSource &Src) { - int unit = Flags.get() >> 3; - Label next, fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail, dispUnknown); - } else { - fail = a.newLabel(); - next = a.newLabel(); - } - - if (emit_bs_get_field_size(Sz, unit, fail, ARG3) >= 0) { - mov_arg(ARG2, Src); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<3>(erts_new_bs_put_binary); - - emit_leave_runtime(); - - if (Fail.get() != 0) { - a.cbz(ARG1, fail); - } else { - a.cbnz(ARG1, next); - } - } - - if (Fail.get() == 0) { - a.bind(fail); - emit_error(BADARG); - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_binary_all(const ArgSource &Src, - const ArgLabel &Fail, - const ArgWord &Unit) { - mov_arg(ARG2, Src); - mov_arg(ARG3, Unit); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<3>(erts_new_bs_put_binary_all); - - emit_leave_runtime(); - - if (Fail.get() == 0) { - Label next = a.newLabel(); - - a.cbnz(ARG1, next); - emit_error(BADARG); - a.bind(next); - } else { - a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_binary_imm(const ArgLabel &Fail, - const ArgWord &Sz, - const ArgSource &Src) { - mov_arg(ARG2, Src); - mov_arg(ARG3, Sz); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<3>(erts_new_bs_put_binary); - - emit_leave_runtime(); - - if (Fail.get() == 0) { - Label next = a.newLabel(); - - a.cbnz(ARG1, next); - emit_error(BADARG); - a.bind(next); - } else { - a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_float(const ArgLabel &Fail, - const ArgRegister &Sz, - const ArgWord &Flags, - const ArgSource &Src) { - int unit = Flags.get() >> 3; - Label next, fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail, dispUnknown); - } else { - fail = a.newLabel(); - next = a.newLabel(); - } - - if (emit_bs_get_field_size(Sz, unit, fail, ARG3) >= 0) { - mov_arg(ARG2, Src); - mov_arg(ARG4, Flags); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<4>(erts_new_bs_put_float); - - emit_leave_runtime(); - - if (Fail.get() != 0) { - emit_branch_if_value(ARG1, fail); - } else { - emit_branch_if_not_value(ARG1, next); - } - } - - if (Fail.get() == 0) { - a.bind(fail); - emit_error(BADARG); - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_float_imm(const ArgLabel &Fail, - const ArgWord &Sz, - const ArgWord &Flags, - const ArgSource &Src) { - mov_arg(ARG2, Src); - mov_arg(ARG3, Sz); - mov_arg(ARG4, Flags); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<4>(erts_new_bs_put_float); - - emit_leave_runtime(); - - if (Fail.get() != 0) { - emit_branch_if_value(ARG1, resolve_beam_label(Fail, disp1MB)); - } else { - Label next = a.newLabel(); - - emit_branch_if_not_value(ARG1, next); - emit_error(BADARG); - a.bind(next); - } -} - void BeamModuleAssembler::emit_i_bs_start_match3(const ArgRegister &Src, const ArgWord &Live, const ArgLabel &Fail, @@ -939,56 +589,6 @@ void BeamModuleAssembler::emit_i_bs_get_float2(const ArgRegister &Ctx, } } -void BeamModuleAssembler::emit_i_bs_utf8_size(const ArgSource &Src, - const ArgXRegister &Dst) { - auto src_reg = load_source(Src, TMP1); - auto dst_reg = init_destination(Dst, TMP2); - - Label next = a.newLabel(); - - /* Note that the source and destination registers could be the - * same register. Therefore, we must copy the source register - * before writing to the destination register. */ - a.lsr(TMP1, src_reg.reg, imm(_TAG_IMMED1_SIZE)); - mov_imm(dst_reg.reg, make_small(1)); - a.cmp(TMP1, imm(0x7F)); - a.b_ls(next); - - mov_imm(dst_reg.reg, make_small(2)); - a.cmp(TMP1, imm(0x7FFUL)); - a.b_ls(next); - - a.cmp(TMP1, imm(0x10000UL)); - mov_imm(TMP2, make_small(3)); - mov_imm(TMP3, make_small(4)); - a.csel(dst_reg.reg, TMP2, TMP3, arm::CondCode::kLO); - - a.bind(next); - flush_var(dst_reg); -} - -void BeamModuleAssembler::emit_i_bs_put_utf8(const ArgLabel &Fail, - const ArgSource &Src) { - mov_arg(ARG2, Src); - - emit_enter_runtime(); - - load_erl_bits_state(ARG1); - runtime_call<2>(erts_bs_put_utf8); - - emit_leave_runtime(); - - if (Fail.get() != 0) { - a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); - } else { - Label next = a.newLabel(); - - a.cbnz(ARG1, next); - emit_error(BADARG); - a.bind(next); - } -} - /* * ARG1 = pointer to match state * ARG2 = number of bits left in binary (< 32) @@ -1282,46 +882,6 @@ void BeamModuleAssembler::emit_i_bs_skip_utf8(const ArgRegister &Ctx, emit_bs_get_utf8(Ctx, Fail); } -void BeamModuleAssembler::emit_i_bs_utf16_size(const ArgSource &Src, - const ArgXRegister &Dst) { - auto src_reg = load_source(Src, TMP1); - auto dst_reg = init_destination(Dst, TMP2); - - /* erts_bs_put_utf16 errors out whenever something's fishy, so we can - * return garbage (2 or 4) if our input is not a small. */ - a.asr(TMP1, src_reg.reg, imm(_TAG_IMMED1_SIZE)); - a.cmp(TMP1, imm(0x10000UL)); - mov_imm(TMP1, make_small(2)); - mov_imm(TMP2, make_small(4)); - a.csel(dst_reg.reg, TMP1, TMP2, arm::CondCode::kLO); - - flush_var(dst_reg); -} - -void BeamModuleAssembler::emit_i_bs_put_utf16(const ArgLabel &Fail, - const ArgWord &Flags, - const ArgSource &Src) { - mov_arg(ARG2, Src); - mov_arg(ARG3, Flags); - - emit_enter_runtime(); - - load_erl_bits_state(ARG1); - runtime_call<3>(erts_bs_put_utf16); - - emit_leave_runtime(); - - if (Fail.get() != 0) { - a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); - } else { - Label next = a.newLabel(); - - a.cbnz(ARG1, next); - emit_error(BADARG); - a.bind(next); - } -} - void BeamModuleAssembler::emit_bs_get_utf16(const ArgRegister &Ctx, const ArgLabel &Fail, const ArgWord &Flags) { @@ -1377,27 +937,6 @@ void BeamModuleAssembler::emit_validate_unicode(Label next, a.b(next); } -void BeamModuleAssembler::emit_i_bs_validate_unicode(const ArgLabel &Fail, - const ArgSource &Src) { - auto src_reg = load_source(Src, TMP1); - Label fail, next = a.newLabel(); - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail, dispUnknown); - } else { - fail = a.newLabel(); - } - - emit_validate_unicode(next, fail, src_reg.reg); - - if (Fail.get() == 0) { - a.bind(fail); - emit_error(BADARG); - } - - a.bind(next); -} - void BeamModuleAssembler::emit_i_bs_validate_unicode_retract( const ArgLabel &Fail, const ArgSource &Src, @@ -1450,182 +989,6 @@ void BeamModuleAssembler::emit_bs_test_unit(const ArgLabel &Fail, } } -/* ARG2 = current `Size`, - * ARG3 = elements to `Add`, - * ARG4 = element `Unit` - * - * Error is indicated through cond_ne() */ -void BeamGlobalAssembler::emit_bs_add_guard_shared() { - Label error = a.newLabel(); - - /* Since `Unit` is guaranteed to be less than 1024, we can check overflow - * and negative numbers by testing whether any of the highest 12 value bits - * are set on either argument. */ - a.orr(TMP1, ARG2, ARG3); - a.tst(TMP1, imm(0xFFF0000000000000UL)); - - a.and_(TMP1, ARG2, ARG3); - a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); - a.ccmp(TMP1, - imm(_TAG_IMMED1_SMALL), - imm(NZCV::kNone), - imm(arm::CondCode::kEQ)); - a.b_ne(error); - - /* Return `Size` + `Add` * `Unit` - * - * Note that the result takes the tag bits from `Size` */ - a.and_(TMP2, ARG3, imm(~_TAG_IMMED1_SMALL)); - a.mul(TMP2, TMP2, ARG4); - a.add(ARG1, TMP2, ARG2); - - a.bind(error); - a.ret(a64::x30); -} - -/* ARG2 = current `Size`, - * ARG3 = elements to `Add`, - * ARG4 = element `Unit` */ -void BeamGlobalAssembler::emit_bs_add_body_shared() { - Label error = a.newLabel(); - - /* Since `Unit` is guaranteed to be less than 1024, we can check overflow - * and negative numbers by testing whether any of the highest 12 value bits - * are set on either argument. */ - a.orr(TMP1, ARG2, ARG3); - a.tst(TMP1, imm(0xFFF0000000000000UL)); - - a.and_(TMP1, ARG2, ARG3); - a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); - a.ccmp(TMP1, - imm(_TAG_IMMED1_SMALL), - imm(NZCV::kNone), - imm(arm::CondCode::kEQ)); - a.b_ne(error); - - /* Return `Size` + `Add` * `Unit` - * - * Note that the result takes the tag bits from `Size` */ - a.and_(TMP2, ARG3, imm(~_TAG_IMMED1_SMALL)); - a.mul(TMP2, TMP2, ARG4); - a.add(ARG1, TMP2, ARG2); - a.ret(a64::x30); - - a.bind(error); - { - emit_enter_runtime_frame(); - emit_enter_runtime(0); - - a.mov(ARG1, c_p); - runtime_call<3>(beam_jit_bs_add_argument_error); - - emit_leave_runtime(0); - emit_leave_runtime_frame(); - - mov_imm(ARG4, 0); - a.b(labels[raise_exception]); - } -} - -void BeamModuleAssembler::emit_bs_add(const ArgLabel &Fail, - const ArgSource &Size, - const ArgSource &Add, - const ArgWord &Unit, - const ArgXRegister &Dst) { - ASSERT(Unit.get() < 1024); - - mov_arg(ARG2, Size); - mov_arg(ARG3, Add); - mov_arg(ARG4, Unit); - - if (Fail.get() == 0) { - fragment_call(ga->get_bs_add_body_shared()); - } else { - fragment_call(ga->get_bs_add_guard_shared()); - a.b_ne(resolve_beam_label(Fail, disp1MB)); - } - - mov_arg(Dst, ARG1); -} - -void BeamModuleAssembler::emit_i_bs_append(const ArgLabel &Fail, - const ArgWord &ExtraHeap, - const ArgWord &Live, - const ArgWord &Unit, - const ArgSource &Size, - const ArgSource &Bin, - const ArgRegister &Dst) { - Label next = a.newLabel(); - - mov_arg(ARG3, Live); - mov_arg(ARG4, Size); - mov_arg(ARG5, ExtraHeap); - mov_arg(ARG6, Unit); - - mov_arg(ArgXRegister(Live.get()), Bin); - - emit_enter_runtime(Live.get() + 1); - - a.mov(ARG1, c_p); - load_x_reg_array(ARG2); - runtime_call<6>(erts_bs_append); - - emit_leave_runtime(Live.get() + 1); - - emit_branch_if_value(ARG1, next); - - if (Fail.get() != 0) { - /* Test whether the max_heap_size limit has been exceeded. */ - a.ldr(TMP1.w(), arm::Mem(c_p, offsetof(Process, state.value))); - a.tst(TMP1, imm(ERTS_PSFLG_EXITING)); - a.b_eq(resolve_beam_label(Fail, disp1MB)); - a.b(resolve_fragment(ga->get_do_schedule(), disp128MB)); - } else { - a.ldr(TMP1.w(), arm::Mem(c_p, offsetof(Process, state.value))); - a.tst(TMP1, imm(ERTS_PSFLG_EXITING)); - a.b_ne(resolve_fragment(ga->get_do_schedule(), disp1MB)); - - /* The error has been prepared in `erts_bs_append` */ - emit_raise_exception(); - } - - a.bind(next); - mov_arg(Dst, ARG1); -} - -void BeamModuleAssembler::emit_i_bs_private_append(const ArgLabel &Fail, - const ArgWord &Unit, - const ArgSource &Size, - const ArgRegister &Src, - const ArgXRegister &Dst) { - mov_arg(ARG2, Src); - mov_arg(ARG3, Size); - mov_arg(ARG4, Unit); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<4>(erts_bs_private_append); - - emit_leave_runtime(); - - if (Fail.get() != 0) { - emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); - } else { - Label next = a.newLabel(); - - emit_branch_if_value(ARG1, next); - /* The error has been prepared in `erts_bs_private_append` */ - emit_raise_exception(); - - a.bind(next); - } - - mov_arg(Dst, ARG1); -} - void BeamModuleAssembler::emit_bs_init_writable() { ERTS_CT_ASSERT(ERTS_HIGHEST_CALLEE_SAVE_XREG >= 0); diff --git a/erts/emulator/beam/jit/arm/ops.tab b/erts/emulator/beam/jit/arm/ops.tab index e7fe14477251..7212e19e056a 100644 --- a/erts/emulator/beam/jit/arm/ops.tab +++ b/erts/emulator/beam/jit/arm/ops.tab @@ -1083,138 +1083,15 @@ bs_create_bin Fail=j Alloc=u Live=u Unit=u Dst=xy N=u Segments=* => i_bs_create_bin j I t d * -# ================================================================ -# Old instruction for constructing binaries (up to OTP 24). -# ================================================================ - -%warm - -bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail - -bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst - -bs_init2 Fail Sz=u Words Regs Flags Dst => - i_bs_init_heap Sz Words Regs Dst - -bs_init2 Fail Sz Words=u==0 Regs Flags Dst => - i_bs_init_fail Sz Fail Regs Dst -bs_init2 Fail Sz Words Regs Flags Dst => - i_bs_init_fail_heap Sz Words Fail Regs Dst - -i_bs_init_fail S j t S - -i_bs_init_fail_heap s I j t S - -i_bs_init W t S - -i_bs_init_heap W I t S - - -bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail - -bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => - i_bs_init_bits Sz Regs Dst -bs_init_bits Fail Sz=u Words Regs Flags Dst => - i_bs_init_bits_heap Sz Words Regs Dst - -bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => - i_bs_init_bits_fail Sz Fail Regs Dst -bs_init_bits Fail Sz Words Regs Flags Dst => - i_bs_init_bits_fail_heap Sz Words Fail Regs Dst - -i_bs_init_bits_fail S j t S - -i_bs_init_bits_fail_heap s I j t S - -i_bs_init_bits W t S -i_bs_init_bits_heap W I t S - -bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D - -bs_add j s s t x - -bs_append Fail Size Extra Live Unit Bin Flags Dst => - i_bs_append Fail Extra Live Unit Size Bin Dst - -bs_private_append Fail Size Unit Bin Flags Dst => - i_bs_private_append Fail Unit Size Bin Dst - -i_bs_private_append Fail Unit Size Bin Dst=y => - i_bs_private_append Fail Unit Size Bin x | move x Dst - bs_init_writable -i_bs_append j I t t s s S -i_bs_private_append j t s S x - -# -# Storing integers into binaries. -# - -bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => - put_integer(Fail, Sz, Unit, Flags, Src) - -i_new_bs_put_integer j S t s -i_new_bs_put_integer_imm s j W t - -# -# Utf8/utf16/utf32 support. (R12B-5) -# - -bs_utf8_size j Src Dst=d => i_bs_utf8_size Src Dst -bs_utf16_size j Src Dst=d => i_bs_utf16_size Src Dst - -bs_put_utf8 Fail u Src => i_bs_put_utf8 Fail Src -bs_put_utf16 Fail Flags Src => put_utf16(Fail, Flags, Src) - -bs_put_utf32 Fail=j Flags=u Src=s => - i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src - -i_bs_utf8_size s x -i_bs_utf16_size s x - -i_bs_put_utf8 j s -i_bs_put_utf16 j t s - -i_bs_validate_unicode j s - -# -# Storing floats into binaries. -# - -# Will fail. No need to keep the instruction, because bs_add or -# bs_init* would already have raised an exception. -bs_put_float Fail Sz=q Unit Flags Val => _ - -bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => - put_float(Fail, Sz, Unit, Flags, Src) - -i_new_bs_put_float j S t s -i_new_bs_put_float_imm j W t s - -# -# Storing binaries into binaries. -# - -bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => - put_binary(Fail, Sz, Unit, Flags, Src) - -i_new_bs_put_binary j s t s -i_new_bs_put_binary_imm j W s -i_new_bs_put_binary_all s j t - -# -# Warning: The i_bs_put_string and i_new_bs_put_string instructions -# are specially treated in the loader. -# Don't change the instruction format unless you change the loader too. -# - -bs_put_string W M # # New floating point instructions (R8). # +%warm + fadd p FR1 FR2 FR3 => i_fadd FR1 FR2 FR3 fsub p FR1 FR2 FR3 => i_fsub FR1 FR2 FR3 fmul p FR1 FR2 FR3 => i_fmul FR1 FR2 FR3 diff --git a/erts/emulator/beam/jit/beam_jit_common.hpp b/erts/emulator/beam/jit/beam_jit_common.hpp index 6f6422d46094..73ea6a22773b 100644 --- a/erts/emulator/beam/jit/beam_jit_common.hpp +++ b/erts/emulator/beam/jit/beam_jit_common.hpp @@ -598,12 +598,6 @@ Uint beam_jit_get_map_elements(Eterm map, void beam_jit_bs_field_size_argument_error(Process *c_p, Eterm size); void beam_jit_bs_add_argument_error(Process *c_p, Eterm A, Eterm B); -Eterm beam_jit_bs_init(Process *c_p, - Eterm *reg, - ERL_BITS_DECLARE_STATEP, - Eterm num_bytes, - Uint alloc, - unsigned Live); Eterm beam_jit_bs_init_bits(Process *c_p, Eterm *reg, ERL_BITS_DECLARE_STATEP, diff --git a/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl b/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl index 86d46dd8ab52..26b8f8791b18 100755 --- a/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl +++ b/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl @@ -28,14 +28,12 @@ bif_nif_epilogue bif_element_shared bif_export_trap - bs_add_shared bs_create_bin_error_shared bs_size_check_shared bs_get_tail_shared bs_get_utf8_shared bs_get_utf8_short_shared bs_init_bits_shared - bs_init_bits_legacy_shared call_bif_shared call_light_bif_shared call_nif_early diff --git a/erts/emulator/beam/jit/x86/instr_bs.cpp b/erts/emulator/beam/jit/x86/instr_bs.cpp index 568dcf7e82f2..d3c9e1c050d6 100644 --- a/erts/emulator/beam/jit/x86/instr_bs.cpp +++ b/erts/emulator/beam/jit/x86/instr_bs.cpp @@ -122,19 +122,6 @@ int BeamModuleAssembler::emit_bs_get_field_size(const ArgSource &Size, } } -void BeamModuleAssembler::emit_i_bs_init_heap(const ArgWord &Size, - const ArgWord &Heap, - const ArgWord &Live, - const ArgRegister &Dst) { - mov_arg(ARG4, ArgWord(Size.get() * 8)); - mov_arg(ARG5, Heap); - mov_arg(ARG6, Live); - - fragment_call(ga->get_bs_init_bits_legacy_shared()); - - mov_arg(Dst, RET); -} - /* Set the error reason when a size check has failed. */ void BeamGlobalAssembler::emit_bs_size_check_shared() { emit_enter_runtime(); @@ -144,390 +131,6 @@ void BeamGlobalAssembler::emit_bs_size_check_shared() { a.ret(); } -void BeamModuleAssembler::emit_i_bs_init_fail_heap(const ArgSource &Size, - const ArgWord &Heap, - const ArgLabel &Fail, - const ArgWord &Live, - const ArgRegister &Dst) { - Label fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail); - } else { - fail = a.newLabel(); - } - - /* Clobbers RET + ARG3 */ - if (emit_bs_get_field_size(Size, 1, fail, ARG4) >= 0) { - a.shl(ARG4, imm(3)); - mov_arg(ARG5, Heap); - mov_arg(ARG6, Live); - fragment_call(ga->get_bs_init_bits_legacy_shared()); - mov_arg(Dst, RET); - } - - if (Fail.get() == 0) { - Label next = a.newLabel(); - a.short_().jmp(next); - - a.bind(fail); - { - mov_arg(ARG2, Size); - safe_fragment_call(ga->get_bs_size_check_shared()); - emit_raise_exception(); - } - - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_bs_init(const ArgWord &Size, - const ArgWord &Live, - const ArgRegister &Dst) { - const ArgVal Heap(ArgVal::Word, 0); - - emit_i_bs_init_bits_heap(ArgWord(Size.get() * 8), Heap, Live, Dst); -} - -void BeamModuleAssembler::emit_i_bs_init_fail(const ArgRegister &Size, - const ArgLabel &Fail, - const ArgWord &Live, - const ArgRegister &Dst) { - const ArgVal Heap(ArgVal::Word, 0); - - emit_i_bs_init_fail_heap(Size, Heap, Fail, Live, Dst); -} - -void BeamModuleAssembler::emit_i_bs_init_bits(const ArgWord &NumBits, - const ArgWord &Live, - const ArgRegister &Dst) { - const ArgVal heap(ArgVal::Word, 0); - emit_i_bs_init_bits_heap(NumBits, heap, Live, Dst); -} - -void BeamModuleAssembler::emit_i_bs_init_bits_heap(const ArgWord &NumBits, - const ArgWord &Alloc, - const ArgWord &Live, - const ArgRegister &Dst) { - mov_arg(ARG4, NumBits); - mov_arg(ARG5, Alloc); - mov_arg(ARG6, Live); - - fragment_call(ga->get_bs_init_bits_legacy_shared()); - - mov_arg(Dst, RET); -} - -void BeamModuleAssembler::emit_i_bs_init_bits_fail(const ArgRegister &NumBits, - const ArgLabel &Fail, - const ArgWord &Live, - const ArgRegister &Dst) { - const ArgVal Heap(ArgVal::Word, 0); - - emit_i_bs_init_bits_fail_heap(NumBits, Heap, Fail, Live, Dst); -} - -void BeamModuleAssembler::emit_i_bs_init_bits_fail_heap( - const ArgSource &NumBits, - const ArgWord &Alloc, - const ArgLabel &Fail, - const ArgWord &Live, - const ArgRegister &Dst) { - Label fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail); - } else { - fail = a.newLabel(); - } - - /* Clobbers RET + ARG3 */ - if (emit_bs_get_field_size(NumBits, 1, fail, ARG4) >= 0) { - mov_arg(ARG5, Alloc); - mov_arg(ARG6, Live); - - fragment_call(ga->get_bs_init_bits_legacy_shared()); - - mov_arg(Dst, RET); - } - - if (Fail.get() == 0) { - Label next = a.newLabel(); - a.short_().jmp(next); - - a.bind(fail); - { - mov_arg(ARG2, NumBits); - safe_fragment_call(ga->get_bs_size_check_shared()); - emit_raise_exception(); - } - - a.bind(next); - } -} - -void BeamModuleAssembler::emit_bs_put_string(const ArgWord &Size, - const ArgBytePtr &Ptr) { - mov_arg(ARG3, Size); - - emit_enter_runtime(); - - mov_arg(ARG2, Ptr); - load_erl_bits_state(ARG1); - runtime_call<3>(erts_new_bs_put_string); - - emit_leave_runtime(); -} - -void BeamModuleAssembler::emit_i_new_bs_put_integer_imm(const ArgSource &Src, - const ArgLabel &Fail, - const ArgWord &Sz, - const ArgWord &Flags) { - Label next; - - if (Fail.get() == 0) { - next = a.newLabel(); - } - - mov_arg(ARG2, Src); - mov_arg(ARG3, Sz); - mov_arg(ARG4, Flags); - - emit_enter_runtime(); - - load_erl_bits_state(ARG1); - runtime_call<4>(erts_new_bs_put_integer); - - emit_leave_runtime(); - - a.test(RET, RET); - - if (Fail.get() != 0) { - a.je(resolve_beam_label(Fail)); - } else { - a.short_().jne(next); - emit_error(BADARG); - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_integer(const ArgLabel &Fail, - const ArgRegister &Sz, - const ArgWord &Flags, - const ArgSource &Src) { - int unit = Flags.get() >> 3; - Label next, fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail); - } else { - fail = a.newLabel(); - next = a.newLabel(); - } - - /* Clobbers RET + ARG3 */ - if (emit_bs_get_field_size(Sz, unit, fail, ARG3) >= 0) { - mov_arg(ARG2, Src); - mov_arg(ARG4, Flags); - - emit_enter_runtime(); - - load_erl_bits_state(ARG1); - runtime_call<4>(erts_new_bs_put_integer); - - emit_leave_runtime(); - - a.test(RET, RET); - - if (Fail.get() != 0) { - a.je(fail); - } else { - a.short_().jne(next); - } - } - - if (Fail.get() == 0) { - a.bind(fail); - emit_error(BADARG); - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_binary(const ArgLabel &Fail, - const ArgSource &Sz, - const ArgWord &Flags, - const ArgSource &Src) { - int unit = Flags.get() >> 3; - Label next, fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail); - } else { - fail = a.newLabel(); - next = a.newLabel(); - } - - /* Clobbers RET + ARG3 */ - if (emit_bs_get_field_size(Sz, unit, fail, ARG3) >= 0) { - mov_arg(ARG2, Src); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<3>(erts_new_bs_put_binary); - - emit_leave_runtime(); - - a.test(RET, RET); - - if (Fail.get() != 0) { - a.je(fail); - } else { - a.short_().jne(next); - } - } - - if (Fail.get() == 0) { - a.bind(fail); - emit_error(BADARG); - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_binary_all(const ArgSource &Src, - const ArgLabel &Fail, - const ArgWord &Unit) { - Label next; - - if (Fail.get() == 0) { - next = a.newLabel(); - } - - mov_arg(ARG2, Src); - mov_arg(ARG3, Unit); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<3>(erts_new_bs_put_binary_all); - - emit_leave_runtime(); - - a.test(RET, RET); - - if (Fail.get() == 0) { - a.jne(next); - emit_error(BADARG); - a.bind(next); - } else { - a.je(resolve_beam_label(Fail)); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_binary_imm(const ArgLabel &Fail, - const ArgWord &Sz, - const ArgSource &Src) { - Label next; - - if (Fail.get() == 0) { - next = a.newLabel(); - } - - mov_arg(ARG2, Src); - mov_arg(ARG3, Sz); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<3>(erts_new_bs_put_binary); - - emit_leave_runtime(); - - a.test(RET, RET); - - if (Fail.get() == 0) { - a.short_().jne(next); - emit_error(BADARG); - a.bind(next); - } else { - a.je(resolve_beam_label(Fail)); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_float(const ArgLabel &Fail, - const ArgRegister &Sz, - const ArgWord &Flags, - const ArgSource &Src) { - int unit = Flags.get() >> 3; - Label next, fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail); - } else { - fail = a.newLabel(); - next = a.newLabel(); - } - - /* Clobbers RET + ARG3 */ - if (emit_bs_get_field_size(Sz, unit, fail, ARG3) >= 0) { - mov_arg(ARG2, Src); - mov_arg(ARG4, Flags); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<4>(erts_new_bs_put_float); - - emit_leave_runtime(); - - emit_test_the_non_value(RET); - - if (Fail.get() != 0) { - a.jne(fail); - } else { - a.short_().je(next); - } - } - - if (Fail.get() == 0) { - a.bind(fail); - emit_error(BADARG); - a.bind(next); - } -} - -void BeamModuleAssembler::emit_i_new_bs_put_float_imm(const ArgLabel &Fail, - const ArgWord &Sz, - const ArgWord &Flags, - const ArgSource &Src) { - Label next; - - if (Fail.get() == 0) { - next = a.newLabel(); - } - - mov_arg(ARG2, Src); - mov_arg(ARG3, Sz); - mov_arg(ARG4, Flags); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<4>(erts_new_bs_put_float); - - emit_leave_runtime(); - - emit_test_the_non_value(RET); - - if (Fail.get() != 0) { - a.jne(resolve_beam_label(Fail)); - } else { - a.short_().je(next); - emit_error(BADARG); - a.bind(next); - } -} - void BeamModuleAssembler::emit_i_bs_start_match3(const ArgRegister &Src, const ArgWord &Live, const ArgLabel &Fail, @@ -960,55 +563,6 @@ void BeamModuleAssembler::emit_i_bs_get_float2(const ArgRegister &Ctx, } } -void BeamModuleAssembler::emit_i_bs_utf8_size(const ArgSource &Src, - const ArgXRegister &Dst) { - Label next = a.newLabel(); - - mov_arg(ARG1, Src); - - mov_imm(RET, make_small(1)); - a.cmp(ARG1, imm(make_small(0x80UL))); - a.short_().jl(next); - mov_imm(RET, make_small(2)); - a.cmp(ARG1, imm(make_small(0x800UL))); - a.short_().jl(next); - mov_imm(RET, make_small(3)); - a.cmp(ARG1, imm(make_small(0x10000UL))); - a.short_().jl(next); - mov_imm(RET, make_small(4)); - - a.bind(next); - mov_arg(Dst, RET); -} - -void BeamModuleAssembler::emit_i_bs_put_utf8(const ArgLabel &Fail, - const ArgSource &Src) { - Label next; - - if (Fail.get() == 0) { - next = a.newLabel(); - } - - mov_arg(ARG2, Src); - - emit_enter_runtime(); - - load_erl_bits_state(ARG1); - runtime_call<2>(erts_bs_put_utf8); - - emit_leave_runtime(); - - a.test(RET, RET); - - if (Fail.get() != 0) { - a.je(resolve_beam_label(Fail)); - } else { - a.short_().jne(next); - emit_error(BADARG); - a.bind(next); - } -} - /* * ARG1 = pointer to match state * ARG2 = position in binary in bits @@ -1403,49 +957,6 @@ void BeamModuleAssembler::emit_i_bs_skip_utf8(const ArgRegister &Ctx, emit_bs_get_utf8(Ctx, Fail); } -void BeamModuleAssembler::emit_i_bs_utf16_size(const ArgSource &Src, - const ArgXRegister &Dst) { - mov_arg(ARG1, Src); - - mov_imm(RET, make_small(2)); - mov_imm(ARG2, make_small(4)); - a.cmp(ARG1, imm(make_small(0x10000UL))); - a.cmovae(RET, ARG2); - - mov_arg(Dst, RET); -} - -void BeamModuleAssembler::emit_i_bs_put_utf16(const ArgLabel &Fail, - const ArgWord &Flags, - const ArgSource &Src) { - Label next; - - if (Fail.get() == 0) { - next = a.newLabel(); - } - - /* mov_arg may clobber ARG1 */ - mov_arg(ARG3, Flags); - mov_arg(ARG2, Src); - - emit_enter_runtime(); - - load_erl_bits_state(ARG1); - runtime_call<3>(erts_bs_put_utf16); - - emit_leave_runtime(); - - a.test(RET, RET); - - if (Fail.get() != 0) { - a.je(resolve_beam_label(Fail)); - } else { - a.short_().jne(next); - emit_error(BADARG); - a.bind(next); - } -} - void BeamModuleAssembler::emit_bs_get_utf16(const ArgRegister &Ctx, const ArgLabel &Fail, const ArgWord &Flags) { @@ -1495,27 +1006,6 @@ void BeamModuleAssembler::emit_validate_unicode(Label next, a.jmp(next); } -void BeamModuleAssembler::emit_i_bs_validate_unicode(const ArgLabel &Fail, - const ArgSource &Src) { - Label fail, next = a.newLabel(); - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail); - } else { - fail = a.newLabel(); - } - - mov_arg(ARG1, Src); - emit_validate_unicode(next, fail, ARG1); - - if (Fail.get() == 0) { - a.bind(fail); - emit_error(BADARG); - } - - a.bind(next); -} - void BeamModuleAssembler::emit_i_bs_validate_unicode_retract( const ArgLabel &Fail, const ArgSource &Src, @@ -1565,185 +1055,6 @@ void BeamModuleAssembler::emit_bs_test_unit(const ArgLabel &Fail, a.jnz(resolve_beam_label(Fail)); } -/* Set the error reason when bs_add has failed. */ -void BeamGlobalAssembler::emit_bs_add_shared() { - emit_enter_runtime(); - a.mov(ARG1, c_p); - runtime_call<3>(beam_jit_bs_add_argument_error); - emit_leave_runtime(); - a.ret(); -} - -void BeamModuleAssembler::emit_bs_add(const ArgLabel &Fail, - const ArgSource &Src1, - const ArgSource &Src2, - const ArgWord &Unit, - const ArgXRegister &Dst) { - Label fail; - - if (Fail.get() != 0) { - fail = resolve_beam_label(Fail); - } else { - fail = a.newLabel(); - } - - /* Both arguments must be immediates on x64. */ - mov_arg(ARG1, Src1); - - if (Src2.isImmed()) { - a.mov(RETd, ARG1d); - } else { - mov_arg(ARG2, Src2); - a.mov(RETd, ARG2d); - if (Src1.isImmed()) { - a.and_(RETd, ARG1d); - } - } - - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); - a.jne(fail); - - /* Verify that ARG2 >= 0 and multiply ARG2 by the unit. The - * result will be untagged but not shifted and stored in RET. */ - if (Src2.isSmall()) { - Uint val = Src2.as().getUnsigned(); - - if ((val >> (sizeof(Eterm) - 1) * 8) != 0) { - /* Protect against negative or huge literal size. */ - a.jmp(fail); - return; - } else { - val = (Unit.get() * val) << _TAG_IMMED1_SIZE; - mov_imm(RET, val); - } - } else { - a.and_(ARG2, imm(~_TAG_IMMED1_MASK)); - a.js(fail); - /* Multiply ARG2 by unit. */ - if (Unit.get() == 1) { - a.mov(RET, ARG2); - } else { - mov_imm(RET, Unit.get()); - a.mul(ARG2); /* CLOBBERS RDX = ARG3! */ - a.jo(fail); - } - } - - /* Verify that ARG1 >= 0. */ - a.test(ARG1, ARG1); - a.js(fail); - - /* RET is untagged but shifted, so adding ARG1 tags it and sets the overflow - * flag when the result won't fit an immediate. */ - a.add(RET, ARG1); - - if (Fail.get() != 0) { - a.jo(fail); - } else { - Label next = a.newLabel(); - - a.short_().jno(next); - - a.bind(fail); - { - mov_arg(ARG2, Src1); - mov_arg(ARG3, Src2); - safe_fragment_call(ga->get_bs_add_shared()); - emit_raise_exception(); - } - - a.bind(next); - } - - mov_arg(Dst, RET); -} - -void BeamModuleAssembler::emit_i_bs_append(const ArgLabel &Fail, - const ArgWord &ExtraHeap, - const ArgWord &Live, - const ArgWord &Unit, - const ArgSource &Size, - const ArgSource &Bin, - const ArgRegister &Dst) { - Label next = a.newLabel(); - - mov_arg(ARG3, Live); - mov_arg(ARG4, Size); - mov_arg(ARG5, ExtraHeap); - mov_arg(ARG6, Unit); - - mov_arg(ArgXRegister(Live.get()), Bin); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - load_x_reg_array(ARG2); - runtime_call<6>(erts_bs_append); - - emit_leave_runtime(); - - emit_test_the_non_value(RET); - a.short_().jne(next); - -#ifdef WIN32 - a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.value))); -#else - a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.counter))); -#endif - a.test(ARG1d, imm(ERTS_PSFLG_EXITING)); - - if (Fail.get() != 0) { - a.je(resolve_beam_label(Fail)); - - a.jmp(resolve_fragment(ga->get_do_schedule())); - } else { - a.jne(resolve_fragment(ga->get_do_schedule())); - - /* The error has been prepared in `erts_bs_append` */ - emit_raise_exception(); - } - - a.bind(next); - mov_arg(Dst, RET); -} - -void BeamModuleAssembler::emit_i_bs_private_append(const ArgLabel &Fail, - const ArgWord &Unit, - const ArgSource &Size, - const ArgRegister &Src, - const ArgXRegister &Dst) { - Label next; - - if (Fail.get() == 0) { - next = a.newLabel(); - } - - mov_arg(ARG2, Src); - mov_arg(ARG3, Size); - mov_arg(ARG4, Unit); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - runtime_call<4>(erts_bs_private_append); - - emit_leave_runtime(); - - emit_test_the_non_value(RET); - - if (Fail.get() != 0) { - a.je(resolve_beam_label(Fail)); - } else { - a.short_().jne(next); - /* The error has been prepared in `erts_bs_private_append` */ - emit_raise_exception(); - a.bind(next); - } - - mov_arg(Dst, RET); -} - void BeamModuleAssembler::emit_bs_init_writable() { emit_enter_runtime(); @@ -2320,45 +1631,6 @@ void BeamModuleAssembler::bs_maybe_leave_runtime(bool entered) { } } -/* - * In: - * ARG4 = Size of binary in bits. - * ARG5 = Extra words to allocate. - * ARG6 = Number of live X registers. - * - * Out: - * RET = Allocated binary object. - */ - -void BeamGlobalAssembler::emit_bs_init_bits_legacy_shared() { - Label exiting = a.newLabel(); - - emit_enter_frame(); - emit_enter_runtime(); - - load_erl_bits_state(ARG3); - load_x_reg_array(ARG2); - a.mov(ARG1, c_p); - - runtime_call<6>(beam_jit_bs_init_bits); - - emit_leave_runtime(); - emit_leave_frame(); - -#ifdef WIN32 - a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.value))); -#else - a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.counter))); -#endif - a.test(ARG1d, imm(ERTS_PSFLG_EXITING)); - a.short_().jne(exiting); - - a.ret(); - - a.bind(exiting); - a.jmp(labels[do_schedule]); -} - /* * In: * ARG4 = Size of binary in bits. diff --git a/erts/emulator/beam/jit/x86/ops.tab b/erts/emulator/beam/jit/x86/ops.tab index d73435be65b7..c66d824e3baf 100644 --- a/erts/emulator/beam/jit/x86/ops.tab +++ b/erts/emulator/beam/jit/x86/ops.tab @@ -1007,134 +1007,8 @@ bs_create_bin Fail=j Alloc=u Live=u Unit=u Dst=xy N=u Segments=* => i_bs_create_bin j I t d * -# ================================================================ -# Old instruction for constructing binaries (up to OTP 24). -# ================================================================ - -%warm - -bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail - -bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst - -bs_init2 Fail Sz=u Words Regs Flags Dst => - i_bs_init_heap Sz Words Regs Dst - -bs_init2 Fail Sz Words=u==0 Regs Flags Dst => - i_bs_init_fail Sz Fail Regs Dst -bs_init2 Fail Sz Words Regs Flags Dst => - i_bs_init_fail_heap Sz Words Fail Regs Dst - -i_bs_init_fail S j t S - -i_bs_init_fail_heap s I j t S - -i_bs_init W t S - -i_bs_init_heap W I t S - - -bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail - -bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => - i_bs_init_bits Sz Regs Dst -bs_init_bits Fail Sz=u Words Regs Flags Dst => - i_bs_init_bits_heap Sz Words Regs Dst - -bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => - i_bs_init_bits_fail Sz Fail Regs Dst -bs_init_bits Fail Sz Words Regs Flags Dst => - i_bs_init_bits_fail_heap Sz Words Fail Regs Dst - -i_bs_init_bits_fail S j t S - -i_bs_init_bits_fail_heap s I j t S - -i_bs_init_bits W t S -i_bs_init_bits_heap W I t S - -bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D - -bs_add j s s t x - -bs_append Fail Size Extra Live Unit Bin Flags Dst => - i_bs_append Fail Extra Live Unit Size Bin Dst - -bs_private_append Fail Size Unit Bin Flags Dst => - i_bs_private_append Fail Unit Size Bin Dst - -i_bs_private_append Fail Unit Size Bin Dst=y => - i_bs_private_append Fail Unit Size Bin x | move x Dst - bs_init_writable -i_bs_append j I t t s s S -i_bs_private_append j t s S x - -# -# Storing integers into binaries. -# - -bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => - put_integer(Fail, Sz, Unit, Flags, Src) - -i_new_bs_put_integer j S t s -i_new_bs_put_integer_imm s j W t - -# -# Utf8/utf16/utf32 support. (R12B-5) -# - -bs_utf8_size j Src Dst=d => i_bs_utf8_size Src Dst -bs_utf16_size j Src Dst=d => i_bs_utf16_size Src Dst - -bs_put_utf8 Fail u Src => i_bs_put_utf8 Fail Src -bs_put_utf16 Fail Flags Src => put_utf16(Fail, Flags, Src) - -bs_put_utf32 Fail=j Flags=u Src=s => - i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src - -i_bs_utf8_size s x -i_bs_utf16_size s x - -i_bs_put_utf8 j s -i_bs_put_utf16 j t s - -i_bs_validate_unicode j s - -# -# Storing floats into binaries. -# - -# Will fail. No need to keep the instruction, because bs_add or -# bs_init* would already have raised an exception. -bs_put_float Fail Sz=q Unit Flags Val => _ - -bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => - put_float(Fail, Sz, Unit, Flags, Src) - -i_new_bs_put_float j S t s -i_new_bs_put_float_imm j W t s - -# -# Storing binaries into binaries. -# - -bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => - put_binary(Fail, Sz, Unit, Flags, Src) - -i_new_bs_put_binary j s t s -i_new_bs_put_binary_imm j W s -i_new_bs_put_binary_all s j t - -# -# Warning: The i_bs_put_string and i_new_bs_put_string instructions -# are specially treated in the loader. -# Don't change the instruction format unless you change the loader too. -# - -bs_put_string W M - # # New floating point instructions (R8). # @@ -1159,8 +1033,6 @@ i_fmul l l l i_fdiv l l l i_fnegate l l -%hot - # # New apply instructions in R10B. # diff --git a/erts/emulator/beam/predicates.tab b/erts/emulator/beam/predicates.tab index 4bccce577ffb..fc5d67e2f9de 100644 --- a/erts/emulator/beam/predicates.tab +++ b/erts/emulator/beam/predicates.tab @@ -178,12 +178,6 @@ pred.is_empty_map(Lit) { return is_flatmap(term) && flatmap_get_size(flatmap_val(term)) == 0; } -// Test whether a binary construction is too big. -pred.binary_too_big(Size) { - return Size.type == TAG_o || - (Size.type == TAG_u && ((Size.val >> (8*sizeof(Uint)-3)) != 0)); -} - // Mark this label. Always succeeds. pred.smp_mark_target_label(L) { ASSERT(L.type == TAG_f); diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index 0530b597651b..302d06dde697 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -154,10 +154,6 @@ NO_OPT= bs_bincomp \ guard \ map -R24= \ - bs_construct \ - process_max_heap_size - R25= \ bs_bincomp \ bs_construct \ @@ -179,9 +175,6 @@ STRIPPED_TYPES= \ NO_OPT_MODULES= $(NO_OPT:%=%_no_opt_SUITE) NO_OPT_ERL_FILES= $(NO_OPT_MODULES:%=%.erl) -R24_MODULES= $(R24:%=%_r24_SUITE) -R24_ERL_FILES= $(R24_MODULES:%=%.erl) - R25_MODULES= $(R25:%=%_r25_SUITE) R25_ERL_FILES= $(R25_MODULES:%=%.erl) @@ -225,13 +218,11 @@ ERL_COMPILE_FLAGS := $(filter-out +deterministic,$($(ERL_COMPILE_FLAGS))) # ---------------------------------------------------- make_emakefile: $(NO_OPT_ERL_FILES) \ - $(KERNEL_ERL_FILES) $(R24_ERL_FILES) $(R25_ERL_FILES) $(STRIPPED_TYPES_ERL_FILES) + $(KERNEL_ERL_FILES) $(R25_ERL_FILES) $(STRIPPED_TYPES_ERL_FILES) $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) +compressed -o$(EBIN) \ $(MODULES) $(STDLIB_MODULES) $(KERNEL_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt +no_ssa_opt +no_bsm_opt \ $(ERL_COMPILE_FLAGS) -o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE) - $(ERL_TOP)/make/make_emakefile +r24 \ - $(ERL_COMPILE_FLAGS) -o$(EBIN) $(R24_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +r25 \ $(ERL_COMPILE_FLAGS) -o$(EBIN) $(R25_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +strip_types \ @@ -257,9 +248,6 @@ targets: $(TARGET_FILES) %_no_opt_SUITE.erl: %_SUITE.erl sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ -%_r24_SUITE.erl: %_SUITE.erl - sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ - %_r25_SUITE.erl: %_SUITE.erl sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ @@ -279,7 +267,6 @@ release_tests_spec: make_emakefile $(ERL_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) $(NO_OPT_ERL_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) $(KERNEL_ERL_FILES) "$(RELSYSDIR)" - $(INSTALL_DATA) $(R24_ERL_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) $(R25_ERL_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) $(STRIPPED_TYPES_ERL_FILES) "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl index 9a8da0bafc43..42de143791a5 100644 --- a/erts/emulator/test/bs_construct_SUITE.erl +++ b/erts/emulator/test/bs_construct_SUITE.erl @@ -26,12 +26,11 @@ not_used/1, in_guard/1, mem_leak/1, coerce_to_float/1, bjorn/1, append_empty_is_same/1, huge_float_field/1, system_limit/1, badarg/1, - copy_writable_binary/1, kostis/1, dynamic/1, bs_add/1, + copy_writable_binary/1, kostis/1, dynamic/1, otp_7422/1, zero_width/1, bad_append/1, bs_append_overflow/1, bs_append_offheap/1, reductions/1, fp16/1, zero_init/1, error_info/1, little/1, - heap_binary_unit/1, - otp_24_code_gh_8238/1 + heap_binary_unit/1 ]). -include_lib("common_test/include/ct.hrl"). @@ -44,11 +43,10 @@ all() -> [test1, test2, test3, test4, test5, testf, not_used, in_guard, mem_leak, coerce_to_float, bjorn, append_empty_is_same, huge_float_field, system_limit, badarg, - copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width, + copy_writable_binary, kostis, dynamic, otp_7422, zero_width, bad_append, bs_append_overflow, bs_append_offheap, reductions, fp16, zero_init, - error_info, little, heap_binary_unit, - otp_24_code_gh_8238]. + error_info, little, heap_binary_unit]. init_per_suite(Config) -> Config. @@ -856,75 +854,6 @@ dynamic_little(Bef, N, Int, Lpad, Rpad) -> <> = id(Bin), ok. -%% Test that the bs_add/5 instruction handles big numbers correctly. -bs_add(Config) when is_list(Config) -> - Mod = list_to_atom(atom_to_list(?MODULE) ++ "_" ++ - atom_to_list(?FUNCTION_NAME)), - N = 2000, - Code = [{module, Mod}, - {exports, [{bs_add,2}]}, - {labels, 2}, - - %% bs_add(Number, -SmallestBig) -> Number + N - {function, bs_add, 2, 2}, - {label,1}, - {func_info,{atom,Mod},{atom,bs_add},2}, - - {label,2}, - {move,{x,0},{x,2}}] ++ - lists:duplicate(N-1, {bs_add,{f,0},[{x,2},{integer,1},1],{x,2}}) ++ - [{gc_bif,abs,{f,0},3,[{x,1}],{x,4}}, %Force GC, ignore result. - {gc_bif,'+',{f,0},3,[{x,2},{integer,1}],{x,0}}, %Safe result in {x,0} - return], - - %% Write assembly file and assemble it. - PrivDir = proplists:get_value(priv_dir, Config), - RootName = filename:join(PrivDir, atom_to_list(Mod)), - AsmFile = RootName ++ ".S", - {ok,Fd} = file:open(AsmFile, [write]), - [io:format(Fd, "~p. \n", [T]) || T <- Code], - ok = file:close(Fd), - {ok,Mod} = compile:file(AsmFile, [from_asm,report,{outdir,PrivDir}]), - LoadRc = code:load_abs(RootName), - {module,_Module} = LoadRc, - - %% Find smallest positive bignum. - SmallestBig = smallest_big(), - io:format("~p\n", [SmallestBig]), - DoTest = fun() -> - exit(Mod:bs_add(SmallestBig, -SmallestBig)) - end, - {Pid,Mref} = spawn_monitor(DoTest), - receive - {'DOWN',Mref,process,Pid,Res} -> ok - end, - - case erlang:system_info(wordsize) of - 8 -> - %% bignum-sized binaries must system_limit on 64-bit platforms - {system_limit, _} = Res; - 4 -> - Res = SmallestBig + N - end, - - %% Clean up. - ok = file:delete(AsmFile), - ok = file:delete(code:which(Mod)), - _ = code:delete(Mod), - _ = code:purge(Mod), - - ok. - - -smallest_big() -> - smallest_big_1(1 bsl 24). - -smallest_big_1(N) -> - case erts_debug:flat_size(N) of - 0 -> smallest_big_1(N+N); - _ -> N - end. - otp_7422(Config) when is_list(Config) -> otp_7422_int(0), otp_7422_bin(0). @@ -1398,16 +1327,6 @@ do_zero_init_1(Size, LPad, RPad) -> end()). error_info(_Config) -> - case ?MODULE of - bs_construct_r24_SUITE -> - %% Error information is not implemented for old bit syntax - %% instructions. - ok; - _ -> - error_info() - end. - -error_info() -> Atom = id(some_atom), NegSize = id(-1), HugeNegSize = id(-1 bsl 64), @@ -1715,21 +1634,6 @@ heap_binary_unit_2(Variant, Rest) -> {error2, Bin2} end. -otp_24_code_gh_8238(Config) -> - case ?MODULE of - bs_construct_SUITE -> - %% GH-8238. Code compiled with Erlang/OTP 24 would crash - %% when run on OTP-26.2.3. - DataDir = proplists:get_value(data_dir, Config), - Asm = filename:join(DataDir, atom_to_list(?FUNCTION_NAME) ++ ".S"), - {ok,Mod,Beam} = compile:file(Asm, [binary,from_asm,report]), - {module,Mod} = code:load_binary(Mod, "", Beam), - Mod:Mod(), - ok; - _ -> - {skip,"Enough to run once"} - end. - %%% %%% Common utilities. %%% diff --git a/erts/emulator/test/bs_construct_SUITE_data/otp_24_code_gh_8238.S b/erts/emulator/test/bs_construct_SUITE_data/otp_24_code_gh_8238.S deleted file mode 100644 index 7944fa818a69..000000000000 --- a/erts/emulator/test/bs_construct_SUITE_data/otp_24_code_gh_8238.S +++ /dev/null @@ -1,50 +0,0 @@ -{module, otp_24_code_gh_8238}. %% version = 0 - -{exports, [{module_info,0},{module_info,1},{otp_24_code_gh_8238,0}]}. - -{attributes, []}. - -{labels, 7}. - - -{function, otp_24_code_gh_8238, 0, 2}. - {label,1}. - {line,[{location,"otp_24_code_gh_8238.erl",4}]}. - {func_info,{atom,otp_24_code_gh_8238},{atom,otp_24_code_gh_8238},0}. - {label,2}. - {allocate,0,0}. - {move,{integer,1000},{x,0}}. - {line,[{location,"otp_24_code_gh_8238.erl",5}]}. - {call_ext,1,{extfunc,erlang,integer_to_binary,1}}. - {line,[{location,"otp_24_code_gh_8238.erl",6}]}. - {gc_bif,byte_size,{f,0},1,[{x,0}],{x,1}}. - {bs_add,{f,0},[{x,1},{integer,9},1],{x,1}}. - {bs_init2,{f,0},{x,1},2,2,{field_flags,[]},{x,1}}. - {bs_put_integer,{f,0}, - {integer,72}, - 1, - {field_flags,[unsigned,big]}, - {integer,1281499675772873685536}}. - {bs_put_binary,{f,0},{atom,all},8,{field_flags,[unsigned,big]},{x,0}}. - {put_list,{x,1},nil,{x,1}}. - {move,{literal,"~p\n"},{x,0}}. - {call_ext_last,2,{extfunc,io,format,2},0}. - - -{function, module_info, 0, 4}. - {label,3}. - {line,[]}. - {func_info,{atom,otp_24_code_gh_8238},{atom,module_info},0}. - {label,4}. - {move,{atom,otp_24_code_gh_8238},{x,0}}. - {call_ext_only,1,{extfunc,erlang,get_module_info,1}}. - - -{function, module_info, 1, 6}. - {label,5}. - {line,[]}. - {func_info,{atom,otp_24_code_gh_8238},{atom,module_info},1}. - {label,6}. - {move,{x,0},{x,1}}. - {move,{atom,otp_24_code_gh_8238},{x,0}}. - {call_ext_only,2,{extfunc,erlang,get_module_info,2}}. diff --git a/erts/emulator/test/bs_construct_SUITE_data/otp_24_code_gh_8238.erl b/erts/emulator/test/bs_construct_SUITE_data/otp_24_code_gh_8238.erl deleted file mode 100644 index d18a7c096d0a..000000000000 --- a/erts/emulator/test/bs_construct_SUITE_data/otp_24_code_gh_8238.erl +++ /dev/null @@ -1,10 +0,0 @@ --module(otp_24_code_gh_8238). --export([?MODULE/0]). - -%% Produce otp_24_code_gh_8238.S using Erlang/OTP 24 like this: -%% erlc -S +no_copt +no_ssa_opt otp_24_code_gh_8238.erl - -?MODULE() -> - Bin = integer_to_binary(1000), - io:format("~p\n", [<<"Example: ", Bin/binary>>]). - diff --git a/erts/emulator/test/erts_test_utils.erl b/erts/emulator/test/erts_test_utils.erl index bcdb79039239..1c2325cf1883 100644 --- a/erts/emulator/test/erts_test_utils.erl +++ b/erts/emulator/test/erts_test_utils.erl @@ -25,7 +25,7 @@ %% don't use it. Therefore, we explicitly disable it until OTP 25 is out of %% support. -feature(maybe_expr, disable). --compile(r24). +-compile(r25). %% %% THIS MODULE IS ALSO USED BY *OTHER* APPLICATIONS TEST CODE diff --git a/erts/test/upgrade_SUITE.erl b/erts/test/upgrade_SUITE.erl index d73c5ce7b75c..f6120abc98b1 100644 --- a/erts/test/upgrade_SUITE.erl +++ b/erts/test/upgrade_SUITE.erl @@ -23,7 +23,7 @@ %% don't use it. Therefore, we explicitly disable it until OTP 25 is out of %% support. -feature(maybe_expr, disable). --compile(r24). +-compile(r25). -compile(export_all). diff --git a/lib/common_test/src/test_server_node.erl b/lib/common_test/src/test_server_node.erl index 2f3d4871826e..93f687628ad4 100644 --- a/lib/common_test/src/test_server_node.erl +++ b/lib/common_test/src/test_server_node.erl @@ -25,7 +25,7 @@ %% don't use it. Therefore, we explicitly disable it until OTP 25 is out of %% support. -feature(maybe_expr, disable). --compile(r24). +-compile(r25). %% Test Controller interface -export([is_release_available/1, find_release/1]). diff --git a/lib/compiler/src/beam_a.erl b/lib/compiler/src/beam_a.erl index ff21073db4ed..fc1c307e70a8 100644 --- a/lib/compiler/src/beam_a.erl +++ b/lib/compiler/src/beam_a.erl @@ -106,40 +106,6 @@ rename_instr({bif,Bif,Fail,[A,B],Dst}=I) -> _ -> I end; -rename_instr({bs_put_binary=I,F,Sz,U,Fl,Src}) -> - {bs_put,F,{I,U,Fl},[Sz,Src]}; -rename_instr({bs_put_float=I,F,Sz,U,Fl,Src}) -> - {bs_put,F,{I,U,Fl},[Sz,Src]}; -rename_instr({bs_put_integer=I,F,Sz,U,Fl,Src}) -> - {bs_put,F,{I,U,Fl},[Sz,Src]}; -rename_instr({bs_put_utf8=I,F,Fl,Src}) -> - {bs_put,F,{I,Fl},[Src]}; -rename_instr({bs_put_utf16=I,F,Fl,Src}) -> - {bs_put,F,{I,Fl},[Src]}; -rename_instr({bs_put_utf32=I,F,Fl,Src}) -> - {bs_put,F,{I,Fl},[Src]}; -rename_instr({bs_put_string,_,{string,String}}) -> - %% Only happens when compiling from .S files. In old - %% .S files, String is a list. In .S in OTP 22 and later, - %% String is a binary. - {bs_put,{f,0},{bs_put_binary,8,{field_flags,[unsigned,big]}}, - [{atom,all},{literal,iolist_to_binary([String])}]}; -rename_instr({bs_add=I,F,[Src1,Src2,U],Dst}) when is_integer(U) -> - {bif,I,F,[Src1,Src2,{integer,U}],Dst}; -rename_instr({bs_utf8_size=I,F,Src,Dst}) -> - {bif,I,F,[Src],Dst}; -rename_instr({bs_utf16_size=I,F,Src,Dst}) -> - {bif,I,F,[Src],Dst}; -rename_instr({bs_init2=I,F,Sz,Extra,Live,Flags,Dst}) -> - {bs_init,F,{I,Extra,Flags},Live,[Sz],Dst}; -rename_instr({bs_init_bits=I,F,Sz,Extra,Live,Flags,Dst}) -> - {bs_init,F,{I,Extra,Flags},Live,[Sz],Dst}; -rename_instr({bs_append=I,F,Sz,Extra,Live,U,Src,Flags,Dst}) -> - {bs_init,F,{I,Extra,U,Flags},Live,[Sz,Src],Dst}; -rename_instr({bs_private_append=I,F,Sz,U,Src,Flags,Dst}) -> - {bs_init,F,{I,U,Flags},none,[Sz,Src],Dst}; -rename_instr(bs_init_writable=I) -> - {bs_init,{f,0},I,1,[{x,0}],{x,0}}; rename_instr({put_map_assoc,Fail,S,D,R,L}) -> {put_map,Fail,assoc,S,D,R,L}; rename_instr({put_map_exact,Fail,S,D,R,L}) -> diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl index 9822ad80ba83..817d740b0206 100644 --- a/lib/compiler/src/beam_asm.erl +++ b/lib/compiler/src/beam_asm.erl @@ -81,7 +81,7 @@ assemble({Mod,Exp0,Attr0,Asm0,NumLabels}, ExtraChunks, CompileInfo, CompilerOpts reject_unsupported_versions(Dict) -> %% Emit an instruction that was added in our lowest supported %% version so that it cannot be loaded by earlier releases. - Instr = beam_opcodes:opcode(make_fun3, 3), %OTP 24 + Instr = beam_opcodes:opcode(bs_create_bin, 6), %OTP 25 beam_dict:opcode(Instr, Dict). on_load(Fs0, Attr0) -> @@ -390,8 +390,6 @@ make_op({gc_bif,Bif,Fail,Live,Args,Dest}, Dict) -> 3 -> gc_bif3 end, encode_op(BifOp, [Fail,Live,{extfunc,erlang,Bif,Arity}|Args++[Dest]],Dict); -make_op({bs_add=Op,Fail,[Src1,Src2,Unit],Dest}, Dict) -> - encode_op(Op, [Fail,Src1,Src2,Unit,Dest], Dict); make_op({test,Cond,Fail,Src,{list,_}=Ops}, Dict) -> encode_op(Cond, [Fail,Src,Ops], Dict); make_op({test,Cond,Fail,Ops}, Dict) when is_list(Ops) -> diff --git a/lib/compiler/src/beam_clean.erl b/lib/compiler/src/beam_clean.erl index 65ed71982c0b..abcf6683c85c 100644 --- a/lib/compiler/src/beam_clean.erl +++ b/lib/compiler/src/beam_clean.erl @@ -37,9 +37,7 @@ module({Mod,Exp,Attr,Fs0,_}, Opts) -> Used = find_all_used(WorkList, All, sets:from_list(WorkList)), Fs2 = remove_unused(Order, Used, All), {Fs3,Lc} = clean_labels(Fs2), - Fs4 = fix_bs_create_bin(Fs3, Opts), - Fs5 = fix_badrecord(Fs4, Opts), - Fs = maybe_remove_lines(Fs5, Opts), + Fs = maybe_remove_lines(Fs3, Opts), {ok,{Mod,Exp,Attr,Fs,Lc}}. %% Determine the rootset, i.e. exported functions and @@ -184,167 +182,6 @@ remove_lines_block([I|Is]) -> [I|remove_lines_block(Is)]; remove_lines_block([]) -> []. -%%% -%%% If compatibility with a previous release (OTP 24 or earlier) has -%%% been requested, eliminate bs_create_bin instructions by translating -%%% them to the old binary syntax instructions. -%%% - -fix_bs_create_bin(Fs, Opts) -> - case proplists:get_bool(no_bs_create_bin, Opts) of - false -> Fs; - true -> fold_functions(fun fix_bs_create_bin/1, Fs) - end. - -fix_bs_create_bin([{bs_create_bin,Fail,Alloc,Live,Unit,Dst,{list,List}}|Is]) -> - Tail = fix_bs_create_bin(Is), - Flags = {field_flags,[]}, - try bs_pre_size_calc(List) of - SizeCalc0 -> - SizeCalc = fold_size_calc(SizeCalc0, 0, []), - TmpDst = SizeReg = {x,Live}, - SizeIs0 = bs_size_calc(SizeCalc, Fail, SizeReg, {x,Live+1}), - SizeIs = [{move,{integer,0},SizeReg}|SizeIs0], - RestIs = bs_puts(List, Fail) ++ [{move,TmpDst,Dst}|Tail], - case List of - [{atom,append},_,_,_,Src|_] -> - SizeIs ++ [{bs_append,Fail,SizeReg,Alloc,Live+1,Unit,Src,Flags,TmpDst}|RestIs]; - [{atom,private_append},_,_,_,Src|_] -> - TestHeap = {test_heap,Alloc,Live+1}, - SizeIs ++ [TestHeap,{bs_private_append,Fail,SizeReg,Unit,Src,Flags,TmpDst}|RestIs]; - _ -> - SizeIs ++ [{bs_init_bits,Fail,SizeReg,Alloc,Live+1,Flags,TmpDst}|RestIs] - end - catch - throw:invalid_size -> - [{move,{atom,badarg},{x,0}}, - {call_ext_only,1,{extfunc,erlang,error,1}}|Tail] - end; -fix_bs_create_bin([I|Is]) -> - [I|fix_bs_create_bin(Is)]; -fix_bs_create_bin([]) -> []. - -bs_pre_size_calc([Type,_Seg,Unit,_Flags,Src,Size|Segs]) -> - case Type of - {atom,T} when T =:= append; T =:= private_append -> - bs_pre_size_calc(Segs); - _ -> - [bs_pre_size_calc_1(Type, Unit, Src, Size)|bs_pre_size_calc(Segs)] - end; -bs_pre_size_calc([]) -> []. - -bs_pre_size_calc_1({atom,Type}, Unit, Src, Size) -> - case {Unit,Size} of - {0,{atom,undefined}} -> - %% No size/unit given. - {8,case Type of - utf8 -> {{instr,bs_utf8_size},Src}; - utf16 -> {{instr,bs_utf16_size},Src}; - utf32 -> {term,{integer,4}} - end}; - {Unit,_} -> - case {Type,Size} of - {binary,{atom,all}} -> - case Unit rem 8 of - 0 -> {8,{{bif,byte_size},Src}}; - _ -> {1,{{bif,bit_size},Src}} - end; - {_,_} -> - ensure_valid_size(Size), - {Unit,{term,Size}} - end - end. - -ensure_valid_size({x,_}) -> ok; -ensure_valid_size({y,_}) -> ok; -ensure_valid_size({integer,Size}) when Size >= 0 -> ok; -ensure_valid_size(_) -> throw(invalid_size). - -fold_size_calc([{Unit,{term,{integer,Size}}}|T], Bits, Acc) -> - fold_size_calc(T, Bits + Unit*Size, Acc); -fold_size_calc([{Unit,{{bif,Bif},{literal,Lit}}}=H|T], Bits, Acc) -> - try erlang:Bif(Lit) of - Result -> - fold_size_calc([{Unit,{term,{integer,Result}}}|T], Bits, Acc) - catch - _:_ -> - fold_size_calc(T, Bits, [H|Acc]) - end; -fold_size_calc([{U,_}=H|T], Bits, Acc) when U =:= 1; U =:= 8 -> - fold_size_calc(T, Bits, [H|Acc]); -fold_size_calc([{U,Var}|T], Bits, Acc) -> - fold_size_calc(T, Bits, [{1,{'*',{term,{integer,U}},Var}}|Acc]); -fold_size_calc([], Bits, Acc) -> - Bytes = Bits div 8, - RemBits = Bits rem 8, - Sizes = [{1,{term,{integer,RemBits}}},{8,{term,{integer,Bytes}}}|Acc], - [Pair || {_,Sz}=Pair <- Sizes, Sz =/= {term,{integer,0}}]. - -bs_size_calc([{Unit,{{bif,Bif},Reg}}|T], Fail, SizeReg, TmpReg) -> - Live = element(2, SizeReg) + 1, - [{gc_bif,Bif,Fail,Live,[Reg],TmpReg}, - {bs_add,Fail,[SizeReg,TmpReg,Unit],SizeReg}|bs_size_calc(T, Fail, SizeReg, TmpReg)]; -bs_size_calc([{Unit,{'*',{term,Term1},{term,Term2}}}|T], Fail, SizeReg, TmpReg) -> - Live = element(2, SizeReg) + 1, - [{gc_bif,'*',Fail,Live,[Term1,Term2],TmpReg}, - {bs_add,Fail,[SizeReg,TmpReg,Unit],SizeReg}|bs_size_calc(T, Fail, SizeReg, TmpReg)]; -bs_size_calc([{Unit,{{instr,Instr},Reg}}|T], Fail, SizeReg, TmpReg) -> - [{Instr,Fail,Reg,TmpReg}, - {bs_add,Fail,[SizeReg,TmpReg,Unit],SizeReg}|bs_size_calc(T, Fail, SizeReg, TmpReg)]; -bs_size_calc([{Unit,{term,Term}}|T], Fail, SizeReg, TmpReg) -> - [{bs_add,Fail,[SizeReg,Term,Unit],SizeReg}|bs_size_calc(T, Fail, SizeReg, TmpReg)]; -bs_size_calc([], _Fail, _SizeReg, _TmpReg) -> []. - -bs_puts([{atom,string},_Seg,_Unit,_Flags,{string,_}=Str,{integer,Size}|Is], Fail) -> - [{bs_put_string,Size,Str}|bs_puts(Is, Fail)]; -bs_puts([{atom,append},_,_,_,_,_|Is], Fail) -> - bs_puts(Is, Fail); -bs_puts([{atom,private_append},_,_,_,_,_|Is], Fail) -> - bs_puts(Is, Fail); -bs_puts([{atom,Type},_Seg,Unit,Flags0,Src,Size|Is], Fail) -> - Op = case Type of - integer -> bs_put_integer; - float -> bs_put_float; - binary -> bs_put_binary; - utf8 -> bs_put_utf8; - utf16 -> bs_put_utf16; - utf32 -> bs_put_utf32 - end, - Flags = case Flags0 of - nil -> []; - {literal,Fs} -> Fs - end, - I = if - Unit =:= 0 -> - {bs_put,Fail,{Op,{field_flags,Flags}},[Src]}; - true -> - {bs_put,Fail,{Op,Unit,{field_flags,Flags}},[Size,Src]} - end, - [I|bs_puts(Is, Fail)]; -bs_puts([], _Fail) -> []. - -%%% -%%% If compatibility with a previous release (OTP 24 or earlier) has -%%% been requested, eliminate badrecord instructions by translating -%%% them to calls to error({badrecord,Value}). -%%% - -fix_badrecord(Fs, Opts) -> - case proplists:get_bool(no_badrecord, Opts) of - false -> Fs; - true -> fold_functions(fun fix_badrecord/1, Fs) - end. - -fix_badrecord([{badrecord,Value}|Is]) -> - [{move,Value,{x,0}}, - {test_heap,3,1}, - {put_tuple2,{x,0},{list,[{atom,badrecord},{x,0}]}}, - {call_ext_only,1,{extfunc,erlang,error,1}}|fix_badrecord(Is)]; -fix_badrecord([I|Is]) -> - [I|fix_badrecord(Is)]; -fix_badrecord([]) -> []. - - %%% %%% Helpers. %%% diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl index 5c84f8fd1418..3a213ed440f7 100644 --- a/lib/compiler/src/beam_jump.erl +++ b/lib/compiler/src/beam_jump.erl @@ -408,7 +408,7 @@ share_1([I|Is], Safe, Dict, Lbls, Seq, Acc) -> share_1(Is, Safe, Dict, Lbls, [I], Acc) end. -unambigous_deallocation([{bs_init,_,bs_init_writable,_,_,_}|Is]) -> +unambigous_deallocation([bs_init_writable|Is]) -> %% beam_validator requires that the size of the stack frame is %% unambigously known when certain instructions are used. %% @@ -429,7 +429,7 @@ unambigous_deallocation([]) -> find_deallocation([{block,_}|Is]) -> find_deallocation(Is); -find_deallocation([{bs_init,_,bs_init_writable,_,_,_}|Is]) -> +find_deallocation([bs_init_writable|Is]) -> find_deallocation(Is); find_deallocation([{call,_,_}|Is]) -> find_deallocation(Is); @@ -937,10 +937,6 @@ instr_labels({gc_bif,_Name,Lbl,_Live,_As,_R}) -> do_instr_labels(Lbl); instr_labels({bs_create_bin,Lbl,_,_,_,_,_}) -> do_instr_labels(Lbl); -instr_labels({bs_init,Lbl,_,_,_,_}) -> - do_instr_labels(Lbl); -instr_labels({bs_put,Lbl,_,_}) -> - do_instr_labels(Lbl); instr_labels({put_map,Lbl,_Op,_Src,_Dst,_Live,_List}) -> do_instr_labels(Lbl); instr_labels({get_map_elements,Lbl,_Src,_List}) -> diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl index aa88a8a5fc11..9a85aaa4103c 100644 --- a/lib/compiler/src/beam_utils.erl +++ b/lib/compiler/src/beam_utils.erl @@ -102,10 +102,6 @@ replace_labels_1([{bs_create_bin,{f,Lbl},Alloc,Live,Unit,Dst,{list,List}}|Is], A when Lbl =/= 0 -> replace_labels_1(Is, [{bs_create_bin,{f,label(Lbl, D, Fb)}, Alloc,Live,Unit,Dst,{list,List}}|Acc], D, Fb); -replace_labels_1([{bs_init,{f,Lbl},Info,Live,Ss,Dst}|Is], Acc, D, Fb) when Lbl =/= 0 -> - replace_labels_1(Is, [{bs_init,{f,label(Lbl, D, Fb)},Info,Live,Ss,Dst}|Acc], D, Fb); -replace_labels_1([{bs_put,{f,Lbl},Info,Ss}|Is], Acc, D, Fb) when Lbl =/= 0 -> - replace_labels_1(Is, [{bs_put,{f,label(Lbl, D, Fb)},Info,Ss}|Acc], D, Fb); replace_labels_1([{put_map=I,{f,Lbl},Op,Src,Dst,Live,List}|Is], Acc, D, Fb) when Lbl =/= 0 -> replace_labels_1(Is, [{I,{f,label(Lbl, D, Fb)},Op,Src,Dst,Live,List}|Acc], D, Fb); diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 007c26efb6b0..791f0bbb5bc0 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -1090,113 +1090,6 @@ vi({bs_create_bin,{f,Fail},Heap,Live,Unit,Dst,{list,List0}}, Vst0) -> create_term(#t_bitstring{size_unit=Unit}, bs_create_bin, [], Dst, SuccVst) end); -vi({bs_init2,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) -> - verify_live(Live, Vst0), - verify_y_init(Vst0), - if - is_integer(Sz) -> ok; - true -> assert_term(Sz, Vst0) - end, - Vst = heap_alloc(Heap, Vst0), - branch(Fail, Vst, - fun(SuccVst0) -> - SuccVst = prune_x_regs(Live, SuccVst0), - create_term(#t_bitstring{size_unit=8}, bs_init2, [], Dst, - SuccVst, SuccVst0) - end); -vi({bs_init_bits,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) -> - verify_live(Live, Vst0), - verify_y_init(Vst0), - if - is_integer(Sz) -> ok; - true -> assert_term(Sz, Vst0) - end, - Vst = heap_alloc(Heap, Vst0), - branch(Fail, Vst, - fun(SuccVst0) -> - SuccVst = prune_x_regs(Live, SuccVst0), - create_term(#t_bitstring{}, bs_init_bits, [], Dst, SuccVst) - end); -vi({bs_add,{f,Fail},[A,B,_],Dst}, Vst) -> - assert_term(A, Vst), - assert_term(B, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - create_term(#t_integer{}, bs_add, [A, B], Dst, SuccVst) - end); -vi({bs_utf8_size,{f,Fail},A,Dst}, Vst) -> - assert_term(A, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - create_term(#t_integer{}, bs_utf8_size, [A], Dst, SuccVst) - end); -vi({bs_utf16_size,{f,Fail},A,Dst}, Vst) -> - assert_term(A, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - create_term(#t_integer{}, bs_utf16_size, [A], Dst, SuccVst) - end); -vi({bs_append,{f,Fail},Bits,Heap,Live,Unit,Bin,_Flags,Dst}, Vst0) -> - verify_live(Live, Vst0), - verify_y_init(Vst0), - assert_term(Bits, Vst0), - assert_term(Bin, Vst0), - Vst = heap_alloc(Heap, Vst0), - branch(Fail, Vst, - fun(SuccVst0) -> - SuccVst = prune_x_regs(Live, SuccVst0), - create_term(#t_bitstring{size_unit=Unit}, bs_append, - [Bin], Dst, SuccVst, SuccVst0) - end); -vi({bs_private_append,{f,Fail},Bits,Unit,Bin,_Flags,Dst}, Vst) -> - assert_term(Bits, Vst), - assert_term(Bin, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - create_term(#t_bitstring{size_unit=Unit}, bs_private_append, - [Bin], Dst, SuccVst) - end); -vi({bs_put_string,Sz,_}, Vst) when is_integer(Sz) -> - Vst; -vi({bs_put_binary,{f,Fail},Sz,_,_,Src}, Vst) -> - assert_term(Sz, Vst), - assert_term(Src, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - update_type(fun meet/2, #t_bitstring{}, Src, SuccVst) - end); -vi({bs_put_float,{f,Fail},Sz,_,_,Src}, Vst) -> - assert_term(Sz, Vst), - assert_term(Src, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - update_type(fun meet/2, #t_float{}, Src, SuccVst) - end); -vi({bs_put_integer,{f,Fail},Sz,_,_,Src}, Vst) -> - assert_term(Sz, Vst), - assert_term(Src, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - update_type(fun meet/2, #t_integer{}, Src, SuccVst) - end); -vi({bs_put_utf8,{f,Fail},_,Src}, Vst) -> - assert_term(Src, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - update_type(fun meet/2, #t_integer{}, Src, SuccVst) - end); -vi({bs_put_utf16,{f,Fail},_,Src}, Vst) -> - assert_term(Src, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - update_type(fun meet/2, #t_integer{}, Src, SuccVst) - end); -vi({bs_put_utf32,{f,Fail},_,Src}, Vst) -> - assert_term(Src, Vst), - branch(Fail, Vst, - fun(SuccVst) -> - update_type(fun meet/2, #t_integer{}, Src, SuccVst) - end); vi(_, _) -> error(unknown_instruction). diff --git a/lib/compiler/src/beam_z.erl b/lib/compiler/src/beam_z.erl index 486d497f1c91..7d0a5d015b90 100644 --- a/lib/compiler/src/beam_z.erl +++ b/lib/compiler/src/beam_z.erl @@ -100,24 +100,6 @@ get_list(Src, Hd, Tl, [{swap,R1,R2}|Is]=Is0) -> get_list(Src, Hd, Tl, Is) -> [{get_list,Src,Hd,Tl}|undo_renames(Is)]. -undo_rename({bs_put,F,{I,U,Fl},[Sz,Src]}) -> - {I,F,Sz,U,Fl,Src}; -undo_rename({bs_put,F,{I,Fl},[Src]}) -> - {I,F,Fl,Src}; -undo_rename({bif,bs_add=I,F,[Src1,Src2,{integer,U}],Dst}) -> - {I,F,[Src1,Src2,U],Dst}; -undo_rename({bif,bs_utf8_size=I,F,[Src],Dst}) -> - {I,F,Src,Dst}; -undo_rename({bif,bs_utf16_size=I,F,[Src],Dst}) -> - {I,F,Src,Dst}; -undo_rename({bs_init,F,{I,U,Flags},none,[Sz,Src],Dst}) -> - {I,F,Sz,U,Src,Flags,Dst}; -undo_rename({bs_init,F,{I,Extra,Flags},Live,[Sz],Dst}) -> - {I,F,Sz,Extra,Live,Flags,Dst}; -undo_rename({bs_init,F,{I,Extra,U,Flags},Live,[Sz,Src],Dst}) -> - {I,F,Sz,Extra,Live,U,Src,Flags,Dst}; -undo_rename({bs_init,_,bs_init_writable=I,_,_,_}) -> - I; undo_rename({put_map,Fail,assoc,S,D,R,L}) -> {put_map_assoc,Fail,S,D,R,L}; undo_rename({put_map,Fail,exact,S,D,R,L}) -> diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index d693937a8917..67a22e97e37b 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -1036,9 +1036,6 @@ expand_opt(report, Os) -> [report_errors,report_warnings|Os]; expand_opt(return, Os) -> [return_errors,return_warnings|Os]; -expand_opt(r24, Os) -> - expand_opt(no_type_opt, [no_badrecord, no_bs_create_bin, no_ssa_opt_ranges | - expand_opt(r25, Os)]); expand_opt(r25, Os) -> [no_ssa_opt_update_tuple, no_bs_match, no_min_max_bifs | expand_opt(r26, Os)]; @@ -2348,6 +2345,9 @@ is_obsolete(r20) -> true; is_obsolete(r21) -> true; is_obsolete(r22) -> true; is_obsolete(r23) -> true; +is_obsolete(r24) -> true; +is_obsolete(no_badrecord) -> true; +is_obsolete(no_bs_create_bin) -> true; is_obsolete(no_bsm3) -> true; is_obsolete(no_get_hd_tl) -> true; is_obsolete(no_put_tuple2) -> true; diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab index f9ac6e1b1d62..fdf038c29dcb 100755 --- a/lib/compiler/src/genop.tab +++ b/lib/compiler/src/genop.tab @@ -384,10 +384,10 @@ BEAM_FORMAT_NUMBER=0 # 87: -bs_init/2 88: -bs_final/2 -89: bs_put_integer/5 -90: bs_put_binary/5 -91: bs_put_float/5 -92: bs_put_string/2 +89: -bs_put_integer/5 +90: -bs_put_binary/5 +91: -bs_put_float/5 +92: -bs_put_string/2 # # Binary construction (R7B). @@ -421,9 +421,9 @@ BEAM_FORMAT_NUMBER=0 108: raise/2 # New instructions in R10B. -109: bs_init2/6 +109: -bs_init2/6 110: -bs_bits_to_bytes/3 -111: bs_add/5 +111: -bs_add/5 112: apply/1 113: apply_last/2 ## @spec is_boolean Lbl Arg1 @@ -482,15 +482,15 @@ BEAM_FORMAT_NUMBER=0 131: bs_test_unit/3 132: bs_match_string/4 133: bs_init_writable/0 -134: bs_append/8 -135: bs_private_append/6 +134: -bs_append/8 +135: -bs_private_append/6 ## @spec trim N Remaining ## @doc Reduce the stack usage by N words, ## keeping the CP on the top of the stack. 136: trim/2 -137: bs_init_bits/6 +137: -bs_init_bits/6 # R12B-5 138: bs_get_utf8/5 @@ -502,13 +502,13 @@ BEAM_FORMAT_NUMBER=0 142: bs_get_utf32/5 143: bs_skip_utf32/4 -144: bs_utf8_size/3 -145: bs_put_utf8/3 +144: -bs_utf8_size/3 +145: -bs_put_utf8/3 -146: bs_utf16_size/3 -147: bs_put_utf16/3 +146: -bs_utf16_size/3 +147: -bs_put_utf16/3 -148: bs_put_utf32/3 +148: -bs_put_utf32/3 # R13B03 diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index bf7e190cefb8..c6e5a23a3215 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -112,11 +112,6 @@ INLINE= \ receive \ record -R24= \ - bs_construct \ - bs_utf \ - bs_bincomp - R25= \ bs_construct \ bs_match \ @@ -147,8 +142,6 @@ NO_CORE_SSA_OPT_MODULES= $(NO_OPT:%=%_no_copt_ssa_SUITE) NO_CORE_SSA_OPT_ERL_FILES= $(NO_CORE_SSA_OPT_MODULES:%=%.erl) INLINE_MODULES= $(INLINE:%=%_inline_SUITE) INLINE_ERL_FILES= $(INLINE_MODULES:%=%.erl) -R24_MODULES= $(R24:%=%_r24_SUITE) -R24_ERL_FILES= $(R24_MODULES:%=%.erl) R25_MODULES= $(R25:%=%_r25_SUITE) R25_ERL_FILES= $(R25_MODULES:%=%.erl) NO_MOD_OPT_MODULES= $(NO_MOD_OPT:%=%_no_module_opt_SUITE) @@ -195,7 +188,7 @@ DISABLE_SSA_OPT = +no_bool_opt +no_share_opt +no_bsm_opt +no_fun_opt +no_ssa_opt make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) $(NO_SSA_OPT_ERL_FILES) \ $(NO_CORE_OPT_ERL_FILES) $(NO_CORE_SSA_OPT_ERL_FILES) \ $(INLINE_ERL_FILES) $(NO_MOD_OPT_ERL_FILES) $(NO_TYPE_OPT_ERL_FILES) \ - $(DIALYZER_ERL_FILES) $(COVER_ERL_FILES) $(R24_ERL_FILES) $(R25_ERL_FILES) + $(DIALYZER_ERL_FILES) $(COVER_ERL_FILES) $(R25_ERL_FILES) $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \ > $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +no_copt $(DISABLE_SSA_OPT) +no_postopt \ @@ -210,8 +203,6 @@ make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) $(NO_SSA_OPT_ERL_FILES -o$(EBIN) $(NO_CORE_SSA_OPT_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +inline $(ERL_COMPILE_FLAGS) \ -o$(EBIN) $(INLINE_MODULES) >> $(EMAKEFILE) - $(ERL_TOP)/make/make_emakefile +r24 $(ERL_COMPILE_FLAGS) \ - -o$(EBIN) $(R24_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +r25 $(ERL_COMPILE_FLAGS) \ -o$(EBIN) $(R25_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +no_module_opt $(ERL_COMPILE_FLAGS) \ @@ -257,12 +248,6 @@ docs: %_inline_SUITE.erl: %_SUITE.erl sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ -%_r23_SUITE.erl: %_SUITE.erl - sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ - -%_r24_SUITE.erl: %_SUITE.erl - sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ - %_r25_SUITE.erl: %_SUITE.erl sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ @@ -291,7 +276,6 @@ release_tests_spec: make_emakefile $(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \ $(INLINE_ERL_FILES) \ - $(R24_ERL_FILES) \ $(R25_ERL_FILES) \ $(NO_CORE_OPT_ERL_FILES) \ $(NO_CORE_SSA_OPT_ERL_FILES) \ diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl index d653a460858d..c986f66920ee 100644 --- a/lib/compiler/test/beam_validator_SUITE.erl +++ b/lib/compiler/test/beam_validator_SUITE.erl @@ -24,7 +24,7 @@ init_per_testcase/2,end_per_testcase/2, compiler_bug/1,stupid_but_valid/1, xrange/1,yrange/1,stack/1,call_last/1,merge_undefined/1, - uninit/1,unsafe_catch/1, + uninit/1, dead_code/1, overwrite_catchtag/1,overwrite_trytag/1,accessing_tags/1,bad_catch_try/1, cons_guard/1, @@ -65,7 +65,7 @@ groups() -> [{p,test_lib:parallel(), [compiler_bug,stupid_but_valid,xrange, yrange,stack,call_last,merge_undefined,uninit, - unsafe_catch,dead_code, + dead_code, overwrite_catchtag,overwrite_trytag,accessing_tags, bad_catch_try,cons_guard,freg_range,freg_uninit, bad_bin_match,bad_dsetel, @@ -209,15 +209,6 @@ uninit(Config) when is_list(Config) -> {unassigned,{y,0}}}}] = Errors, ok. -unsafe_catch(Config) when is_list(Config) -> - Errors = do_val(unsafe_catch, Config), - [{{t,small,2}, - {{bs_put_integer,{f,0},{integer,16},1, - {field_flags,[unsigned,big]},{y,0}}, - 21, - {unassigned,{y,0}}}}] = Errors, - ok. - dead_code(Config) when is_list(Config) -> [] = do_val(dead_code, Config), ok. diff --git a/lib/compiler/test/beam_validator_SUITE_data/unsafe_catch.S b/lib/compiler/test/beam_validator_SUITE_data/unsafe_catch.S deleted file mode 100644 index 81f035c6c8f6..000000000000 --- a/lib/compiler/test/beam_validator_SUITE_data/unsafe_catch.S +++ /dev/null @@ -1,68 +0,0 @@ -{module, unsafe_catch}. %% version = 0 - -{exports, [{small,2}]}. - -{attributes, []}. - -{labels, 14}. - - -{function, small, 2, 5}. - {label,4}. - {func_info,{atom,t},{atom,small},2}. - {label,5}. - {allocate,2,2}. - {init_yregs,{list,[{y,0},{y,1}]}}. - {'catch',{y,1},{f,6}}. - {bs_init2,{f,0},1,0,2,{field_flags,[]},{x,2}}. - {bs_put_integer,{f,0}, - {integer,8}, - 1, - {field_flags,[unsigned,big]}, - {x,0}}. - {move,{x,1},{y,0}}. - {move,{x,2},{x,0}}. - {label,6}. - {catch_end,{y,1}}. - {test,is_tuple,{f,7},[{x,0}]}. - {test,test_arity,{f,7},[{x,0},2]}. - {get_tuple_element,{x,0},0,{x,1}}. - {test,is_eq_exact,{f,7},[{x,1},{atom,'EXIT'}]}. - {bs_init2,{f,0},0,0,0,{field_flags,[]},{x,0}}. - {label,7}. - {'catch',{y,1},{f,8}}. - {bs_init2,{f,0},2,0,1,{field_flags,[]},{x,1}}. - {bs_put_integer,{f,0}, - {integer,16}, - 1, - {field_flags,[unsigned,big]}, - {y,0}}. - {move,{x,0},{y,0}}. - {move,{x,1},{x,0}}. - {label,8}. - {catch_end,{y,1}}. - {test,is_tuple,{f,9},[{x,0}]}. - {test,test_arity,{f,9},[{x,0},2]}. - {get_tuple_element,{x,0},0,{x,1}}. - {test,is_eq_exact,{f,9},[{x,1},{atom,'EXIT'}]}. - {bs_init2,{f,0},0,0,0,{field_flags,[]},{x,0}}. - {label,9}. - {move,{integer,0},{x,1}}. - {bif,size,{f,0},[{x,0}],{x,2}}. - {bs_add,{f,0},[{x,1},{x,2},1],{x,1}}. - {bif,size,{f,0},[{y,0}],{x,2}}. - {bs_add,{f,0},[{x,1},{x,2},1],{x,1}}. - {bs_init2,{f,0},{x,1},0,2,{field_flags,[]},{x,1}}. - {bs_put_binary,{f,0}, - {atom,all}, - 8, - {field_flags,[unsigned,big]}, - {y,0}}. - {bs_put_binary,{f,0}, - {atom,all}, - 8, - {field_flags,[unsigned,big]}, - {x,0}}. - {move,{x,1},{x,0}}. - {deallocate,2}. - return. diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl index 3d95ec29d87e..b86756d5085c 100644 --- a/lib/compiler/test/bs_bincomp_SUITE.erl +++ b/lib/compiler/test/bs_bincomp_SUITE.erl @@ -61,15 +61,7 @@ end_per_group(_GroupName, Config) -> verify_highest_opcode(_Config) -> case ?MODULE of - bs_construct_r24_SUITE -> - {ok,Beam} = file:read_file(code:which(?MODULE)), - case test_lib:highest_opcode(Beam) of - Highest when Highest =< 176 -> - ok; - TooHigh -> - ct:fail({too_high_opcode,TooHigh}) - end; - bs_construct_r25_SUITE -> + bs_bincomp_r25_SUITE -> {ok,Beam} = file:read_file(code:which(?MODULE)), case test_lib:highest_opcode(Beam) of Highest when Highest =< 180 -> @@ -700,8 +692,6 @@ cs(Bin) -> ok; bs_bincomp_post_opt_SUITE -> ok; - bs_bincomp_r24_SUITE -> - ok; bs_bincomp_r25_SUITE -> ok; bs_bincomp_r26_SUITE -> diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl index f24074193726..58536c4d23ff 100644 --- a/lib/compiler/test/bs_construct_SUITE.erl +++ b/lib/compiler/test/bs_construct_SUITE.erl @@ -72,14 +72,6 @@ end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> verify_highest_opcode(_Config) -> case ?MODULE of - bs_construct_r24_SUITE -> - {ok,Beam} = file:read_file(code:which(?MODULE)), - case test_lib:highest_opcode(Beam) of - Highest when Highest =< 176 -> - ok; - TooHigh -> - ct:fail({too_high_opcode,TooHigh}) - end; bs_construct_r25_SUITE -> {ok,Beam} = file:read_file(code:which(?MODULE)), case test_lib:highest_opcode(Beam) of diff --git a/lib/compiler/test/bs_utf_SUITE.erl b/lib/compiler/test/bs_utf_SUITE.erl index beb0f4ef23f5..af5bd9217b4e 100644 --- a/lib/compiler/test/bs_utf_SUITE.erl +++ b/lib/compiler/test/bs_utf_SUITE.erl @@ -55,14 +55,6 @@ end_per_group(_GroupName, Config) -> verify_highest_opcode(_Config) -> case ?MODULE of - bs_construct_r24_SUITE -> - {ok,Beam} = file:read_file(code:which(?MODULE)), - case test_lib:highest_opcode(Beam) of - Highest when Highest =< 176 -> - ok; - TooHigh -> - ct:fail({too_high_opcode,TooHigh}) - end; bs_construct_r25_SUITE -> {ok,Beam} = file:read_file(code:which(?MODULE)), case test_lib:highest_opcode(Beam) of diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index e0791172c440..131b950a3c89 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -1707,43 +1707,36 @@ bc_options(Config) -> DataDir = proplists:get_value(data_dir, Config), - L = [{171, small_float, [no_line_info, - no_ssa_opt_float, - no_type_opt]}, - {171, small_float, [no_line_info]}, - {171, small_float, []}, - {171, small_float, [r24]}, - {171, small_float, [r25]}, - - {172, small, [no_ssa_opt_record, + L = [{177, small_float, []}, + + {177, small, [no_ssa_opt_record, no_ssa_opt_float, no_line_info, no_type_opt, no_bs_match]}, - {172, small, [r24]}, - {172, funs, [no_ssa_opt_record, - no_ssa_opt_float,no_line_info, - no_type_opt]}, - {172, funs, [no_ssa_opt_record, + {177, funs, [no_ssa_opt_record, + no_ssa_opt_float, no_line_info, no_stack_trimming, no_type_opt]}, - {172, funs, [r24]}, - {172, small_maps, [r24]}, - {172, small_maps, [no_type_opt]}, + {177, small_maps, [no_type_opt]}, - {172, big, [no_ssa_opt_record, + {177, big, [no_ssa_opt_record, no_ssa_opt_float, no_line_info, no_type_opt]}, - {172, big, [r24]}, {178, small, [r25]}, {178, big, [r25]}, {178, funs, []}, - {178, big, []} + {178, big, []}, + + {182, small, [r26]}, + {182, small, []}, + + {183, small, [line_coverage]} ], Test = fun({Expected,Mod,Options}) -> diff --git a/lib/compiler/test/property_test/compile_prop.erl b/lib/compiler/test/property_test/compile_prop.erl index 5b0e6ef13c40..7f0f9d77eb9a 100644 --- a/lib/compiler/test/property_test/compile_prop.erl +++ b/lib/compiler/test/property_test/compile_prop.erl @@ -82,7 +82,6 @@ spawn_compile(Forms, Options) -> compiler_variants() -> [ [ssalint,clint0,clint], - [r24,ssalint], [r25,ssalint], [r26,ssalint], [no_type_opt,ssalint], diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl index e17122b8b0b0..6719e2152452 100644 --- a/lib/kernel/test/global_SUITE.erl +++ b/lib/kernel/test/global_SUITE.erl @@ -24,7 +24,7 @@ %% don't use it. Therefore, we explicitly disable it until OTP 25 is out of %% support. -feature(maybe_expr, disable). --compile(r24). % many_nodes() +-compile(r25). % many_nodes() -export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1, diff --git a/lib/kernel/test/kernel_SUITE.erl b/lib/kernel/test/kernel_SUITE.erl index 829d10c6a006..2937ca833236 100644 --- a/lib/kernel/test/kernel_SUITE.erl +++ b/lib/kernel/test/kernel_SUITE.erl @@ -27,7 +27,7 @@ %% don't use it. Therefore, we explicitly disable it until OTP 25 is out of %% support. -feature(maybe_expr, disable). --compile(r24). +-compile(r25). -include_lib("common_test/include/ct.hrl"). diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl index 2b6d15cf1b65..d4669dafa393 100644 --- a/lib/observer/test/crashdump_helper.erl +++ b/lib/observer/test/crashdump_helper.erl @@ -25,7 +25,7 @@ %% don't use it. Therefore, we explicitly disable it until OTP 25 is out of %% support. -feature(maybe_expr, disable). --compile(r24). +-compile(r25). -export([n1_proc/2,remote_proc/2, dump_maps/0,create_maps/0, diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl index 0ea38bcfe21e..0247c436a111 100644 --- a/lib/sasl/test/sasl_SUITE.erl +++ b/lib/sasl/test/sasl_SUITE.erl @@ -24,7 +24,7 @@ %% don't use it. Therefore, we explicitly disable it until OTP 25 is out of %% support. -feature(maybe_expr, disable). --compile(r24). +-compile(r25). -include_lib("common_test/include/ct.hrl"). diff --git a/lib/stdlib/test/stdlib_SUITE.erl b/lib/stdlib/test/stdlib_SUITE.erl index 061e1bc96c1a..26d8e2fc944a 100644 --- a/lib/stdlib/test/stdlib_SUITE.erl +++ b/lib/stdlib/test/stdlib_SUITE.erl @@ -27,7 +27,7 @@ %% don't use it. Therefore, we explicitly disable it until OTP 25 is out of %% support. -feature(maybe_expr, disable). --compile(r24). +-compile(r25). -include_lib("common_test/include/ct.hrl"). -export([all/0, suite/0, init_per_suite/1, end_per_suite/1,