summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Gustavsson <bjorn@erlang.org>2021-10-13 09:23:11 +0200
committerBjörn Gustavsson <bjorn@erlang.org>2021-10-14 17:12:49 +0200
commit08f397986125047900a18275cc04a8c440f1c5ce (patch)
tree463464ae5848f0e2ea5899e57bf14327b9c6c700
parent36d78533bdd0c820843ed71747104c7049ee42db (diff)
downloaderlang-08f397986125047900a18275cc04a8c440f1c5ce.tar.gz
fixup! compiler: Add a new instruction for creating binaries
-rw-r--r--erts/emulator/beam/erl_bits.c42
-rw-r--r--erts/emulator/beam/erl_bits.h2
-rw-r--r--erts/emulator/beam/jit/arm/instr_bs.cpp91
-rw-r--r--erts/emulator/beam/jit/beam_jit_common.cpp34
-rw-r--r--erts/emulator/beam/jit/beam_jit_common.hpp36
-rw-r--r--erts/emulator/beam/jit/x86/instr_bs.cpp95
-rw-r--r--erts/emulator/test/bs_construct_SUITE.erl136
-rw-r--r--lib/kernel/src/erl_erts_errors.erl90
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.