aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r--erts/emulator/beam/atom.names1
-rw-r--r--erts/emulator/beam/beam_debug.c15
-rw-r--r--erts/emulator/beam/beam_emu.c22
-rw-r--r--erts/emulator/beam/beam_load.c285
-rw-r--r--erts/emulator/beam/bif.c1
-rw-r--r--erts/emulator/beam/bif.tab2
-rw-r--r--erts/emulator/beam/dist.c114
-rw-r--r--erts/emulator/beam/dist.h3
-rw-r--r--erts/emulator/beam/erl_bif_info.c23
-rw-r--r--erts/emulator/beam/erl_binary.h11
-rw-r--r--erts/emulator/beam/erl_nif.c28
-rw-r--r--erts/emulator/beam/erl_node_tables.c2
-rw-r--r--erts/emulator/beam/erl_node_tables.h1
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c10
-rw-r--r--erts/emulator/beam/erl_process.c35
-rw-r--r--erts/emulator/beam/erl_process.h1
-rw-r--r--erts/emulator/beam/instrs.tab62
-rw-r--r--erts/emulator/beam/map_instrs.tab28
-rw-r--r--erts/emulator/beam/ops.tab193
19 files changed, 589 insertions, 248 deletions
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index f81082a698..412d689246 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -290,6 +290,7 @@ atom Ge='>='
atom generational
atom get_all_trap
atom get_seq_token
+atom get_size
atom get_tcw
atom gather_gc_info_result
atom gather_io_bytes
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index f71efd708f..762c5da9be 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -332,6 +332,13 @@ erts_debug_disassemble_1(BIF_ALIST_1)
"unknown " HEXF "\n", instr);
code_ptr++;
}
+ if (i == op_call_nif) {
+ /*
+ * The rest of the code will not be executed. Don't disassemble any
+ * more code in this function.
+ */
+ code_ptr = 0;
+ }
bin = new_binary(p, (byte *) dsbufp->str, dsbufp->str_len);
erts_destroy_tmp_dsbuf(dsbufp);
hsz = 4+4;
@@ -569,6 +576,7 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
}
break;
case op_i_bs_match_string_xfWW:
+ case op_i_bs_match_string_yfWW:
if (ap - first_arg < 3) {
erts_print(to, to_arg, "%d", *ap);
} else {
@@ -772,8 +780,11 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
case op_put_tuple2_xI:
case op_put_tuple2_yI:
case op_new_map_dtI:
- case op_update_map_assoc_sdtI:
- case op_update_map_exact_jsdtI:
+ case op_update_map_assoc_xdtI:
+ case op_update_map_assoc_ydtI:
+ case op_update_map_assoc_cdtI:
+ case op_update_map_exact_xjdtI:
+ case op_update_map_exact_yjdtI:
{
int n = unpacked[-1];
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 04a2a83123..73bf443372 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -1479,9 +1479,15 @@ next_catch(Process* c_p, Eterm *reg) {
BeamInstr i_return_time_trace = beam_return_time_trace[0];
ptr = prev = c_p->stop;
- ASSERT(is_CP(*ptr));
ASSERT(ptr <= STACK_START(c_p));
if (ptr == STACK_START(c_p)) return NULL;
+
+ /*
+ * Better safe than sorry here. In debug builds, produce a core
+ * dump if the top of the stack doesn't point to a continuation
+ * pointer. In other builds, ignore a non-CP at the top of stack.
+ */
+ ASSERT(is_CP(*ptr));
if ((is_not_CP(*ptr) || (*cp_val(*ptr) != i_return_trace &&
*cp_val(*ptr) != i_return_to_trace &&
*cp_val(*ptr) != i_return_time_trace ))
@@ -2310,12 +2316,16 @@ fixed_apply(Process* p, Eterm* reg, Uint arity,
function = reg[arity+1];
if (is_not_atom(function)) {
+ Eterm bad_args;
error:
- p->freason = BADARG;
- reg[0] = module;
- reg[1] = function;
- reg[2] = NIL;
- return 0;
+ bad_args = make_arglist(p, reg, arity);
+
+ p->freason = BADARG;
+ reg[0] = module;
+ reg[1] = function;
+ reg[2] = bad_args;
+
+ return 0;
}
if (is_not_atom(module)) goto error;
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 0ad5329b2f..21740caa2c 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -492,6 +492,11 @@ typedef struct LoaderState {
(Genop)->arity * sizeof(GenOpArg)); \
} while (0)
+#define GENOP_NAME_ARITY(Genop, Name, Arity) \
+ do { \
+ (Genop)->op = genop_##Name##_##Arity; \
+ (Genop)->arity = Arity; \
+ } while (0)
static void free_loader_state(Binary* magic);
static ErlHeapFragment* new_literal_fragment(Uint size);
@@ -3141,6 +3146,35 @@ is_killed(LoaderState* stp, GenOpArg Reg, GenOpArg Live)
}
/*
+ * Test whether register Reg is killed by make_fun instruction that
+ * creates the fun given by index idx.
+ */
+
+static int
+is_killed_by_make_fun(LoaderState* stp, GenOpArg Reg, GenOpArg idx)
+{
+ Uint num_free;
+
+ if (idx.val >= stp->num_lambdas) {
+ /* Invalid index. Ignore the error for now. */
+ return 0;
+ } else {
+ num_free = stp->lambdas[idx.val].num_free;
+ return Reg.type == TAG_x && num_free <= Reg.val;
+ }
+}
+
+/*
+ * Test whether register Reg is killed by the send instruction that follows.
+ */
+
+static int
+is_killed_by_send(LoaderState* stp, GenOpArg Reg)
+{
+ return Reg.type == TAG_x && 2 <= Reg.val;
+}
+
+/*
* Generate an instruction for element/2.
*/
@@ -3151,20 +3185,19 @@ gen_element(LoaderState* stp, GenOpArg Fail, GenOpArg Index,
GenOp* op;
NEW_GENOP(stp, op);
- op->arity = 4;
op->next = NULL;
if (Index.type == TAG_i && Index.val > 0 &&
Index.val <= ERTS_MAX_TUPLE_SIZE &&
(Tuple.type == TAG_x || Tuple.type == TAG_y)) {
- op->op = genop_i_fast_element_4;
+ GENOP_NAME_ARITY(op, i_fast_element, 4);
op->a[0] = Tuple;
op->a[1] = Fail;
op->a[2].type = TAG_u;
op->a[2].val = Index.val;
op->a[3] = Dst;
} else {
- op->op = genop_i_element_4;
+ GENOP_NAME_ARITY(op, i_element, 4);
op->a[0] = Tuple;
op->a[1] = Fail;
op->a[2] = Index;
@@ -3180,8 +3213,7 @@ gen_bs_save(LoaderState* stp, GenOpArg Reg, GenOpArg Index)
GenOp* op;
NEW_GENOP(stp, op);
- op->op = genop_i_bs_save2_2;
- op->arity = 2;
+ GENOP_NAME_ARITY(op, i_bs_save2, 2);
op->a[0] = Reg;
op->a[1] = Index;
if (Index.type == TAG_u) {
@@ -3200,8 +3232,7 @@ gen_bs_restore(LoaderState* stp, GenOpArg Reg, GenOpArg Index)
GenOp* op;
NEW_GENOP(stp, op);
- op->op = genop_i_bs_restore2_2;
- op->arity = 2;
+ GENOP_NAME_ARITY(op, i_bs_restore2, 2);
op->a[0] = Reg;
op->a[1] = Index;
if (Index.type == TAG_u) {
@@ -3235,21 +3266,18 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
} else if ((Flags.val & BSF_SIGNED) != 0) {
goto generic;
} else if (bits == 8) {
- op->op = genop_i_bs_get_integer_8_3;
- op->arity = 3;
- op->a[0] = Ms;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_8, 3);
+ op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Dst;
} else if (bits == 16 && (Flags.val & BSF_LITTLE) == 0) {
- op->op = genop_i_bs_get_integer_16_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_16, 3);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Dst;
#ifdef ARCH_64
} else if (bits == 32 && (Flags.val & BSF_LITTLE) == 0) {
- op->op = genop_i_bs_get_integer_32_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_32, 3);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Dst;
@@ -3257,8 +3285,7 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
} else {
generic:
if (bits < SMALL_BITS) {
- op->op = genop_i_bs_get_integer_small_imm_5;
- op->arity = 5;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_small_imm, 5);
op->a[0] = Ms;
op->a[1].type = TAG_u;
op->a[1].val = bits;
@@ -3266,8 +3293,7 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
op->a[3] = Flags;
op->a[4] = Dst;
} else {
- op->op = genop_i_bs_get_integer_imm_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_imm, 6);
op->a[0] = Ms;
op->a[1].type = TAG_u;
op->a[1].val = bits;
@@ -3283,8 +3309,7 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
if (!term_to_Uint(big, &bigval)) {
error:
- op->op = genop_jump_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, jump, 1);
op->a[0] = Fail;
} else {
if (!safe_mul(bigval, Unit.val, &bits)) {
@@ -3293,8 +3318,7 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
goto generic;
}
} else {
- op->op = genop_i_bs_get_integer_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_integer, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3324,23 +3348,20 @@ gen_get_binary2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
NATIVE_ENDIAN(Flags);
if (Size.type == TAG_a && Size.val == am_all) {
if (Ms.type == Dst.type && Ms.val == Dst.val) {
- op->op = genop_i_bs_get_binary_all_reuse_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_get_binary_all_reuse, 3);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Unit;
} else {
- op->op = genop_i_bs_get_binary_all2_5;
- op->arity = 5;
+ GENOP_NAME_ARITY(op, i_bs_get_binary_all2, 5);
op->a[0] = Ms;
op->a[1] = Fail;
- op->a[2] = Live;
+ op->a[2] = Live;
op->a[3] = Unit;
op->a[4] = Dst;
}
} else if (Size.type == TAG_i) {
- op->op = genop_i_bs_get_binary_imm2_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_binary_imm2, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3356,12 +3377,10 @@ gen_get_binary2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
if (!term_to_Uint(big, &bigval)) {
error:
- op->op = genop_jump_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, jump, 1);
op->a[0] = Fail;
} else {
- op->op = genop_i_bs_get_binary_imm2_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_binary_imm2, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3373,8 +3392,7 @@ gen_get_binary2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
op->a[5] = Dst;
}
} else {
- op->op = genop_i_bs_get_binary2_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_binary2, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3407,22 +3425,19 @@ gen_put_binary(LoaderState* stp, GenOpArg Fail,GenOpArg Size,
NATIVE_ENDIAN(Flags);
if (Size.type == TAG_a && Size.val == am_all) {
- op->op = genop_i_new_bs_put_binary_all_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(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) {
- op->op = genop_i_new_bs_put_binary_imm_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_new_bs_put_binary_imm, 3);
op->a[0] = Fail;
op->a[1].type = TAG_u;
if (safe_mul(Size.val, Unit.val, &op->a[1].val)) {
op->a[2] = Src;
} else {
error:
- op->op = genop_badarg_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, badarg, 1);
op->a[0] = Fail;
}
} else if (Size.type == TAG_q) {
@@ -3440,16 +3455,14 @@ gen_put_binary(LoaderState* stp, GenOpArg Fail,GenOpArg Size,
!safe_mul(bigval, Unit.val, &size)) {
goto error;
}
- op->op = genop_i_new_bs_put_binary_imm_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(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 {
- op->op = genop_i_new_bs_put_binary_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_binary, 4);
op->a[0] = Fail;
op->a[1] = Size;
op->a[2].type = TAG_u;
@@ -3474,14 +3487,12 @@ gen_put_integer(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
Uint size;
if (!safe_mul(Size.val, Unit.val, &size)) {
error:
- op->op = genop_badarg_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, badarg, 1);
op->a[0] = Fail;
op->next = NULL;
return op;
}
- op->op = genop_i_new_bs_put_integer_imm_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_integer_imm, 4);
op->a[0] = Src;
op->a[1] = Fail;
op->a[2].type = TAG_u;
@@ -3497,8 +3508,7 @@ gen_put_integer(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
!safe_mul(bigval, Unit.val, &size)) {
goto error;
}
- op->op = genop_i_new_bs_put_integer_imm_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_integer_imm, 4);
op->a[0] = Src;
op->a[1] = Fail;
op->a[2].type = TAG_u;
@@ -3506,8 +3516,7 @@ gen_put_integer(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
op->a[3].type = Flags.type;
op->a[3].val = (Flags.val & 7);
} else {
- op->op = genop_i_new_bs_put_integer_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_integer, 4);
op->a[0] = Fail;
op->a[1] = Size;
op->a[2].type = TAG_u;
@@ -3527,21 +3536,18 @@ gen_put_float(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
NATIVE_ENDIAN(Flags);
if (Size.type == TAG_i) {
- op->op = genop_i_new_bs_put_float_imm_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_float_imm, 4);
op->a[0] = Fail;
op->a[1].type = TAG_u;
if (!safe_mul(Size.val, Unit.val, &op->a[1].val)) {
- op->op = genop_badarg_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, badarg, 1);
op->a[0] = Fail;
} else {
op->a[2] = Flags;
op->a[3] = Src;
}
} else {
- op->op = genop_i_new_bs_put_float_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_float, 4);
op->a[0] = Fail;
op->a[1] = Size;
op->a[2].type = TAG_u;
@@ -3564,8 +3570,7 @@ gen_get_float2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
NEW_GENOP(stp, op);
NATIVE_ENDIAN(Flags);
- op->op = genop_i_bs_get_float2_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_float2, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3582,7 +3587,7 @@ gen_get_float2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
*/
static GenOp*
-gen_skip_bits2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms,
+gen_skip_bits2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms,
GenOpArg Size, GenOpArg Unit, GenOpArg Flags)
{
GenOp* op;
@@ -3602,16 +3607,14 @@ gen_skip_bits2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms,
* a bs_restore2 instruction which will overwrite the position
* by one of the stored positions.
*/
- op->op = genop_bs_test_unit_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, bs_test_unit, 3);
op->a[0] = Fail;
op->a[1] = Ms;
op->a[2] = Unit;
} else if (Size.type == TAG_i) {
- op->op = genop_i_bs_skip_bits_imm2_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_skip_bits_imm2, 3);
op->a[0] = Fail;
- op->a[1] = Ms;
+ op->a[1] = Ms;
op->a[2].type = TAG_u;
if (!safe_mul(Size.val, Unit.val, &op->a[2].val)) {
goto error;
@@ -3622,22 +3625,19 @@ gen_skip_bits2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms,
if (!term_to_Uint(big, &bigval)) {
error:
- op->op = genop_jump_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, jump, 1);
op->a[0] = Fail;
} else {
- op->op = genop_i_bs_skip_bits_imm2_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_skip_bits_imm2, 3);
op->a[0] = Fail;
- op->a[1] = Ms;
+ op->a[1] = Ms;
op->a[2].type = TAG_u;
if (!safe_mul(bigval, Unit.val, &op->a[2].val)) {
goto error;
}
}
} else {
- op->op = genop_i_bs_skip_bits2_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_bs_skip_bits2, 4);
op->a[0] = Ms;
op->a[1] = Size;
op->a[2] = Fail;
@@ -3654,8 +3654,7 @@ gen_increment(LoaderState* stp, GenOpArg Reg,
GenOp* op;
NEW_GENOP(stp, op);
- op->op = genop_i_increment_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_increment, 3);
op->next = NULL;
op->a[0] = Reg;
op->a[1].type = TAG_u;
@@ -3671,8 +3670,7 @@ gen_increment_from_minus(LoaderState* stp, GenOpArg Reg,
GenOp* op;
NEW_GENOP(stp, op);
- op->op = genop_i_increment_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_increment, 3);
op->next = NULL;
op->a[0] = Reg;
op->a[1].type = TAG_u;
@@ -3681,6 +3679,24 @@ gen_increment_from_minus(LoaderState* stp, GenOpArg Reg,
return op;
}
+static GenOp*
+gen_plus_from_minus(LoaderState* stp, GenOpArg Fail, GenOpArg Live,
+ GenOpArg Src, GenOpArg Integer, GenOpArg Dst)
+{
+ GenOp* op;
+
+ NEW_GENOP(stp, op);
+ GENOP_NAME_ARITY(op, gen_plus, 5);
+ op->next = NULL;
+ op->a[0] = Fail;
+ op->a[1] = Live;
+ op->a[2] = Src;
+ op->a[3].type = TAG_i;
+ op->a[3].val = -Integer.val;
+ op->a[4] = Dst;
+ return op;
+}
+
/*
* Test whether the negation of the given number is small.
*/
@@ -3727,12 +3743,11 @@ gen_literal_timeout(LoaderState* stp, GenOpArg Fail, GenOpArg Time)
Sint timeout;
NEW_GENOP(stp, op);
- op->op = genop_wait_timeout_unlocked_int_2;
+ GENOP_NAME_ARITY(op, wait_timeout_unlocked_int, 2);
op->next = NULL;
- op->arity = 2;
op->a[0].type = TAG_u;
op->a[1] = Fail;
-
+
if (Time.type == TAG_i && (timeout = Time.val) >= 0 &&
#if defined(ARCH_64)
(timeout >> 32) == 0
@@ -3761,8 +3776,7 @@ gen_literal_timeout(LoaderState* stp, GenOpArg Fail, GenOpArg Time)
#if !defined(ARCH_64)
error:
#endif
- op->op = genop_i_wait_error_0;
- op->arity = 0;
+ GENOP_NAME_ARITY(op, i_wait_error, 0);
}
return op;
}
@@ -3774,9 +3788,8 @@ gen_literal_timeout_locked(LoaderState* stp, GenOpArg Fail, GenOpArg Time)
Sint timeout;
NEW_GENOP(stp, op);
- op->op = genop_wait_timeout_locked_int_2;
+ GENOP_NAME_ARITY(op, wait_timeout_locked_int, 2);
op->next = NULL;
- op->arity = 2;
op->a[0].type = TAG_u;
op->a[1] = Fail;
@@ -3808,8 +3821,7 @@ gen_literal_timeout_locked(LoaderState* stp, GenOpArg Fail, GenOpArg Time)
#if !defined(ARCH_64)
error:
#endif
- op->op = genop_i_wait_error_locked_0;
- op->arity = 0;
+ GENOP_NAME_ARITY(op, i_wait_error_locked, 0);
}
return op;
}
@@ -3846,9 +3858,9 @@ gen_select_tuple_arity(LoaderState* stp, GenOpArg S, GenOpArg Fail,
*/
if (size == 2) {
NEW_GENOP(stp, op);
- op->next = NULL;
- op->op = genop_i_select_tuple_arity2_4;
+ GENOP_NAME_ARITY(op, i_select_tuple_arity2, 4);
GENOP_ARITY(op, arity - 1);
+ op->next = NULL;
op->a[0] = S;
op->a[1] = Fail;
op->a[2].type = TAG_u;
@@ -3874,9 +3886,9 @@ gen_select_tuple_arity(LoaderState* stp, GenOpArg S, GenOpArg Fail,
size += align;
NEW_GENOP(stp, op);
- op->next = NULL;
- op->op = genop_i_select_tuple_arity_3;
+ GENOP_NAME_ARITY(op, i_select_tuple_arity, 3);
GENOP_ARITY(op, arity);
+ op->next = NULL;
op->a[0] = S;
op->a[1] = Fail;
op->a[2].type = TAG_u;
@@ -3932,21 +3944,18 @@ gen_split_values(LoaderState* stp, GenOpArg S, GenOpArg TypeFail,
ASSERT(Size.val >= 2 && Size.val % 2 == 0);
NEW_GENOP(stp, is_integer);
- is_integer->op = genop_is_integer_2;
- is_integer->arity = 2;
+ GENOP_NAME_ARITY(is_integer, is_integer, 2);
is_integer->a[0] = TypeFail;
is_integer->a[1] = S;
NEW_GENOP(stp, label);
- label->op = genop_label_1;
- label->arity = 1;
+ GENOP_NAME_ARITY(label, label, 1);
label->a[0].type = TAG_u;
label->a[0].val = new_label(stp);
NEW_GENOP(stp, op1);
- op1->op = genop_select_val_3;
+ GENOP_NAME_ARITY(op1, select_val, 3);
GENOP_ARITY(op1, 3 + Size.val);
- op1->arity = 3;
op1->a[0] = S;
op1->a[1].type = TAG_f;
op1->a[1].val = label->a[0].val;
@@ -3954,9 +3963,8 @@ gen_split_values(LoaderState* stp, GenOpArg S, GenOpArg TypeFail,
op1->a[2].val = 0;
NEW_GENOP(stp, op2);
- op2->op = genop_select_val_3;
+ GENOP_NAME_ARITY(op2, select_val, 3);
GENOP_ARITY(op2, 3 + Size.val);
- op2->arity = 3;
op2->a[0] = S;
op2->a[1] = Fail;
op2->a[2].type = TAG_u;
@@ -4034,19 +4042,17 @@ gen_jump_tab(LoaderState* stp, GenOpArg S, GenOpArg Fail, GenOpArg Size, GenOpAr
GenOp* jump;
NEW_GENOP(stp, op);
- op->arity = 3;
- op->op = genop_is_ne_exact_3;
+ GENOP_NAME_ARITY(op, is_ne_exact, 3);
op->a[0] = Rest[1];
op->a[1] = S;
op->a[2] = Rest[0];
NEW_GENOP(stp, jump);
- jump->next = NULL;
- jump->arity = 1;
- jump->op = genop_jump_1;
+ GENOP_NAME_ARITY(jump, jump, 1);
jump->a[0] = Fail;
op->next = jump;
+ jump->next = NULL;
return op;
}
@@ -4073,12 +4079,11 @@ gen_jump_tab(LoaderState* stp, GenOpArg S, GenOpArg Fail, GenOpArg Size, GenOpAr
NEW_GENOP(stp, op);
op->next = NULL;
if (min == 0) {
- op->op = genop_i_jump_on_val_zero_3;
- fixed_args = 3;
+ GENOP_NAME_ARITY(op, i_jump_on_val_zero, 3);
} else {
- op->op = genop_i_jump_on_val_4;
- fixed_args = 4;
+ GENOP_NAME_ARITY(op, i_jump_on_val, 4);
}
+ fixed_args = op->arity;
arity = fixed_args + size;
GENOP_ARITY(op, arity);
op->a[0] = S;
@@ -4143,7 +4148,7 @@ gen_select_val(LoaderState* stp, GenOpArg S, GenOpArg Fail,
NEW_GENOP(stp, op);
op->next = NULL;
- op->op = genop_i_select_val2_4;
+ GENOP_NAME_ARITY(op, i_select_val2, 4);
GENOP_ARITY(op, arity - 1);
op->a[0] = S;
op->a[1] = Fail;
@@ -4165,7 +4170,11 @@ gen_select_val(LoaderState* stp, GenOpArg S, GenOpArg Fail,
NEW_GENOP(stp, op);
op->next = NULL;
- op->op = (align == 0) ? genop_i_select_val_bins_3 : genop_i_select_val_lins_3;
+ if (align == 0) {
+ GENOP_NAME_ARITY(op, i_select_val_bins, 3);
+ } else {
+ GENOP_NAME_ARITY(op, i_select_val_lins, 3);
+ }
GENOP_ARITY(op, arity);
op->a[0] = S;
op->a[1] = Fail;
@@ -4229,8 +4238,7 @@ gen_select_literals(LoaderState* stp, GenOpArg S, GenOpArg Fail,
ASSERT(Rest[i].type == TAG_q);
NEW_GENOP(stp, op);
- op->op = genop_is_ne_exact_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, is_ne_exact, 3);
op->a[0] = Rest[i+1];
op->a[1] = S;
op->a[2] = Rest[i];
@@ -4239,9 +4247,8 @@ gen_select_literals(LoaderState* stp, GenOpArg S, GenOpArg Fail,
}
NEW_GENOP(stp, jump);
+ GENOP_NAME_ARITY(jump, jump, 1);
jump->next = NULL;
- jump->op = genop_jump_1;
- jump->arity = 1;
jump->a[0] = Fail;
*prev_next = jump;
return op;
@@ -4263,9 +4270,8 @@ const_select_val(LoaderState* stp, GenOpArg S, GenOpArg Fail,
ASSERT(Size.type == TAG_u);
NEW_GENOP(stp, op);
+ GENOP_NAME_ARITY(op, jump, 1);
op->next = NULL;
- op->op = genop_jump_1;
- op->arity = 1;
/*
* Search for a literal matching the controlling expression.
@@ -4346,15 +4352,17 @@ gen_make_fun2(LoaderState* stp, GenOpArg idx)
funp->creator = erts_init_process_id;
funp->arity = arity;
- op->op = genop_move_2;
- op->arity = 2;
+ /*
+ * Use a move_fun/2 instruction to load the fun to enable
+ * further optimizations.
+ */
+ GENOP_NAME_ARITY(op, move_fun, 2);
op->a[0].type = TAG_q;
op->a[0].val = lit;
op->a[1].type = TAG_x;
op->a[1].val = 0;
} else {
- op->op = genop_i_make_fun_2;
- op->arity = 2;
+ GENOP_NAME_ARITY(op, i_make_fun, 2);
op->a[0].type = TAG_u;
op->a[0].val = (BeamInstr) fe;
op->a[1].type = TAG_u;
@@ -4382,13 +4390,11 @@ gen_is_function2(LoaderState* stp, GenOpArg Fail, GenOpArg Fun, GenOpArg Arity)
*/
if (Arity.val > MAX_ARG) {
/* Arity is negative or too big. */
- op->op = genop_jump_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, jump, 1);
op->a[0] = Fail;
return op;
} else {
- op->op = genop_hot_is_function2_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, hot_is_function2, 3);
op->a[0] = Fail;
op->a[1] = Fun;
op->a[2].type = TAG_u;
@@ -4408,20 +4414,17 @@ gen_is_function2(LoaderState* stp, GenOpArg Fail, GenOpArg Fun, GenOpArg Arity)
move_fun->next = move_arity;
move_arity->next = op;
- move_fun->arity = 2;
- move_fun->op = genop_move_2;
+ GENOP_NAME_ARITY(move_fun, move, 2);
move_fun->a[0] = Fun;
move_fun->a[1].type = TAG_x;
move_fun->a[1].val = 1022;
- move_arity->arity = 2;
- move_arity->op = genop_move_2;
+ GENOP_NAME_ARITY(move_arity, move, 2);
move_arity->a[0] = Arity;
move_arity->a[1].type = TAG_x;
move_arity->a[1].val = 1023;
- op->op = genop_cold_is_function2_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, cold_is_function2, 3);
op->a[0] = Fail;
op->a[1].type = TAG_x;
op->a[1].val = 1022;
@@ -4442,8 +4445,8 @@ tuple_append_put5(LoaderState* stp, GenOpArg Arity, GenOpArg Dst,
NEW_GENOP(stp, op);
op->next = NULL;
+ GENOP_NAME_ARITY(op, i_put_tuple, 2);
GENOP_ARITY(op, arity+2+5);
- op->op = genop_i_put_tuple_2;
op->a[0] = Dst;
op->a[1].type = TAG_u;
op->a[1].val = arity + 5;
@@ -4468,8 +4471,8 @@ tuple_append_put(LoaderState* stp, GenOpArg Arity, GenOpArg Dst,
NEW_GENOP(stp, op);
op->next = NULL;
+ GENOP_NAME_ARITY(op, i_put_tuple, 2);
GENOP_ARITY(op, arity+2+1);
- op->op = genop_i_put_tuple_2;
op->a[0] = Dst;
op->a[1].type = TAG_u;
op->a[1].val = arity + 1;
@@ -4537,9 +4540,9 @@ gen_new_small_map_lit(LoaderState* stp, GenOpArg Dst, GenOpArg Live,
Eterm keys;
NEW_GENOP(stp, op);
+ GENOP_NAME_ARITY(op, i_new_small_map_lit, 3);
GENOP_ARITY(op, 3 + size/2);
op->next = NULL;
- op->op = genop_i_new_small_map_lit_3;
tmp = thp = erts_alloc(ERTS_ALC_T_LOADER_TMP, (1 + size/2) * sizeof(*tmp));
keys = make_tuple(thp);
@@ -4720,14 +4723,12 @@ gen_get_map_element(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
Key = Rest[0];
if (hash_genop_arg(stp, Key, &hx)) {
- op->arity = 5;
- op->op = genop_i_get_map_element_hash_5;
+ GENOP_NAME_ARITY(op, i_get_map_element_hash, 5);
op->a[3].type = TAG_u;
op->a[3].val = (BeamInstr) hx;
op->a[4] = Rest[1];
} else {
- op->arity = 4;
- op->op = genop_i_get_map_element_4;
+ GENOP_NAME_ARITY(op, i_get_map_element, 4);
op->a[3] = Rest[1];
}
return op;
@@ -4767,15 +4768,13 @@ gen_get(LoaderState* stp, GenOpArg Src, GenOpArg Dst)
NEW_GENOP(stp, op);
op->next = NULL;
if (hash_internal_genop_arg(stp, Src, &hx)) {
- op->arity = 3;
- op->op = genop_i_get_hash_3;
+ GENOP_NAME_ARITY(op, i_get_hash, 3);
op->a[0] = Src;
op->a[1].type = TAG_u;
op->a[1].val = (BeamInstr) hx;
op->a[2] = Dst;
} else {
- op->arity = 2;
- op->op = genop_i_get_2;
+ GENOP_NAME_ARITY(op, i_get, 2);
op->a[0] = Src;
op->a[1] = Dst;
}
@@ -4799,7 +4798,7 @@ gen_get_map_elements(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
ASSERT(Size.type == TAG_u);
NEW_GENOP(stp, op);
- op->op = genop_i_get_map_elements_3;
+ GENOP_NAME_ARITY(op, i_get_map_elements, 3);
GENOP_ARITY(op, 3 + 3*(Size.val/2));
op->next = NULL;
op->a[0] = Fail;
@@ -4837,9 +4836,9 @@ gen_has_map_fields(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
n = Size.val;
NEW_GENOP(stp, op);
+ GENOP_NAME_ARITY(op, get_map_elements, 3);
GENOP_ARITY(op, 3 + 2*n);
op->next = NULL;
- op->op = genop_get_map_elements_3;
op->a[0] = Fail;
op->a[1] = Src;
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index acb7d472fd..d0e2d9afc2 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -2463,6 +2463,7 @@ BIF_RETTYPE iolist_size_1(BIF_ALIST_1)
ErtsIOListSizeContext* context = NULL;
Eterm state_mref;
int is_trap_at_L_iter_list;
+ ERTS_UNDEF(state_mref, THE_NON_VALUE);
ESTACK_CHANGE_ALLOCATOR(s, ERTS_ALC_T_SAVED_ESTACK);
#ifdef DEBUG
iterations_until_trap = iterations_until_trap / 10;
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 11941db8cd..34a0be4f2d 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -160,6 +160,8 @@ bif erlang:dist_ctrl_input_handler/2
bif erlang:dist_ctrl_put_data/2
bif erlang:dist_ctrl_get_data/1
bif erlang:dist_ctrl_get_data_notification/1
+bif erlang:dist_ctrl_get_opt/2
+bif erlang:dist_ctrl_set_opt/3
# Static native functions in erts_internal
bif erts_internal:port_info/1
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 45ada4e38a..a1da1addf9 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -3253,6 +3253,86 @@ dist_ctrl_put_data_2(BIF_ALIST_2)
}
BIF_RETTYPE
+dist_ctrl_set_opt_3(BIF_ALIST_3)
+{
+ DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P);
+ Uint32 conn_id;
+ BIF_RETTYPE ret;
+
+ if (!dep)
+ BIF_ERROR(BIF_P, EXC_NOTSUP);
+
+ if (erts_dhandle_to_dist_entry(BIF_ARG_1, &conn_id) != dep)
+ BIF_ERROR(BIF_P, BADARG);
+
+ erts_de_rlock(dep);
+
+ if (dep->connection_id != conn_id)
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ else {
+
+ switch (BIF_ARG_2) {
+ case am_get_size:
+ ERTS_BIF_PREP_RET(ret, (dep->opts & ERTS_DIST_CTRL_OPT_GET_SIZE
+ ? am_true
+ : am_false));
+ if (BIF_ARG_3 == am_true)
+ dep->opts |= ERTS_DIST_CTRL_OPT_GET_SIZE;
+ else if (BIF_ARG_3 == am_false)
+ dep->opts &= ~ERTS_DIST_CTRL_OPT_GET_SIZE;
+ else
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ break;
+ default:
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ break;
+ }
+
+ }
+
+ erts_de_runlock(dep);
+
+ return ret;
+}
+
+BIF_RETTYPE
+dist_ctrl_get_opt_2(BIF_ALIST_2)
+{
+ DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P);
+ Uint32 conn_id;
+ BIF_RETTYPE ret;
+
+ if (!dep)
+ BIF_ERROR(BIF_P, EXC_NOTSUP);
+
+ if (erts_dhandle_to_dist_entry(BIF_ARG_1, &conn_id) != dep)
+ BIF_ERROR(BIF_P, BADARG);
+
+ erts_de_rlock(dep);
+
+ if (dep->connection_id != conn_id)
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ else {
+
+ switch (BIF_ARG_2) {
+ case am_get_size:
+ ERTS_BIF_PREP_RET(ret, (dep->opts & ERTS_DIST_CTRL_OPT_GET_SIZE
+ ? am_true
+ : am_false));
+ break;
+ default:
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ break;
+ }
+
+ }
+
+ erts_de_runlock(dep);
+
+ return ret;
+}
+
+BIF_RETTYPE
dist_get_stat_1(BIF_ALIST_1)
{
Sint64 read, write, pend;
@@ -3332,7 +3412,9 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
Eterm *hp;
ProcBin *pb;
erts_aint_t qsize;
- Uint32 conn_id;
+ Uint32 conn_id, get_size;
+ Eterm res;
+ Uint hsz, bin_sz;
if (!dep)
BIF_ERROR(BIF_P, EXC_NOTSUP);
@@ -3400,15 +3482,26 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
erts_de_runlock(dep);
- hp = HAlloc(BIF_P, PROC_BIN_SIZE);
+ bin_sz = obuf->ext_endp - obuf->extp;
+ hsz = PROC_BIN_SIZE;
+
+ get_size = dep->opts & ERTS_DIST_CTRL_OPT_GET_SIZE;
+ if (get_size) {
+ hsz += 3; /* 2 tuple */
+ if (!IS_USMALL(0, bin_sz))
+ hsz += BIG_UINT_HEAP_SIZE;
+ }
+
+ hp = HAlloc(BIF_P, hsz);
pb = (ProcBin *) (char *) hp;
pb->thing_word = HEADER_PROC_BIN;
- pb->size = obuf->ext_endp - obuf->extp;
+ pb->size = bin_sz;
pb->next = MSO(BIF_P).first;
MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
pb->val = ErtsDistOutputBuf2Binary(obuf);
pb->bytes = (byte*) obuf->extp;
pb->flags = 0;
+ hp += PROC_BIN_SIZE;
qsize = erts_atomic_add_read_nob(&dep->qsize, -size_obuf(obuf));
ASSERT(qsize >= 0);
@@ -3425,7 +3518,20 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
}
}
- BIF_RET2(make_binary(pb), (initial_reds - reds));
+ res = make_binary(pb);
+
+ if (get_size) {
+ Eterm sz_term;
+ if (IS_USMALL(0, bin_sz))
+ sz_term = make_small(bin_sz);
+ else {
+ sz_term = uint_to_big(bin_sz, hp);
+ hp += BIG_UINT_HEAP_SIZE;
+ }
+ res = TUPLE2(hp, sz_term, res);
+ }
+
+ BIF_RET2(res, (initial_reds - reds));
}
void
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index 38ac972f51..9b5e62ab7e 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -172,6 +172,9 @@ extern int erts_is_alive;
/* Pending connection; signals can be enqueued */
#define ERTS_DSIG_PREP_PENDING 4
+/* dist_ctrl_{g,s}et_option/2 */
+#define ERTS_DIST_CTRL_OPT_GET_SIZE ((Uint32) (1 << 0))
+
#ifdef DEBUG
#define ERTS_DBG_CHK_NO_DIST_LNK(D, R, L) \
erts_dbg_chk_no_dist_proc_link((D), (R), (L))
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 137f87a75c..504aa8f943 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -4606,18 +4606,17 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
}
}
else if (ERTS_IS_ATOM_STR("wait", BIF_ARG_1)) {
- if (ERTS_IS_ATOM_STR("deallocations", BIF_ARG_2)) {
- int flag = ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS;
- if (erts_debug_wait_completed(BIF_P, flag)) {
- ERTS_BIF_YIELD_RETURN(BIF_P, am_ok);
- }
- }
- if (ERTS_IS_ATOM_STR("timer_cancellations", BIF_ARG_2)) {
- int flag = ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS;
- if (erts_debug_wait_completed(BIF_P, flag)) {
- ERTS_BIF_YIELD_RETURN(BIF_P, am_ok);
- }
- }
+ int flag = 0;
+ if (ERTS_IS_ATOM_STR("deallocations", BIF_ARG_2))
+ flag = ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS;
+ else if (ERTS_IS_ATOM_STR("timer_cancellations", BIF_ARG_2))
+ flag = ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS;
+ else if (ERTS_IS_ATOM_STR("aux_work", BIF_ARG_2))
+ flag = ERTS_DEBUG_WAIT_COMPLETED_AUX_WORK;
+
+ if (flag && erts_debug_wait_completed(BIF_P, flag)) {
+ ERTS_BIF_YIELD_RETURN(BIF_P, am_ok);
+ }
}
else if (ERTS_IS_ATOM_STR("broken_halt", BIF_ARG_1)) {
erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h
index 4bf77988f7..c9c047255a 100644
--- a/erts/emulator/beam/erl_binary.h
+++ b/erts/emulator/beam/erl_binary.h
@@ -314,6 +314,7 @@ ERTS_GLB_INLINE Binary *erts_bin_drv_alloc(Uint size);
ERTS_GLB_INLINE Binary *erts_bin_nrml_alloc(Uint size);
ERTS_GLB_INLINE Binary *erts_bin_realloc_fnf(Binary *bp, Uint size);
ERTS_GLB_INLINE Binary *erts_bin_realloc(Binary *bp, Uint size);
+ERTS_GLB_INLINE void erts_magic_binary_free(Binary *bp);
ERTS_GLB_INLINE void erts_bin_free(Binary *bp);
ERTS_GLB_INLINE void erts_bin_release(Binary *bp);
ERTS_GLB_INLINE Binary *erts_create_magic_binary_x(Uint size,
@@ -446,6 +447,13 @@ erts_bin_realloc(Binary *bp, Uint size)
}
ERTS_GLB_INLINE void
+erts_magic_binary_free(Binary *bp)
+{
+ erts_magic_ref_remove_bin(ERTS_MAGIC_BIN_REFN(bp));
+ erts_free(ERTS_MAGIC_BIN_ATYPE(bp), (void *) bp);
+}
+
+ERTS_GLB_INLINE void
erts_bin_free(Binary *bp)
{
if (bp->intern.flags & BIN_FLAG_MAGIC) {
@@ -453,8 +461,7 @@ erts_bin_free(Binary *bp)
/* Destructor took control of the deallocation */
return;
}
- erts_magic_ref_remove_bin(ERTS_MAGIC_BIN_REFN(bp));
- erts_free(ERTS_MAGIC_BIN_ATYPE(bp), (void *) bp);
+ erts_magic_binary_free(bp);
}
else if (bp->intern.flags & BIN_FLAG_DRV)
erts_free(ERTS_ALC_T_DRV_BINARY, (void *) bp);
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index af1acbfc90..deaf35c2a1 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1024,7 +1024,7 @@ static Eterm call_whereis(ErlNifEnv *env, Eterm name)
int scheduler;
execution_state(env, &c_p, &scheduler);
- ASSERT((c_p && scheduler) || (!c_p && !scheduler));
+ ASSERT(scheduler || !c_p);
if (scheduler < 0) {
/* dirty scheduler */
@@ -2442,10 +2442,26 @@ int erts_dbg_is_resource_dying(ErtsResource* resource)
}
#endif
-# define NIF_RESOURCE_DTOR &nif_resource_dtor
+#define NIF_RESOURCE_DTOR &nif_resource_dtor_prologue
-static int nif_resource_dtor(Binary* bin)
+static void run_resource_dtor(void* vbin);
+
+static int nif_resource_dtor_prologue(Binary* bin)
{
+ /*
+ * Schedule user resource destructor as aux work to get a context
+ * where we know what locks we have for example.
+ */
+ Uint sched_id = erts_get_scheduler_id();
+ if (!sched_id)
+ sched_id = 1;
+ erts_schedule_misc_aux_work(sched_id, run_resource_dtor, bin);
+ return 0; /* don't free */
+}
+
+static void run_resource_dtor(void* vbin)
+{
+ Binary* bin = (Binary*) vbin;
ErtsResource* resource = (ErtsResource*) ERTS_MAGIC_BIN_UNALIGNED_DATA(bin);
ErlNifResourceType* type = resource->type;
ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == NIF_RESOURCE_DTOR);
@@ -2477,11 +2493,11 @@ static int nif_resource_dtor(Binary* bin)
* If resource->monitors->refc != 0 there are
* outstanding references to the resource from
* monitors that has not been removed yet.
- * nif_resource_dtor() will be called again this
+ * nif_resource_dtor_prologue() will be called again when this
* reference count reach zero.
*/
if (refc != 0)
- return 0; /* we'll be back... */
+ return; /* we'll be back... */
erts_mtx_destroy(&rm->lock);
}
@@ -2498,7 +2514,7 @@ static int nif_resource_dtor(Binary* bin)
steal_resource_type(type);
erts_free(ERTS_ALC_T_NIF, type);
}
- return 1;
+ erts_magic_binary_free((Binary*)vbin);
}
void erts_resource_stop(ErtsResource* resource, ErlNifEvent e,
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 09edcbbb7f..215dc6fa71 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -177,6 +177,7 @@ dist_table_alloc(void *dep_tmpl)
dep->connection_id = 0;
dep->state = ERTS_DE_STATE_IDLE;
dep->flags = 0;
+ dep->opts = 0;
dep->version = 0;
dep->mld = NULL;
@@ -659,6 +660,7 @@ erts_set_dist_entry_not_connected(DistEntry *dep)
dep->state = ERTS_DE_STATE_IDLE;
dep->flags = 0;
+ dep->opts = 0;
dep->prev = NULL;
dep->cid = NIL;
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index eb0e13ccbe..c434926142 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -148,6 +148,7 @@ struct dist_entry_ {
enum dist_entry_state state;
Uint32 flags; /* Distribution flags, like hidden,
atom cache etc. */
+ Uint32 opts;
unsigned long version; /* Protocol version */
ErtsMonLnkDist *mld; /* Monitors and links */
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index 9c74a2c355..bd59c4afa3 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -3429,9 +3429,15 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
erts_nif_demonitored((ErtsResource *) tmon->other.ptr);
cnt++;
break;
- case ERTS_MON_TYPE_SUSPEND:
- erts_resume(c_p, ERTS_PROC_LOCK_MAIN);
+ case ERTS_MON_TYPE_SUSPEND: {
+ ErtsMonitorSuspend *msp;
+ erts_aint_t mstate;
+ msp = (ErtsMonitorSuspend *) erts_monitor_to_data(tmon);
+ mstate = erts_atomic_read_acqb(&msp->state);
+ if (mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE)
+ erts_resume(c_p, ERTS_PROC_LOCK_MAIN);
break;
+ }
default:
break;
}
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 0a099e69bb..f34289339f 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -2375,9 +2375,12 @@ struct debug_lop {
static void later_thr_debug_wait_completed(void *vlop)
{
struct debug_lop *lop = vlop;
- erts_aint32_t count = (erts_aint32_t) erts_no_schedulers;
- count += 1; /* aux thread */
- if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == count) {
+
+ if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == 1) {
+ erts_aint32_t count = (erts_aint32_t) erts_no_schedulers;
+ count += 1; /* aux thread */
+ erts_atomic32_set_nob(&debug_wait_completed_count, count);
+
/* scheduler threads */
erts_schedule_multi_misc_aux_work(0,
erts_no_schedulers,
@@ -2395,19 +2398,28 @@ static void later_thr_debug_wait_completed(void *vlop)
static void
init_thr_debug_wait_completed(void *vproc)
{
- struct debug_lop* lop = erts_alloc(ERTS_ALC_T_DEBUG,
- sizeof(struct debug_lop));
- lop->proc = vproc;
- erts_schedule_thr_prgr_later_op(later_thr_debug_wait_completed, lop, &lop->lop);
+ if (debug_wait_completed_flags == ERTS_DEBUG_WAIT_COMPLETED_AUX_WORK) {
+ if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == 1) {
+ erts_atomic32_set_nob(&debug_wait_completed_count, 0);
+ erts_resume((Process *) vproc, (ErtsProcLocks) 0);
+ erts_proc_dec_refc((Process *) vproc);
+ }
+ }
+ else {
+ struct debug_lop* lop = erts_alloc(ERTS_ALC_T_DEBUG,
+ sizeof(struct debug_lop));
+ lop->proc = vproc;
+ erts_schedule_thr_prgr_later_op(later_thr_debug_wait_completed, lop, &lop->lop);
+ }
}
int
erts_debug_wait_completed(Process *c_p, int flags)
{
- /* Only one process at a time can do this */
- erts_aint32_t count = (erts_aint32_t) (2*erts_no_schedulers);
- count += 1; /* aux thread */
+ /* Only one process at a time can do this, +1 to mark as busy */
+ erts_aint32_t count = (erts_aint32_t) (erts_no_schedulers + 1);
+
if (0 == erts_atomic32_cmpxchg_mb(&debug_wait_completed_count,
count,
0)) {
@@ -9460,6 +9472,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
if (!is_normal_sched & !!(flags & ERTS_RUNQ_FLG_HALTING)) {
/* Wait for emulator to terminate... */
+ erts_runq_unlock(rq);
while (1)
erts_milli_sleep(1000*1000);
}
@@ -13403,10 +13416,10 @@ void erts_halt(int code)
if (-1 == erts_atomic32_cmpxchg_acqb(&erts_halt_progress,
erts_no_schedulers,
-1)) {
+ notify_reap_ports_relb();
ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_CPU_RUNQ, ERTS_RUNQ_FLG_HALTING);
ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_IO_RUNQ, ERTS_RUNQ_FLG_HALTING);
erts_halt_code = code;
- notify_reap_ports_relb();
}
}
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 3b593bce02..4ffa022d5c 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1856,6 +1856,7 @@ Uint erts_debug_nbalance(void);
#define ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS (1 << 0)
#define ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS (1 << 1)
+#define ERTS_DEBUG_WAIT_COMPLETED_AUX_WORK (1 << 2)
int erts_debug_wait_completed(Process *c_p, int flags);
diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab
index 1eb83b61f2..692408e212 100644
--- a/erts/emulator/beam/instrs.tab
+++ b/erts/emulator/beam/instrs.tab
@@ -477,6 +477,13 @@ i_make_fun(FunP, NumFree) {
HEAVY_SWAPIN;
}
+move_trim(Src, Dst, Words) {
+ Uint cp = E[0];
+ $Dst = $Src;
+ E += $Words;
+ E[0] = cp;
+}
+
i_trim(Words) {
Uint cp = E[0];
E += $Words;
@@ -493,10 +500,6 @@ move3(S1, D1, S2, D2, S3, D3) {
$D3 = $S3;
}
-move_dup(Src, D1, D2) {
- $D1 = $D2 = $Src;
-}
-
move2_par(S1, D1, S2, D2) {
Eterm V1, V2;
V1 = $S1;
@@ -512,6 +515,39 @@ move_shift(Src, SD, D) {
$SD = V;
}
+move_src_window2(Src, D1, D2) {
+ Eterm* src = &$Src;
+ Eterm s1, s2;
+ s1 = src[0];
+ s2 = src[1];
+ $D1 = s1;
+ $D2 = s2;
+}
+
+move_src_window3(Src, D1, D2, D3) {
+ Eterm* src = &$Src;
+ Eterm s1, s2, s3;
+ s1 = src[0];
+ s2 = src[1];
+ s3 = src[2];
+ $D1 = s1;
+ $D2 = s2;
+ $D3 = s3;
+}
+
+move_src_window4(Src, D1, D2, D3, D4) {
+ Eterm* src = &$Src;
+ Eterm s1, s2, s3, s4;
+ s1 = src[0];
+ s2 = src[1];
+ s3 = src[2];
+ s4 = src[3];
+ $D1 = s1;
+ $D2 = s2;
+ $D3 = s3;
+ $D4 = s4;
+}
+
move_window2(S1, S2, D) {
Eterm xt0, xt1;
Eterm* y = &$D;
@@ -703,9 +739,11 @@ jump(Fail) {
$JUMP($Fail);
}
-move_jump(Fail, Src) {
- x(0) = $Src;
- $jump($Fail);
+move_jump(Lbl, Src, Dst) {
+ Eterm lbl = $Lbl;
+ Eterm src = $Src;
+ $Dst = src;
+ $JUMP(lbl);
}
//
@@ -817,6 +855,16 @@ is_tagged_tuple(Fail, Src, Arityval, Tag) {
}
}
+is_tagged_tuple_ff(NotTupleFail, WrongRecordFail, Src, Arityval, Tag) {
+ Eterm term = $Src;
+ if (is_not_tuple(term)) {
+ $FAIL($NotTupleFail);
+ } else if (ERTS_UNLIKELY((tuple_val(term))[0] != $Arityval ||
+ (tuple_val(term))[1] != $Tag)) {
+ $FAIL($WrongRecordFail);
+ }
+}
+
is_tuple(Fail, Src) {
if (is_not_tuple($Src)) {
$FAIL($Fail);
diff --git a/erts/emulator/beam/map_instrs.tab b/erts/emulator/beam/map_instrs.tab
index c594a87298..5620d5a2d1 100644
--- a/erts/emulator/beam/map_instrs.tab
+++ b/erts/emulator/beam/map_instrs.tab
@@ -127,11 +127,21 @@ i_get_map_elements(Fail, Src, N) {
}
}
-update_map_assoc(Src, Dst, Live, N) {
+update_map_assoc := update_map_assoc.fetch.execute;
+
+update_map_assoc.head() {
+ Eterm map;
+}
+
+update_map_assoc.fetch(Src) {
+ map = $Src;
+}
+
+update_map_assoc.execute(Dst, Live, N) {
Eterm res;
Uint live = $Live;
- reg[live] = $Src;
+ reg[live] = map;
HEAVY_SWAPOUT;
res = erts_gc_update_map_assoc(c_p, reg, live, $N, $NEXT_INSTRUCTION);
HEAVY_SWAPIN;
@@ -141,11 +151,21 @@ update_map_assoc(Src, Dst, Live, N) {
$NEXT($NEXT_INSTRUCTION+$N);
}
-update_map_exact(Fail, Src, Dst, Live, N) {
+update_map_exact := update_map_exact.fetch.execute;
+
+update_map_exact.head() {
+ Eterm map;
+}
+
+update_map_exact.fetch(Src) {
+ map = $Src;
+}
+
+update_map_exact.execute(Fail, Dst, Live, N) {
Eterm res;
Uint live = $Live;
- reg[live] = $Src;
+ reg[live] = map;
HEAVY_SWAPOUT;
res = erts_gc_update_map_exact(c_p, reg, live, $N, $NEXT_INSTRUCTION);
HEAVY_SWAPIN;
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index da5364183c..6832e65b1b 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -106,7 +106,10 @@ init y
allocate_zero t t?
allocate_heap_zero t I t?
+move Src=y Dst=x | trim N Remaining => move_trim Src Dst N
trim N Remaining => i_trim N
+
+move_trim y x t
i_trim t
test_heap I t?
@@ -261,12 +264,14 @@ system_limit j
# Move instructions.
#
-move C=cxy x==0 | jump Lbl => move_jump Lbl C
+move Src=cxy Dst=xy | jump Lbl => move_jump Lbl Src Dst
+
+move_jump f cxy xy
+move_jump f c r
-move_jump f ncxy
-# Movement to and from the stack is common
-# Try to pack as much as we can into one instruction
+# Movement to and from the stack is common.
+# Try to pack as much as we can into one instruction.
# Window move
move_window/5
@@ -294,11 +299,49 @@ move_window3 x x x y
move_window4 x x x x y
move_window5 x x x x x y
+# y -> x
+
+move_src_window/4
+move_src_window/5
+
+move Y1=y X1=x | move Y2=y X2=x | succ(Y1, Y2) => \
+ move_src_window Y1 Y2 X1 X2
+
+move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | succ(Y2, Y3) => \
+ move_src_window Y1 Y3 X1 X2 X3
+move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | move Y4=y X4=x | succ(Y3, Y4) => \
+ move_src_window2 Y1 X1 X2 | move_src_window Y3 Y4 X3 X4
+move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x => \
+ move3 Y1 X1 Y2 X2 Y3 X3
+
+move_src_window Y1 Y3 X1 X2 X3 | move Y4=y X4=x | succ(Y3, Y4) => \
+ move_src_window4 Y1 X1 X2 X3 X4
+
+move_src_window Y1 y X1 X2 => move_src_window2 Y1 X1 X2
+move_src_window Y1 y X1 X2 X3 => move_src_window3 Y1 X1 X2 X3
+
+move_src_window2 y x x
+move_src_window3 y x x x
+move_src_window4 y x x x x
+
# Swap registers.
-move R1=x Tmp=x | move R2=x R1 | move Tmp R2 => swap_temp R1 R2 Tmp
+move R1=xy Tmp=x | move R2=xy R1 | move Tmp R2 => swap_temp R1 R2 Tmp
+
+# The compiler uses x(1022) when swapping registers. It will definitely
+# not be used again.
+swap_temp R1 R2 Tmp=x==1022 => swap R1 R2
+
+swap_temp R1 R2 Tmp | move Src Tmp => swap R1 R2 | move Src Tmp
swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed_apply(Tmp, Live) => \
swap R1 R2 | line Loc | apply Live
+swap_temp R1 R2 Tmp | line Loc | apply_last Live D | is_killed_apply(Tmp, Live) => \
+ swap R1 R2 | line Loc | apply_last Live D
+
+swap_temp R1 R2 Tmp | line Loc | call_fun Live | is_killed(Tmp, Live) => \
+ swap R1 R2 | line Loc | call_fun Live
+swap_temp R1 R2 Tmp | make_fun2 OldIndex=u | is_killed_by_make_fun(Tmp, OldIndex) => \
+ swap R1 R2 | make_fun2 OldIndex
swap_temp R1 R2 Tmp | line Loc | call Live Addr | is_killed(Tmp, Live) => \
swap R1 R2 | line Loc | call Live Addr
@@ -314,27 +357,55 @@ swap_temp R1 R2 Tmp | line Loc | call_ext_only Live Addr | \
swap_temp R1 R2 Tmp | line Loc | call_ext_last Live Addr D | \
is_killed(Tmp, Live) => swap R1 R2 | line Loc | call_ext_last Live Addr D
-swap_temp x x x
-
-swap x x
+swap_temp R1 R2 Tmp | call_ext Live Addr | is_killed(Tmp, Live) => \
+ swap R1 R2 | call_ext Live Addr
+swap_temp R1 R2 Tmp | call_ext_only Live Addr | is_killed(Tmp, Live) => \
+ swap R1 R2 | call_ext_only Live Addr
+swap_temp R1 R2 Tmp | call_ext_last Live Addr D | is_killed(Tmp, Live) => \
+ swap R1 R2 | call_ext_last Live Addr D
+
+swap_temp R1 R2 Tmp | move Src Any | line Loc | call Live Addr | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | line Loc | call Live Addr
+swap_temp R1 R2 Tmp | move Src Any | line Loc | call_ext Live Addr | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | line Loc | call_ext Live Addr
+swap_temp R1 R2 Tmp | move Src Any | call_only Live Addr | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | call_only Live Addr
+swap_temp R1 R2 Tmp | move Src Any | line Loc | call_ext_only Live Addr | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | line Loc | call_ext_only Live Addr
+swap_temp R1 R2 Tmp | move Src Any | line Loc | call_fun Live | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | line Loc | call_fun Live
+
+swap_temp R1 R2 Tmp | line Loc | send | is_killed_by_send(Tmp) => \
+ swap R1 R2 | line Loc | send
+
+# swap_temp/3 with Y register operands are rare.
+swap_temp R1 R2=y Tmp => swap R1 R2 | move R2 Tmp
+swap_temp R1=y R2 Tmp => swap R1 R2 | move R2 Tmp
+
+swap R1=x R2=y => swap R2 R1
-# move_dup
-
-move Src=x D1=x | move Src=x D2=x => move_dup Src D1 D2
-move Src=x SD=x | move SD=x D=x => move_dup Src SD D
+swap_temp x x x
-move_dup x x x
+swap xy x
+swap y y
# move_shift
-move SD=x D=x | move Src=xy SD=x | distinct(D, Src) => move_shift Src SD D
-move SD=y D=x | move Src=x SD=y | distinct(D, Src) => move_shift Src SD D
-move SD=x D=y | move Src=x SD=x | distinct(D, Src) => move_shift Src SD D
+move SD=x D=x | move Src=cxy SD=x | distinct(D, Src) => move_shift Src SD D
+move SD=y D=x | move Src=x SD=y | distinct(D, Src) => move_shift Src SD D
+move SD=y D=x | init SD | => move_shift n SD D
+move SD=x D=y | move Src=x SD=x | distinct(D, Src) => move_shift Src SD D
+move SD=x==0 D=y | move Src=y SD=x==0 | distinct(D, Src) => move_shift Src SD D
-move_shift x x x
-move_shift y x x
-move_shift x y x
+move_shift cxy x x
+move_shift nx y x
move_shift x x y
+move_shift y r y
# move2_par x x x x
@@ -530,32 +601,26 @@ put_list Src Dst=x Dst => update_list Src Dst
update_list xyc x
-put_list x n x
-put_list y n x
-put_list x x x
-put_list y x x
+# put_list SrcReg1 SrcReg2 => Dst
-put_list y y x
-put_list x y x
+put_list xy xy x
-# put_list SrcReg Constant Dst
+# put_list SrcReg [] => Dst
-put_list x c x
-put_list x c y
+put_list xy n xy
-put_list y c x
+# put_list SrcReg Constant => x
-# put_list Constant SrcReg Dst
+put_list xy c x
-put_list c x x
-put_list c y x
+# put_list Constant SrcReg => Dst
+
+put_list c xy x
# The following put_list instructions using x(0) are frequently used.
-put_list r n r
-put_list r n x
-put_list r x x
-put_list r x r
+put_list r n rx
+put_list r x rx
put_list x x r
%cold
@@ -629,6 +694,11 @@ test_arity f? xy A
test_arity_get_tuple_element f? x A P x
+is_tuple NotTupleFail Tuple=x | is_tagged_tuple WrongRecordFail Tuple Arity Atom => \
+ is_tagged_tuple_ff NotTupleFail WrongRecordFail Tuple Arity Atom
+
+is_tagged_tuple_ff f? f? rx A a
+
get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
get_tuple_element Reg=x P3 D3=x | \
succ(P1, P2) | succ(P2, P3) | \
@@ -1103,8 +1173,25 @@ call_fun Arity => i_call_fun Arity
i_call_fun t
i_call_fun_last t Q
+
+#
+# A fun with an empty environment can be converted to a literal.
+# As a further optimization, the we try to move the fun to its
+# final destination directly.
+
make_fun2 OldIndex=u => gen_make_fun2(OldIndex)
+move_fun/2
+move_fun Fun X0 | move X0 Dst | move Src X0 => move Fun Dst | move Src X0
+move_fun Fun X0 | move A B | move X0 Dst | move Src X0 | \
+ independent_moves(Fun, X0, A, B) | distinct(Dst, A) => \
+ move Fun Dst | move A B | move Src X0
+move_fun Fun X0 | move X0 Dst | make_fun2 OldIndex | \
+ is_killed_by_make_fun(X0, OldIndex)=> \
+ move Fun Dst | make_fun2 OldIndex
+
+move_fun Fun Dst => move Fun Dst
+
%cold
i_make_fun W t
%hot
@@ -1484,23 +1571,22 @@ put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \
sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => \
new_map Dst Live Size Rest
-sorted_put_map_assoc Src=s Dst Live Size Rest=* => \
- update_map_assoc Src Dst Live Size Rest
-sorted_put_map_assoc Src Dst Live Size Rest=* => \
- move Src x | update_map_assoc x Dst Live Size Rest
+sorted_put_map_assoc Src=xyc Dst Live Size Rest=* => \
+ update_map_assoc Src Dst Live Size Rest
-sorted_put_map_exact F Src=s Dst Live Size Rest=* => \
- update_map_exact F Src Dst Live Size Rest
-sorted_put_map_exact F Src Dst Live Size Rest=* => \
- move Src x | update_map_exact F x Dst Live Size Rest
+sorted_put_map_exact Fail Src=xy Dst Live Size Rest=* => \
+ update_map_exact Src Fail Dst Live Size Rest
+# Literal map arguments for an exact update operation are extremely rare.
+sorted_put_map_exact Fail Src Dst Live Size Rest=* => \
+ move Src x | update_map_exact x Fail Dst Live Size Rest
new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => \
gen_new_small_map_lit(Dst, Live, Size, Rest)
new_map d t I
i_new_small_map_lit d t q
-update_map_assoc s d t I
-update_map_exact j? s d t I
+update_map_assoc xyc d t I
+update_map_exact xy j? d t I
is_map Fail Lit=q | literal_is_map(Lit) =>
is_map Fail cq => jump Fail
@@ -1562,6 +1648,11 @@ gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \
# Arithmetic instructions.
#
+# It is OK to swap arguments for '+' in a guard. It is also
+# OK to turn minus into plus in a guard.
+gen_plus Fail=f Live S1=c S2 Dst => i_plus S2 S1 Fail Dst
+gen_minus Fail=f Live S1 S2=i Dst => gen_plus_from_minus(Fail, Live, S1, S2, Dst)
+
gen_plus Fail Live S1 S2 Dst => i_plus S1 S2 Fail Dst
gen_minus Fail Live S1 S2 Dst => i_minus S1 S2 Fail Dst
@@ -1595,10 +1686,13 @@ gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst=d => i_int_bnot Fail Src Dst
i_increment rxy W d
-i_plus x xy j? d
-i_plus s s j? d
+# Handle unoptimized code.
+i_plus S1=c S2=c Fail Dst => move S1 x | i_plus x S2 Fail Dst
+
+i_plus xy xyc j? d
i_minus x x j? d
+i_minus c x j? d
i_minus s s j? d
i_times j? s s d
@@ -1639,8 +1733,9 @@ bif1 Fail u$bif:erlang:trunc/1 s d => too_old_compiler
gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => \
i_length_setup Live Src | i_length Fail Live Dst
-i_length_setup t xyc
+i_length_setup Live Src=c => move Src x | i_length_setup Live x
+i_length_setup t xy
i_length j? t d
#