summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/generators.tab
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/generators.tab')
-rw-r--r--erts/emulator/beam/generators.tab194
1 files changed, 108 insertions, 86 deletions
diff --git a/erts/emulator/beam/generators.tab b/erts/emulator/beam/generators.tab
index eec78315a2..a737228c44 100644
--- a/erts/emulator/beam/generators.tab
+++ b/erts/emulator/beam/generators.tab
@@ -2,7 +2,7 @@
//
// %CopyrightBegin%
//
-// Copyright Ericsson AB 2020-2021. All Rights Reserved.
+// Copyright Ericsson AB 2020-2023. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -300,111 +300,133 @@ gen.skip_bits2(Fail, Ms, Size, Unit, Flags) {
return op;
}
-gen_increment(stp, reg, val, dst) {
- BeamOp* op;
- $NewBeamOp($stp, op);
- $BeamOpNameArity(op, i_increment, 3);
- op->a[0] = $reg;
- op->a[1].type = TAG_u;
- op->a[1].val = $val;
- op->a[2] = $dst;
- return op;
-}
-
-gen.increment(Reg, Integer, Dst) {
- $gen_increment(S, Reg, Integer.val, Dst);
-}
-
-gen.increment_from_minus(Reg, Integer, Dst) {
- $gen_increment(S, Reg, -Integer.val, Dst);
-}
-
-gen.plus_from_minus(Fail, Live, Src, Integer, Dst) {
- BeamOp* op;
-
- ASSERT(Integer.type == TAG_i && IS_SSMALL(-(Sint)Integer.val));
-
- $NewBeamOp(S, op);
- $BeamOpNameArity(op, gen_plus, 5);
- op->a[0] = Fail;
- op->a[1] = Live;
- op->a[2] = Src;
- op->a[3].type = TAG_i;
- op->a[3].val = -(Sint)Integer.val;
- op->a[4] = Dst;
+// Creates an instruction that moves a literal lambda to a register.
+MakeLiteralLambda(Op, Index, DstType, DstVal) {
+ BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[Idx.val];
+ SWord literal;
+
+ ASSERT(entry->num_free == 0);
+
+ /* If we haven't already done so, we need to create a placeholder for the
+ * lambda. */
+ if (S->lambda_literals[$Index] == ERTS_SWORD_MAX) {
+ Eterm tmp_hp[ERL_FUN_SIZE];
+ ErlFunThing *funp;
+
+ /* The placeholder is an external fun with the export field set to
+ * NULL, preventing it from colliding with external fun literals
+ * created by the user. We also disable deduplication to prevent it
+ * from colliding with other placeholder lambdas of the same arity. */
+ funp = (ErlFunThing*)tmp_hp;
+ funp->thing_word = HEADER_FUN;
+ funp->entry.exp = NULL;
+ funp->next = NULL;
+ funp->arity = entry->arity;
+ funp->num_free = 0;
+ funp->creator = am_external;
+
+ literal = beamfile_add_literal(&S->beam, make_fun(tmp_hp), 0);
+ S->lambda_literals[$Index] = literal;
+ } else {
+ literal = S->lambda_literals[$Index];
+ }
- return op;
+ $BeamOpNameArity($Op, move, 2);
+ ($Op)->a[0].type = TAG_q;
+ ($Op)->a[0].val = literal;
+ ($Op)->a[1].type = $DstType;
+ ($Op)->a[1].val = $DstVal;
}
-gen.make_fun2(idx) {
+gen.make_fun2(Idx) {
BeamOp* op;
BeamOp* th;
$NewBeamOp(S, op);
- if (idx.val >= S->beam.lambdas.count) {
+ if (Idx.val >= S->beam.lambdas.count) {
$BeamOpNameArity(op, i_lambda_error, 1);
op->a[0].type = TAG_o;
op->a[0].val = 0;
- return op;
+ return op;
} else {
- int i;
- BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[idx.val];
- unsigned num_free = entry->num_free;
- unsigned arity = entry->arity;
-
- $NewBeamOp(S, th);
-
- $BeamOpNameArity(th, test_heap, 2);
- th->a[0].type = TAG_u;
- th->a[0].val = ERL_FUN_SIZE + num_free;
- th->a[1].type = TAG_u;
- th->a[1].val = num_free;
- th->next = op;
-
- $BeamOpNameArity(op, i_make_fun3, 4);
- $BeamOpArity(op, 4 + num_free);
- op->a[0].type = TAG_u;
- op->a[0].val = idx.val;
- op->a[1].type = TAG_x;
- op->a[1].val = 0;
- op->a[2].type = TAG_u;
- op->a[2].val = arity - num_free;
- op->a[3].type = TAG_u;
- op->a[3].val = num_free;
- for (i = 0; i < num_free; i++) {
- op->a[i+4].type = TAG_x;
- op->a[i+4].val = i;
- }
- return th;
+ BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[Idx.val];
+ unsigned num_free = entry->num_free;
+ unsigned arity = entry->arity;
+ int i;
+
+ /* Literal lambdas are all owned by the init process as a workaround
+ * for all local funs needing a creator pid. Skip the optimization if
+ * this module is being loaded before said process has started
+ * (just preloaded modules, really). */
+ if (num_free == 0 && erts_init_process_id != ERTS_INVALID_PID) {
+ $MakeLiteralLambda(op, Idx.val, TAG_x, 0);
+ return op;
+ }
+
+ $NewBeamOp(S, th);
+
+ $BeamOpNameArity(th, test_heap, 2);
+ th->a[0].type = TAG_u;
+ th->a[0].val = ERL_FUN_SIZE + num_free;
+ th->a[1].type = TAG_u;
+ th->a[1].val = num_free;
+ th->next = op;
+
+ $BeamOpNameArity(op, i_make_fun3, 4);
+ $BeamOpArity(op, 4 + num_free);
+ op->a[0].type = TAG_u;
+ op->a[0].val = Idx.val;
+ op->a[1].type = TAG_x;
+ op->a[1].val = 0;
+ op->a[2].type = TAG_u;
+ op->a[2].val = arity - num_free;
+ op->a[3].type = TAG_u;
+ op->a[3].val = num_free;
+
+ for (i = 0; i < num_free; i++) {
+ op->a[i+4].type = TAG_x;
+ op->a[i+4].val = i;
+ }
+
+ return th;
}
}
-gen.make_fun3(idx, Dst, NumFree, Env) {
+gen.make_fun3(Idx, Dst, NumFree, Env) {
BeamOp* op;
$NewBeamOp(S, op);
- if (idx.val < S->beam.lambdas.count) {
- BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[idx.val];
- if (NumFree.val == entry->num_free) {
- int i;
-
- $BeamOpNameArity(op, i_make_fun3, 4);
- $BeamOpArity(op, 4 + NumFree.val);
- op->a[0].type = TAG_u;
- op->a[0].val = idx.val;
- op->a[1] = Dst;
- op->a[2].type = TAG_u;
- op->a[2].val = entry->arity - entry->num_free;
- op->a[3].type = TAG_u;
- op->a[3].val = entry->num_free;
- for (i = 0; i < NumFree.val; i++) {
- op->a[i+4] = Env[i];
- }
- return op;
- }
+ if (Idx.val < S->beam.lambdas.count) {
+ BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[Idx.val];
+
+ if (NumFree.val == entry->num_free) {
+ int i;
+
+ if (NumFree.val == 0 && erts_init_process_id != ERTS_INVALID_PID) {
+ $MakeLiteralLambda(op, Idx.val, Dst.type, Dst.val);
+ } else {
+ $BeamOpNameArity(op, i_make_fun3, 4);
+ $BeamOpArity(op, 4 + NumFree.val);
+
+ op->a[0].type = TAG_u;
+ op->a[0].val = Idx.val;
+ op->a[1] = Dst;
+ op->a[2].type = TAG_u;
+ op->a[2].val = entry->arity - entry->num_free;
+ op->a[3].type = TAG_u;
+ op->a[3].val = entry->num_free;
+
+ for (i = 0; i < NumFree.val; i++) {
+ op->a[i+4] = Env[i];
+ }
+ }
+
+ return op;
+ }
}
+
$BeamOpNameArity(op, i_lambda_error, 1);
op->a[0].type = TAG_o;
op->a[0].val = 0;