diff options
Diffstat (limited to 'erts/emulator/beam/generators.tab')
-rw-r--r-- | erts/emulator/beam/generators.tab | 194 |
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; |