diff options
author | Björn Gustavsson <bjorn@erlang.org> | 2021-10-13 09:23:11 +0200 |
---|---|---|
committer | Björn Gustavsson <bjorn@erlang.org> | 2021-10-14 17:12:49 +0200 |
commit | 08f397986125047900a18275cc04a8c440f1c5ce (patch) | |
tree | 463464ae5848f0e2ea5899e57bf14327b9c6c700 | |
parent | 36d78533bdd0c820843ed71747104c7049ee42db (diff) | |
download | erlang-08f397986125047900a18275cc04a8c440f1c5ce.tar.gz |
fixup! compiler: Add a new instruction for creating binaries
-rw-r--r-- | erts/emulator/beam/erl_bits.c | 42 | ||||
-rw-r--r-- | erts/emulator/beam/erl_bits.h | 2 | ||||
-rw-r--r-- | erts/emulator/beam/jit/arm/instr_bs.cpp | 91 | ||||
-rw-r--r-- | erts/emulator/beam/jit/beam_jit_common.cpp | 34 | ||||
-rw-r--r-- | erts/emulator/beam/jit/beam_jit_common.hpp | 36 | ||||
-rw-r--r-- | erts/emulator/beam/jit/x86/instr_bs.cpp | 95 | ||||
-rw-r--r-- | erts/emulator/test/bs_construct_SUITE.erl | 136 | ||||
-rw-r--r-- | lib/kernel/src/erl_erts_errors.erl | 90 |
8 files changed, 302 insertions, 224 deletions
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c index 2fb0d26059..e24adbcdf6 100644 --- a/erts/emulator/beam/erl_bits.c +++ b/erts/emulator/beam/erl_bits.c @@ -1021,12 +1021,12 @@ erts_new_bs_put_binary(Process *c_p, Eterm arg, Uint num_bits) ERL_BITS_DEFINE_STATEP(c_p); if (!is_binary(arg)) { - c_p->fvalue = am_type; + c_p->fvalue = arg; return 0; } ERTS_GET_BINARY_BYTES(arg, bptr, bitoffs, bitsize); if (num_bits > 8*binary_size(arg)+bitsize) { - c_p->fvalue = am_short; + c_p->fvalue = arg; return 0; } copy_binary_to_buffer(erts_current_bin, erts_bin_offset, bptr, bitoffs, num_bits); @@ -1065,7 +1065,13 @@ erts_new_bs_put_binary_all(Process *c_p, Eterm arg, Uint unit) return 1; } -int +/* + * Returns THE_NON_VALUE on success. + * + * On failure, returns whichever was wrong of the value or the size, + * and sets c_p-fvalue to 'type', 'no_float', or 'invalid'. + */ +Eterm erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) { ERL_BITS_DEFINE_STATEP(c_p); @@ -1101,7 +1107,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) } else if (is_big(arg)) { if (big_to_double(arg, &u.f64) < 0) { c_p->fvalue = am_no_float; - return 0; + return arg; } #ifdef DOUBLE_MIDDLE_ENDIAN a = u.i32[1]; @@ -1112,7 +1118,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) #endif } else { c_p->fvalue = am_type; - return 0; + return arg; } } else if (num_bits == 32) { union { @@ -1135,7 +1141,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) double f64; if (big_to_double(arg, &f64) < 0) { c_p->fvalue = am_no_float; - return 0; + return arg; } ERTS_FP_CHECK_INIT(c_p); u.f32 = (float) f64; @@ -1143,7 +1149,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) a = u.i32; } else { c_p->fvalue = am_type; - return 0; + return arg; } } else if (num_bits == 16) { union { @@ -1166,7 +1172,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) double f64; if (big_to_double(arg, &f64) < 0) { c_p->fvalue = am_no_float; - return 0; + return arg; } ERTS_FP_CHECK_INIT(c_p); ERTS_FP_ERROR(c_p,f64,;); @@ -1174,11 +1180,11 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) a = u.i16; } else { c_p->fvalue = am_type; - return 0; + return arg; } } else { c_p->fvalue = am_invalid; - return 0; + return make_small(num_bits); } if (BIT_IS_MACHINE_ENDIAN(flags)) { @@ -1275,7 +1281,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) } else if (is_big(arg)) { if (big_to_double(arg, &f64) < 0) { c_p->fvalue = am_no_float; - return 0; + return arg; } #ifdef DOUBLE_MIDDLE_ENDIAN ftmp.fd = f64; @@ -1284,7 +1290,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) #endif } else { c_p->fvalue = am_type; - return 0; + return arg; } #ifdef DOUBLE_MIDDLE_ENDIAN fbuf.fw[0] = ftmp.fw[1]; @@ -1305,7 +1311,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) } else if (is_big(arg)) { if (big_to_double(arg, &f64) < 0) { c_p->fvalue = am_no_float; - return 0; + return arg; } ERTS_FP_CHECK_INIT(c_p); f32 = (float) f64; @@ -1313,7 +1319,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) bptr = (byte *) &f32; } else { c_p->fvalue = am_type; - return 0; + return arg; } } else if (num_bits == 16) { if (is_float(arg)) { @@ -1329,7 +1335,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) } else if (is_big(arg)) { if (big_to_double(arg, &f64) < 0) { c_p->fvalue = am_no_float; - return 0; + return arg; } ERTS_FP_CHECK_INIT(c_p); ERTS_FP_ERROR(c_p,f64,;); @@ -1337,11 +1343,11 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) bptr = (byte *) &f16; } else { c_p->fvalue = am_type; - return 0; + return arg; } } else { c_p->fvalue = am_invalid; - return 0; + return make_small(num_bits); } if (BIT_IS_MACHINE_ENDIAN(flags)) { erts_copy_bits(bptr, 0, 1, @@ -1354,7 +1360,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) } } erts_bin_offset += num_bits; - return 1; + return THE_NON_VALUE; } void diff --git a/erts/emulator/beam/erl_bits.h b/erts/emulator/beam/erl_bits.h index 5ac6dd9ca7..6f9fdaa7e8 100644 --- a/erts/emulator/beam/erl_bits.h +++ b/erts/emulator/beam/erl_bits.h @@ -173,7 +173,7 @@ int erts_bs_put_utf8(ERL_BITS_PROTO_1(Eterm Integer)); 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); -int erts_new_bs_put_float(Process *c_p, Eterm Float, Uint num_bits, int flags); +Eterm erts_new_bs_put_float(Process *c_p, Eterm Float, Uint num_bits, int flags); void erts_new_bs_put_string(ERL_BITS_PROTO_2(byte* iptr, Uint num_bytes)); Uint erts_bits_bufs_size(void); diff --git a/erts/emulator/beam/jit/arm/instr_bs.cpp b/erts/emulator/beam/jit/arm/instr_bs.cpp index 2914dd0ebf..0b2ae2100d 100644 --- a/erts/emulator/beam/jit/arm/instr_bs.cpp +++ b/erts/emulator/beam/jit/arm/instr_bs.cpp @@ -466,9 +466,9 @@ void BeamModuleAssembler::emit_i_new_bs_put_float(const ArgVal &Fail, emit_leave_runtime(); if (Fail.getValue() != 0) { - a.cbz(ARG1, fail); + emit_branch_if_value(ARG1, fail); } else { - a.cbnz(ARG1, next); + emit_branch_if_not_value(ARG1, next); } } @@ -495,11 +495,11 @@ void BeamModuleAssembler::emit_i_new_bs_put_float_imm(const ArgVal &Fail, emit_leave_runtime(); if (Fail.getValue() != 0) { - a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); + emit_branch_if_value(ARG1, resolve_beam_label(Fail, disp1MB)); } else { Label next = a.newLabel(); - a.cbnz(ARG1, next); + emit_branch_if_not_value(ARG1, next); emit_error(BADARG); a.bind(next); } @@ -1361,7 +1361,6 @@ void BeamGlobalAssembler::emit_bs_create_bin_error_shared() { emit_enter_runtime<Update::eStack | Update::eHeap>(0); - a.mov(ARG3, ARG1); a.mov(ARG2, ARG4); a.mov(ARG1, c_p); runtime_call<3>(beam_jit_bs_construct_fail_info); @@ -1534,7 +1533,7 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, /* * ARG4 = packed error information - * ARG1 = optional bad size value; only valid if + * ARG3 = optional bad size value; only valid if * BSC_REASON_DEPENDS is set in ARG4 */ fragment_call(ga->get_bs_create_bin_error_shared()); @@ -1568,35 +1567,32 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, seg.type == am_binary) { comment("size of an entire binary"); mov_arg(ARG1, seg.src); + a.mov(ARG3, ARG1); fragment_call(ga->get_bs_bit_size_shared()); if (Fail.getValue() == 0) { mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); } a.cond_mi().b(resolve_label(error, disp1MB)); a.add(sizeReg, sizeReg, ARG1); } else if (seg.unit != 0) { comment("size binary/integer/float/string"); - mov_arg(ARG1, seg.size); - a.and_(TMP2, ARG1, imm(_TAG_IMMED1_MASK)); + mov_arg(ARG3, seg.size); + a.and_(TMP2, ARG3, imm(_TAG_IMMED1_MASK)); a.cmp(TMP2, imm(_TAG_IMMED1_SMALL)); if (Fail.getValue() == 0) { mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_DEPENDS, - BSC_INFO_DEPENDS)); + BSC_INFO_SIZE, + BSC_VALUE_ARG3)); } a.cond_ne().b(resolve_label(error, disp1MB)); - if (Fail.getValue() == 0) { - mov_imm(ARG4, - beam_jit_update_bsc_reason_info(seg.error_info, - BSC_REASON_BADARG, - BSC_INFO_NEGATIVE)); - } - a.tbnz(ARG1, 63, resolve_label(error, disp32K)); - a.asr(TMP1, ARG1, imm(_TAG_IMMED1_SIZE)); + a.tbnz(ARG3, 63, resolve_label(error, disp32K)); + a.asr(TMP1, ARG3, imm(_TAG_IMMED1_SIZE)); if (seg.unit == 1) { a.add(sizeReg, sizeReg, TMP1); } else { @@ -1605,7 +1601,8 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, beam_jit_update_bsc_reason_info( seg.error_info, BSC_REASON_SYSTEM_LIMIT, - BSC_INFO_SIZE)); + BSC_INFO_SIZE, + BSC_VALUE_ARG3)); } a.tst(TMP1, imm(0xffful << 52)); a.cond_ne().b(resolve_label(error, disp1MB)); @@ -1656,31 +1653,32 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, Label next = a.newLabel(); comment("size utf32"); - auto src_reg = load_source(seg.src, TMP1); + mov_arg(ARG3, seg.src); if (Fail.getValue() == 0) { mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); } a.add(sizeReg, sizeReg, imm(4 * 8)); - a.and_(TMP2, src_reg.reg, imm(_TAG_IMMED1_MASK)); + a.and_(TMP2, ARG3, imm(_TAG_IMMED1_MASK)); a.cmp(TMP2, imm(_TAG_IMMED1_SMALL)); a.cond_ne().b(error); mov_imm(TMP2, make_small(0xD800UL)); - a.cmp(src_reg.reg, TMP2); + a.cmp(ARG3, TMP2); a.cond_lo().b(next); mov_imm(TMP2, make_small(0xDFFFUL)); - a.cmp(src_reg.reg, TMP2); + a.cmp(ARG3, TMP2); a.cond_ls().b(error); mov_imm(TMP2, make_small(0x10FFFFUL)); - a.cmp(src_reg.reg, TMP2); + a.cmp(ARG3, TMP2); a.cond_hi().b(error); a.bind(next); @@ -1716,10 +1714,12 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, Update::eReductions>(Live.getValue() + 1); if (Fail.getValue() == 0) { + mov_arg(ARG3, ArgVal(ArgVal::XReg, Live.getValue())); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_FVALUE)); + BSC_INFO_FVALUE, + BSC_VALUE_ARG3)); } emit_branch_if_not_value(ARG1, resolve_label(error, dispUnknown)); } else if (segments[0].type == am_private_append) { @@ -1739,13 +1739,7 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, emit_enter_runtime(Live.getValue()); runtime_call<4>(erts_bs_private_append_checked); emit_leave_runtime(Live.getValue()); - if (Fail.getValue() == 0) { - mov_imm(ARG4, - beam_jit_update_bsc_reason_info(seg.error_info, - BSC_REASON_FREASON, - BSC_INFO_FVALUE)); - } - emit_branch_if_not_value(ARG1, resolve_label(error, dispUnknown)); + /* There is no way the call can fail on a 64-bit architecture. */ } else { comment("allocate binary"); mov_arg(ARG5, Alloc); @@ -1791,7 +1785,8 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, runtime_call<3>(erts_new_bs_put_binary); error_info = beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_FVALUE); + BSC_INFO_DEPENDS, + BSC_VALUE_FVALUE); } else if (seg.size.isImmed() && seg.size.getValue() == am_all) { /* Include the entire binary/bitstring in the * resulting binary. */ @@ -1801,7 +1796,8 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, runtime_call<3>(erts_new_bs_put_binary_all); error_info = beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_UNIT); + BSC_INFO_UNIT, + BSC_VALUE_FVALUE); } else { /* The size is a variable. We have verified that * the value is a non-negative small in the @@ -1818,7 +1814,8 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, runtime_call<3>(erts_new_bs_put_binary); error_info = beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_FVALUE); + BSC_INFO_DEPENDS, + BSC_VALUE_FVALUE); } emit_leave_runtime<Update::eReductions>(Live.getValue()); if (Fail.getValue() == 0) { @@ -1851,9 +1848,11 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_FVALUE)); + BSC_INFO_FVALUE, + BSC_VALUE_ARG3)); + a.mov(ARG3, ARG1); } - a.cbz(ARG1, resolve_label(error, disp1MB)); + emit_branch_if_value(ARG1, resolve_label(error, dispUnknown)); break; case am_integer: comment("construct integer segment"); @@ -1876,10 +1875,12 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, emit_leave_runtime(Live.getValue()); if (Fail.getValue() == 0) { + mov_arg(ARG3, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); } a.cbz(ARG1, resolve_label(error, disp1MB)); break; @@ -1906,10 +1907,12 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, emit_leave_runtime(Live.getValue()); if (Fail.getValue() == 0) { + mov_arg(ARG3, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); } a.cbz(ARG1, resolve_label(error, disp1MB)); break; @@ -1924,10 +1927,12 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, emit_leave_runtime(Live.getValue()); if (Fail.getValue() == 0) { + mov_arg(ARG3, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); } a.cbz(ARG1, resolve_label(error, disp1MB)); break; @@ -1942,10 +1947,12 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, emit_leave_runtime(Live.getValue()); if (Fail.getValue() == 0) { + mov_arg(ARG3, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); } a.cbz(ARG1, resolve_label(error, disp1MB)); break; diff --git a/erts/emulator/beam/jit/beam_jit_common.cpp b/erts/emulator/beam/jit/beam_jit_common.cpp index 6025b0130f..0f3afc6536 100644 --- a/erts/emulator/beam/jit/beam_jit_common.cpp +++ b/erts/emulator/beam/jit/beam_jit_common.cpp @@ -741,15 +741,17 @@ Eterm beam_jit_bs_get_integer(Process *c_p, void beam_jit_bs_construct_fail_info(Process *c_p, Uint packed_error_info, Eterm bad_value) { - Eterm *hp = HAlloc(c_p, Sint(MAP3_SZ + 3 + 1)); + Eterm *hp; Eterm cause_tuple; Eterm error_info; Uint segment = beam_jit_get_bsc_segment(packed_error_info); Uint op = beam_jit_get_bsc_op(packed_error_info); Uint info = beam_jit_get_bsc_info(packed_error_info); Uint reason = beam_jit_get_bsc_reason(packed_error_info); + Uint value_location = beam_jit_get_bsc_value(packed_error_info); Eterm Op = am_none; Eterm Info = am_none; + Eterm value = am_undefined; switch (op) { case BSC_OP_BINARY: @@ -792,6 +794,19 @@ void beam_jit_bs_construct_fail_info(Process *c_p, break; } + switch (value_location) { +#if defined(__aarch64__) + case BSC_VALUE_ARG3: +#else + case BSC_VALUE_ARG1: +#endif + value = bad_value; + break; + case BSC_VALUE_FVALUE: + value = c_p->fvalue; + break; + } + switch (info) { case BSC_INFO_FVALUE: Info = c_p->fvalue; @@ -802,25 +817,18 @@ void beam_jit_bs_construct_fail_info(Process *c_p, case BSC_INFO_SIZE: Info = am_size; break; - case BSC_INFO_NEGATIVE: - Info = am_negative_size; - break; case BSC_INFO_UNIT: Info = am_unit; break; case BSC_INFO_DEPENDS: - if (reason == SYSTEM_LIMIT) { - Info = am_size; - } else if (is_small(bad_value) || is_big(bad_value)) { - Info = am_negative_size; - } else { - Info = am_size; - } + ASSERT(op == BSC_OP_BINARY); + Info = is_binary(value) ? am_short : am_type; break; } - cause_tuple = TUPLE3(hp, make_small(segment), Op, Info); - hp += 4; + hp = HAlloc(c_p, Sint(MAP3_SZ + 5)); + cause_tuple = TUPLE4(hp, make_small(segment), Op, Info, value); + hp += 5; error_info = MAP3(hp, am_cause, cause_tuple, diff --git a/erts/emulator/beam/jit/beam_jit_common.hpp b/erts/emulator/beam/jit/beam_jit_common.hpp index 5542919409..ed508ee416 100644 --- a/erts/emulator/beam/jit/beam_jit_common.hpp +++ b/erts/emulator/beam/jit/beam_jit_common.hpp @@ -235,7 +235,7 @@ public: } }; -static const Uint BSC_SEGMENT_OFFSET = 8; +static const Uint BSC_SEGMENT_OFFSET = 9; typedef enum : Uint { BSC_OP_BINARY = 0, @@ -246,20 +246,18 @@ typedef enum : Uint { BSC_OP_UTF32 = 5, BSC_OP_LAST = 5, BSC_OP_MASK = 0x07, - BSC_OP_OFFSET = 5 + BSC_OP_OFFSET = 6 } JitBSCOp; typedef enum : Uint { BSC_INFO_FVALUE = 0, BSC_INFO_TYPE = 1, BSC_INFO_SIZE = 2, - BSC_INFO_NEGATIVE = 3, - BSC_INFO_UNIT = 4, - BSC_INFO_DEPENDS_ARG1 = 5, - BSC_INFO_DEPENDS_FVALUE = 6, - BSC_INFO_LAST = 6, + BSC_INFO_UNIT = 3, + BSC_INFO_DEPENDS = 4, + BSC_INFO_LAST = 4, BSC_INFO_MASK = 0x07, - BSC_INFO_OFFSET = 2, + BSC_INFO_OFFSET = 3, } JitBSCInfo; typedef enum : Uint { @@ -271,14 +269,27 @@ typedef enum : Uint { BSC_REASON_MASK = 0x03 } JitBSCReason; +typedef enum : Uint { +#if defined(__aarch64__) + BSC_VALUE_ARG3 = 0, +#else + BSC_VALUE_ARG1 = 0, +#endif + BSC_VALUE_FVALUE = 1, + BSC_VALUE_LAST = 1, + BSC_VALUE_MASK = 0x01, + BSC_VALUE_OFFSET = 2 +} JitBSCValue; + static constexpr Uint beam_jit_set_bsc_segment_op(Uint segment, JitBSCOp op) { return (segment << BSC_SEGMENT_OFFSET) | (op << BSC_OP_OFFSET); } static constexpr Uint beam_jit_update_bsc_reason_info(Uint packed_info, JitBSCReason reason, - JitBSCInfo info) { - return packed_info | (info << BSC_INFO_OFFSET) | reason; + JitBSCInfo info, + JitBSCValue value) { + return packed_info | (value << BSC_VALUE_OFFSET) | (info << BSC_INFO_OFFSET) | reason; } static constexpr Uint beam_jit_get_bsc_segment(Uint packed_info) { @@ -300,6 +311,11 @@ static constexpr JitBSCReason beam_jit_get_bsc_reason(Uint packed_info) { return (JitBSCReason)(packed_info & BSC_REASON_MASK); } +static constexpr JitBSCValue beam_jit_get_bsc_value(Uint packed_info) { + ERTS_CT_ASSERT((BSC_VALUE_LAST & ~BSC_VALUE_MASK) == 0); + return (JitBSCValue)((packed_info >> BSC_VALUE_OFFSET) & BSC_VALUE_MASK); +} + /* ** */ #if defined(DEBUG) && defined(JIT_HARD_DEBUG) diff --git a/erts/emulator/beam/jit/x86/instr_bs.cpp b/erts/emulator/beam/jit/x86/instr_bs.cpp index a5e02af410..8d7ba7d1c7 100644 --- a/erts/emulator/beam/jit/x86/instr_bs.cpp +++ b/erts/emulator/beam/jit/x86/instr_bs.cpp @@ -488,12 +488,12 @@ void BeamModuleAssembler::emit_i_new_bs_put_float(const ArgVal &Fail, emit_leave_runtime(); - a.test(RET, RET); + emit_test_the_non_value(RET); if (Fail.getValue() != 0) { - a.je(fail); + a.jne(fail); } else { - a.short_().jne(next); + a.short_().je(next); } } @@ -525,12 +525,12 @@ void BeamModuleAssembler::emit_i_new_bs_put_float_imm(const ArgVal &Fail, emit_leave_runtime(); - a.test(RET, RET); + emit_test_the_non_value(RET); if (Fail.getValue() != 0) { - a.je(labels[Fail.getValue()]); + a.jne(labels[Fail.getValue()]); } else { - a.short_().jne(next); + a.short_().je(next); emit_error(BADARG); a.bind(next); } @@ -1755,10 +1755,12 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, mov_arg(ARG1, seg.src); runtime_call<1>(beam_jit_bs_bit_size); if (Fail.getValue() == 0) { + mov_arg(ARG1, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); } a.test(RET, RET); a.js(error); @@ -1773,28 +1775,23 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_DEPENDS, - BSC_INFO_DEPENDS_ARG1)); + BSC_INFO_SIZE, + BSC_VALUE_ARG1)); } a.jne(error); - if (Fail.getValue() == 0) { - mov_imm(ARG4, - beam_jit_update_bsc_reason_info(seg.error_info, - BSC_REASON_BADARG, - BSC_INFO_NEGATIVE)); - } - a.sar(ARG1, imm(_TAG_IMMED1_SIZE)); + a.mov(RET, ARG1); + a.sar(RET, imm(_TAG_IMMED1_SIZE)); a.js(error); - if (seg.unit == 1) { - a.mov(RET, ARG1); - } else { + if (seg.unit != 1) { if (Fail.getValue() == 0) { mov_imm(ARG4, beam_jit_update_bsc_reason_info( seg.error_info, BSC_REASON_SYSTEM_LIMIT, - BSC_INFO_SIZE)); + BSC_INFO_SIZE, + BSC_VALUE_ARG1)); } - a.imul(RET, ARG1, imm(seg.unit)); + a.imul(RET, RET, imm(seg.unit)); a.jo(error); } a.add(sizeReg, RET); @@ -1843,7 +1840,8 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); } a.add(sizeReg, imm(4 * 8)); @@ -1886,10 +1884,12 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, load_x_reg_array(ARG2); runtime_call<6>(erts_bs_append_checked); if (Fail.getValue() == 0) { + mov_arg(ARG1, ArgVal(ArgVal::XReg, Live.getValue())); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_FVALUE)); + BSC_INFO_FVALUE, + BSC_VALUE_ARG1)); } emit_test_the_non_value(RET); a.je(error); @@ -1908,14 +1908,7 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, a.mov(ARG4, seg.unit); a.mov(ARG1, c_p); runtime_call<4>(erts_bs_private_append_checked); - if (Fail.getValue() == 0) { - mov_imm(ARG4, - beam_jit_update_bsc_reason_info(seg.error_info, - BSC_REASON_FREASON, - BSC_INFO_FVALUE)); - } - emit_test_the_non_value(RET); - a.je(error); + /* There is no way the call can fail on a 64-bit architecture. */ } else { comment("allocate binary"); mov_arg(ARG5, Alloc); @@ -1956,7 +1949,8 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, runtime_call<3>(erts_new_bs_put_binary); error_info = beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_FVALUE); + BSC_INFO_DEPENDS, + BSC_VALUE_FVALUE); } else if (seg.size.isImmed() && seg.size.getValue() == am_all) { /* Include the entire binary/bitstring in the * resulting binary. */ @@ -1966,7 +1960,8 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, runtime_call<3>(erts_new_bs_put_binary_all); error_info = beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_UNIT); + BSC_INFO_UNIT, + BSC_VALUE_FVALUE); } else { /* The size is a variable. We have verified that * the value is a non-negative small in the @@ -1984,12 +1979,13 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, runtime_call<3>(erts_new_bs_put_binary); error_info = beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_FVALUE); + BSC_INFO_DEPENDS, + BSC_VALUE_FVALUE); } if (Fail.getValue() == 0) { mov_imm(ARG4, error_info); } - a.test(RET, RET); + a.test(RETd, RETd); a.je(error); break; } @@ -2011,13 +2007,16 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, a.mov(ARG1, c_p); runtime_call<4>(erts_new_bs_put_float); if (Fail.getValue() == 0) { + mov_arg(ARG1, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_FVALUE)); + BSC_INFO_FVALUE, + BSC_VALUE_ARG1)); } - a.test(RET, RET); - a.je(error); + a.mov(ARG1, RET); + emit_test_the_non_value(RET); + a.jne(error); break; case am_integer: comment("construct integer segment"); @@ -2036,12 +2035,14 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, mov_imm(ARG4, seg.flags); load_erl_bits_state(ARG1); runtime_call<4>(erts_new_bs_put_integer); - a.test(RET, RET); + a.test(RETd, RETd); if (Fail.getValue() == 0) { + mov_arg(ARG1, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); } a.je(error); break; @@ -2058,10 +2059,12 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, load_erl_bits_state(ARG1); runtime_call<2>(erts_bs_put_utf8); if (Fail.getValue() == 0) { + mov_arg(ARG1, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); } a.test(RET, RET); a.je(error); @@ -2072,12 +2075,14 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, load_erl_bits_state(ARG1); runtime_call<3>(erts_bs_put_utf16); if (Fail.getValue() == 0) { + mov_arg(ARG1, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); } - a.test(RET, RET); + a.test(RETd, RETd); a.je(error); break; case am_utf32: @@ -2087,12 +2092,14 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgVal &Fail, load_erl_bits_state(ARG1); runtime_call<4>(erts_new_bs_put_integer); if (Fail.getValue() == 0) { + mov_arg(ARG1, seg.src); mov_imm(ARG4, beam_jit_update_bsc_reason_info(seg.error_info, BSC_REASON_BADARG, - BSC_INFO_TYPE)); + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); } - a.test(RET, RET); + a.test(RETd, RETd); a.je(error); break; default: diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl index 5f3cea1bcb..5cf34a5507 100644 --- a/erts/emulator/test/bs_construct_SUITE.erl +++ b/erts/emulator/test/bs_construct_SUITE.erl @@ -994,83 +994,89 @@ fp16(_Config) -> end()). error_info(_Config) -> - Atom = id(atom), - NegativeSize = id(-1), - HugeNegativeSize = id(-1 bsl 64), + Atom = id(some_atom), + NegSize = id(-1), + HugeNegSize = id(-1 bsl 64), Binary = id(<<"abc">>), HugeBig = id(1 bsl 1500), - - {badarg, {1,binary,type}} = ?ERROR_INFO(<<Atom/binary, Binary/binary>>), - {badarg, {2,binary,type}} = ?ERROR_INFO(<<Binary/binary, Atom/binary>>), - {badarg, {3,binary,type}} = ?ERROR_INFO(<<1:32, Binary/binary, Atom/binary>>), - {badarg, {4,binary,type}} = ?ERROR_INFO(<<1:32, "xyz", Binary/binary, Atom/binary>>), - - {badarg, {1,integer,type}} = ?ERROR_INFO(<<Atom:32>>), - {badarg, {1,integer,size}} = ?ERROR_INFO(<<42:Atom>>), - {badarg, {1,integer,negative_size}} = ?ERROR_INFO(<<42:NegativeSize>>), - {badarg, {1,integer,negative_size}} = ?ERROR_INFO(<<42:HugeNegativeSize>>), - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<42:(1 bsl 58)/unit:255>>), - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<42:(1 bsl 60)/unit:8>>), - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<42:(1 bsl 64)>>), - - {badarg, {1,binary,type}} = ?ERROR_INFO(<<Atom:10/binary>>), - {badarg, {1,binary,size}} = ?ERROR_INFO(<<Binary:Atom/binary>>), - {badarg, {1,binary,negative_size}} = ?ERROR_INFO(<<Binary:NegativeSize/binary>>), - {badarg, {1,binary,negative_size}} = ?ERROR_INFO(<<Binary:HugeNegativeSize/binary>>), - {system_limit, {1,binary,size}} = ?ERROR_INFO(<<Binary:(1 bsl 64)/binary>>), - {badarg, {1,binary,short}} = ?ERROR_INFO(<<Binary:10/binary>>), - {badarg, {1,binary,type}} = ?ERROR_INFO(<<Atom/binary>>), - - {badarg, {1,float,type}} = ?ERROR_INFO(<<Atom:64/float>>), - {badarg, {1,float,size}} = ?ERROR_INFO(<<Atom:Atom/float>>), - {badarg, {1,float,negative_size}} = ?ERROR_INFO(<<42.0:NegativeSize/float>>), - {badarg, {1,float,negative_size}} = ?ERROR_INFO(<<42.0:HugeNegativeSize/float>>), - {badarg, {1,float,invalid}} = ?ERROR_INFO(<<42.0:(id(1))/float>>), - {badarg, {1,float,no_float}} = ?ERROR_INFO(<<HugeBig:(id(64))/float>>), - {badarg, {1,float,no_float}} = ?ERROR_INFO(<<HugeBig:64/float>>), - {system_limit, {1,float,size}} = ?ERROR_INFO(<<42.0:(id(1 bsl 64))/float>>), - - {badarg, {1,utf8,type}} = ?ERROR_INFO(<<Atom/utf8>>), - {badarg, {1,utf16,type}} = ?ERROR_INFO(<<Atom/utf16>>), - {badarg, {1,utf32,type}} = ?ERROR_INFO(<<Atom/utf32>>), + LongList = lists:seq(1, 100), + + {badarg, {1,binary,type,Atom}} = ?ERROR_INFO(<<Atom/binary, Binary/binary>>), + {badarg, {2,binary,type,Atom}} = ?ERROR_INFO(<<Binary/binary, Atom/binary>>), + {badarg, {3,binary,type,Atom}} = ?ERROR_INFO(<<1:32, Binary/binary, Atom/binary>>), + {badarg, {4,binary,type,Atom}} = ?ERROR_INFO(<<1:32, "xyz", Binary/binary, Atom/binary>>), + + {badarg, {1,integer,type,Atom}} = ?ERROR_INFO(<<Atom:32>>), + {badarg, {1,integer,type,LongList}} = ?ERROR_INFO(<<LongList:32>>), + {badarg, {1,integer,size,Atom}} = ?ERROR_INFO(<<42:Atom>>), + {badarg, {1,integer,type,Atom}} = ?ERROR_INFO(<<Atom:32>>), + {badarg, {1,integer,size,NegSize}} = ?ERROR_INFO(<<42:NegSize>>), + {badarg, {1,integer,size,HugeNegSize}} = ?ERROR_INFO(<<42:HugeNegSize>>), + {system_limit, {1,integer,size,1 bsl 58}} = ?ERROR_INFO(<<42:(1 bsl 58)/unit:255>>), + {system_limit, {1,integer,size,1 bsl 60}} = ?ERROR_INFO(<<42:(1 bsl 60)/unit:8>>), + {system_limit, {1,integer,size,1 bsl 64}} = ?ERROR_INFO(<<42:(1 bsl 64)>>), + + {badarg, {1,binary,type,Atom}} = ?ERROR_INFO(<<Atom:10/binary>>), + {badarg, {1,binary,size,Atom}} = ?ERROR_INFO(<<Binary:Atom/binary>>), + {badarg, {1,binary,size,NegSize}} = ?ERROR_INFO(<<Binary:NegSize/binary>>), + {badarg, {1,binary,size,HugeNegSize}} = ?ERROR_INFO(<<Binary:HugeNegSize/binary>>), + {badarg, {1,binary,short,Binary}} = ?ERROR_INFO(<<Binary:10/binary>>), + {badarg, {1,binary,type,Atom}} = ?ERROR_INFO(<<Atom/binary>>), + {badarg, {1,binary,unit,<<1:1>>}} = ?ERROR_INFO(<<(id(<<1:1>>))/binary>>), + {badarg, {1,binary,unit,<<0:1111>>}} = ?ERROR_INFO(<<(id(<<0:1111>>))/binary>>), + {system_limit, {1,binary,size,1 bsl 64}} = ?ERROR_INFO(<<Binary:(1 bsl 64)/binary>>), + + {badarg, {1,float,type,Atom}} = ?ERROR_INFO(<<Atom:64/float>>), + {badarg, {1,float,size,Atom}} = ?ERROR_INFO(<<Atom:Atom/float>>), + {badarg, {1,float,size,NegSize}} = ?ERROR_INFO(<<42.0:NegSize/float>>), + {badarg, {1,float,size,HugeNegSize}} = ?ERROR_INFO(<<42.0:HugeNegSize/float>>), + {badarg, {1,float,invalid,1}} = ?ERROR_INFO(<<42.0:(id(1))/float>>), + {badarg, {1,float,no_float,HugeBig}} = ?ERROR_INFO(<<HugeBig:(id(64))/float>>), + {badarg, {1,float,no_float,HugeBig}} = ?ERROR_INFO(<<HugeBig:64/float>>), + {system_limit, {1,float,size,1 bsl 64}} = ?ERROR_INFO(<<42.0:(id(1 bsl 64))/float>>), + + {badarg, {1,utf8,type,Atom}} = ?ERROR_INFO(<<Atom/utf8>>), + {badarg, {1,utf16,type,Atom}} = ?ERROR_INFO(<<Atom/utf16>>), + {badarg, {1,utf32,type,Atom}} = ?ERROR_INFO(<<Atom/utf32>>), Bin = id(<<>>), Float = id(42.0), + MaxSmall = (1 bsl 59) - 1, %Max small for 64-bit architectures. %% Attempt constructing a binary with total size 1^64 + 32. - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<0:((1 bsl 59)-1)/unit:32,0:64>>), - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<0:((1 bsl 59)-1)/unit:32,(id(0)):64>>), - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<0:(id((1 bsl 59)-1))/unit:32,0:64>>), - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<0:(id((1 bsl 59)-1))/unit:32,(id(0)):64>>), + {system_limit, {1,integer,size,MaxSmall}} = ?ERROR_INFO(<<0:(MaxSmall)/unit:32,0:64>>), + {system_limit, {1,integer,size,MaxSmall}} = ?ERROR_INFO(<<0:(MaxSmall)/unit:32,(id(0)):64>>), + {system_limit, {1,integer,size,MaxSmall}} = ?ERROR_INFO(<<0:(id(MaxSmall))/unit:32,0:64>>), + {system_limit, {1,integer,size,MaxSmall}} = ?ERROR_INFO(<<0:(id(MaxSmall))/unit:32,(id(0)):64>>), - {system_limit, {1,binary,size}} = ?ERROR_INFO(<<Bin:((1 bsl 59)-1)/binary-unit:32,0:64>>), - {system_limit, {1,binary,size}} = ?ERROR_INFO(<<Bin:((1 bsl 59)-1)/binary-unit:32,(id(0)):64>>), - {system_limit, {1,binary,size}} = ?ERROR_INFO(<<Bin:(id((1 bsl 59)-1))/binary-unit:32,0:64>>), - {system_limit, {1,binary,size}} = ?ERROR_INFO(<<Bin:(id((1 bsl 59)-1))/binary-unit:32,(id(0)):64>>), + {system_limit, {1,binary,size,MaxSmall}} = ?ERROR_INFO(<<Bin:(MaxSmall)/binary-unit:32,0:64>>), + {system_limit, {1,binary,size,MaxSmall}} = ?ERROR_INFO(<<Bin:(MaxSmall)/binary-unit:32,(id(0)):64>>), + {system_limit, {1,binary,size,MaxSmall}} = ?ERROR_INFO(<<Bin:(id(MaxSmall))/binary-unit:32,0:64>>), + {system_limit, {1,binary,size,MaxSmall}} = ?ERROR_INFO(<<Bin:(id(MaxSmall))/binary-unit:32,(id(0)):64>>), - {system_limit, {1,float,size}} = ?ERROR_INFO(<<Float:((1 bsl 59)-1)/float-unit:32,0:64>>), - {system_limit, {1,float,size}} = ?ERROR_INFO(<<Float:((1 bsl 59)-1)/float-unit:32,(id(0)):64>>), - {system_limit, {1,float,size}} = ?ERROR_INFO(<<Float:(id((1 bsl 59)-1))/float-unit:32,0:64>>), - {system_limit, {1,float,size}} = ?ERROR_INFO(<<Float:(id((1 bsl 59)-1))/float-unit:32,(id(0)):64>>), + {system_limit, {1,float,size,MaxSmall}} = ?ERROR_INFO(<<Float:(MaxSmall)/float-unit:32,0:64>>), + {system_limit, {1,float,size,MaxSmall}} = ?ERROR_INFO(<<Float:(MaxSmall)/float-unit:32,(id(0)):64>>), + {system_limit, {1,float,size,MaxSmall}} = ?ERROR_INFO(<<Float:(id(MaxSmall))/float-unit:32,0:64>>), + {system_limit, {1,float,size,MaxSmall}} = ?ERROR_INFO(<<Float:(id(MaxSmall))/float-unit:32,(id(0)):64>>), %% Test a size exceeding 1^64, where the sign bit (bit 63) is not set. - 0 = ((((1 bsl 59)-1) * 33) bsr 63) band 1, %Assertion: The sign bit is not set. - - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<0:((1 bsl 59)-1)/unit:33>>), - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<0:((1 bsl 59)-1)/unit:33>>), - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<0:(id((1 bsl 59)-1))/unit:33>>), - {system_limit, {1,integer,size}} = ?ERROR_INFO(<<0:(id((1 bsl 59)-1))/unit:33>>), - - {system_limit, {1,binary,size}} = ?ERROR_INFO(<<Bin:((1 bsl 59)-1)/binary-unit:33>>), - {system_limit, {1,binary,size}} = ?ERROR_INFO(<<Bin:((1 bsl 59)-1)/binary-unit:33>>), - {system_limit, {1,binary,size}} = ?ERROR_INFO(<<Bin:(id((1 bsl 59)-1))/binary-unit:33>>), - {system_limit, {1,binary,size}} = ?ERROR_INFO(<<Bin:(id((1 bsl 59)-1))/binary-unit:33>>), - - {system_limit, {1,float,size}} = ?ERROR_INFO(<<Float:((1 bsl 59)-1)/float-unit:33>>), - {system_limit, {1,float,size}} = ?ERROR_INFO(<<Float:((1 bsl 59)-1)/float-unit:33>>), - {system_limit, {1,float,size}} = ?ERROR_INFO(<<Float:(id((1 bsl 59)-1))/float-unit:33>>), - {system_limit, {1,float,size}} = ?ERROR_INFO(<<Float:(id((1 bsl 59)-1))/float-unit:33>>), + 0 = (((MaxSmall) * 33) bsr 63) band 1, %Assertion: The sign bit is not set. + + {system_limit, {1,integer,size,MaxSmall}} = ?ERROR_INFO(<<0:(MaxSmall)/unit:33>>), + {system_limit, {1,integer,size,MaxSmall}} = ?ERROR_INFO(<<0:(MaxSmall)/unit:33>>), + {system_limit, {1,integer,size,MaxSmall}} = ?ERROR_INFO(<<0:(id(MaxSmall))/unit:33>>), + {system_limit, {1,integer,size,MaxSmall}} = ?ERROR_INFO(<<0:(id(MaxSmall))/unit:33>>), + + {system_limit, {1,binary,size,MaxSmall}} = ?ERROR_INFO(<<Bin:(MaxSmall)/binary-unit:33>>), + {system_limit, {1,binary,size,MaxSmall}} = ?ERROR_INFO(<<Bin:(MaxSmall)/binary-unit:33>>), + {system_limit, {1,binary,size,MaxSmall}} = ?ERROR_INFO(<<Bin:(id(MaxSmall))/binary-unit:33>>), + {system_limit, {1,binary,size,MaxSmall}} = ?ERROR_INFO(<<Bin:(id(MaxSmall))/binary-unit:33>>), + + {system_limit, {1,float,size,MaxSmall}} = ?ERROR_INFO(<<Float:(MaxSmall)/float-unit:33>>), + {system_limit, {1,float,size,MaxSmall}} = ?ERROR_INFO(<<Float:(MaxSmall)/float-unit:33>>), + {system_limit, {1,float,size,MaxSmall}} = ?ERROR_INFO(<<Float:(id(MaxSmall))/float-unit:33>>), + {system_limit, {1,float,size,MaxSmall}} = ?ERROR_INFO(<<Float:(id(MaxSmall))/float-unit:33>>), ok. diff --git a/lib/kernel/src/erl_erts_errors.erl b/lib/kernel/src/erl_erts_errors.erl index 66fcd1bb0b..1139e02e05 100644 --- a/lib/kernel/src/erl_erts_errors.erl +++ b/lib/kernel/src/erl_erts_errors.erl @@ -51,12 +51,12 @@ format_error(Reason, [{M,F,As,Info}|_]) -> format_bs_fail(Reason, [{_,_,_,Info}|_]) -> ErrorInfoMap = proplists:get_value(error_info, Info, #{}), case ErrorInfoMap of - #{cause := {Segment,Type,Error}} -> - Str0 = do_format_bs_fail( Reason, Type, Error), - Str1 = io_lib:format("failed constructing binary: segment ~p, type '~ts': ~ts", + #{cause := {Segment,Type,Error,Value}} -> + Str0 = do_format_bs_fail(Reason, Type, Error, Value), + Str1 = io_lib:format("segment ~p of type '~ts': ~ts", [Segment,Type,Str0]), Str = iolist_to_binary(Str1), - #{general => Str}; + #{general => Str, reason => <<"construction of binary failed">>}; #{} -> #{} end. @@ -1045,35 +1045,63 @@ format_erlang_error(whereis, [_], _) -> format_erlang_error(_, _, _) -> []. -do_format_bs_fail(system_limit, _Type, size) -> - <<"the size is too large">>; -do_format_bs_fail(badarg, Type, Info) -> - do_format_bs_fail(Type, Info). +do_format_bs_fail(system_limit, _Type, size, Value) -> + io_lib:format(<<"the size ~p is too large">>, [Value]); +do_format_bs_fail(badarg, Type, Info, Value) -> + do_format_bs_fail(Type, Info, Value). -do_format_bs_fail(float, invalid) -> - <<"the size is not one of the supported sizes (16, 32, or 64)">>; -do_format_bs_fail(float, no_float) -> - <<"the integer is outside the range expressible as a float of the given size">>; -do_format_bs_fail(binary, unit) -> - <<"the size of the given binary/bitstring is not a multiple of the unit for the segment">>; -do_format_bs_fail(_Type, short) -> - <<"the given binary/bitstring is shorter than the size of the segment">>; -do_format_bs_fail(_Type, negative_size) -> - <<"the size is negative">>; -do_format_bs_fail(_Type, size) -> - <<"the size is not an integer">>; -do_format_bs_fail(Type, type) -> - <<"not a", - (case Type of - binary -> - <<" binary">>; - float -> - <<" float or an integer">>; +do_format_bs_fail(float, invalid, Value) -> + io_lib:format(<<"expected one of the supported sizes 16, 32, or 64 but got: ~p">>, + [Value]); +do_format_bs_fail(float, no_float, Value) -> + io_lib:format(<<"the value ~ts is outside the range expressible as a float">>, + [possibly_truncated(Value)]); +do_format_bs_fail(binary, unit, Value) -> + io_lib:format(<<"the size of the value ~ts is not a multiple of the unit for the segment">>, + [possibly_truncated(Value)]); +do_format_bs_fail(_Type, short, Value) -> + io_lib:format(<<"the value ~ts is shorter than the size of the segment">>, + [possibly_truncated(Value)]); +do_format_bs_fail(_Type, size, Value) -> + io_lib:format(<<"expected a non-negative integer as size but got: ~ts">>, + [possibly_truncated(Value)]); +do_format_bs_fail(Type, type, Value) -> + F = <<"expected a", + (case Type of + binary -> + <<" binary">>; + float -> + <<" float or an integer">>; integer -> - <<"n integer">>; - _ -> - <<"n integer encodable as ", (atom_to_binary(Type))/binary>> - end)/binary>>. + <<"n integer">>; + _ -> + <<" non-negative integer encodable as ", (atom_to_binary(Type))/binary>> + end)/binary, " but got: ~ts">>, + io_lib:format(F, [possibly_truncated(Value)]). + +possibly_truncated(Int) when is_integer(Int) -> + Bin = integer_to_binary(Int), + case byte_size(Bin) of + Size when Size < 48 -> + Bin; + Size -> + <<Prefix:12/binary, _:(Size-24)/binary, Suffix/binary>> = Bin, + [Prefix, <<"...">>, Suffix] + end; +possibly_truncated(Bin) when is_bitstring(Bin) -> + case byte_size(Bin) of + Size when Size < 16 -> + io_lib:format("~p", [Bin]); + Size -> + <<Prefix0:8/binary, _:(Size-10)/binary, Suffix0/bitstring>> = Bin, + Prefix1 = iolist_to_binary(io_lib:format("~w", [Prefix0])), + <<Prefix:(byte_size(Prefix1)-2)/binary,_/binary>> = Prefix1, + <<_:2/unit:8,Suffix/binary>> = iolist_to_binary(io_lib:format("~w", [Suffix0])), + [Prefix, <<"...,">>, Suffix] + end; +%% possibly_truncated(Value) when is_bitstring(Value) -> +possibly_truncated(Value) -> + io_lib:format("~P", [Value,20]). %%% %%% Utility functions. |