aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/beam_load.c
diff options
context:
space:
mode:
authorMichał Muskała <[email protected]>2018-05-09 19:41:24 +0200
committerMichał Muskała <[email protected]>2018-07-17 13:58:27 +0200
commitf31db22102bde44c6ee17bc756bdeb109855acea (patch)
tree3342059d448e5d6af69b96b2bd2d0eaf84ffc755 /erts/emulator/beam/beam_load.c
parent9ae2044073e6433030ce30756658b103ce67c3c1 (diff)
downloadotp-f31db22102bde44c6ee17bc756bdeb109855acea.tar.gz
otp-f31db22102bde44c6ee17bc756bdeb109855acea.tar.bz2
otp-f31db22102bde44c6ee17bc756bdeb109855acea.zip
Optimise creation of anonymous functions
This introduces a similar optimisation for normal funs to what was introduced for external funs in #1725. It is possible to allocate the fun as a literal, if it does not capture the environment (i.e. it does not close over any variables). Unfortunately it's not possible to do this in the compiler due to problems with representation of such functions in the `.beam` files. Fortunately, we can do this in the loader. Simple evaluation shows that functions that don't capture the enviornment consistute over 60% of all funs in the source code of Erlang/OTP itself. The only downside is that we lose a meningful value in the `pid` field of the fun. The goal of this field, beyond debugging, was to be able to identify the original node of a function. To be able to still do this, the functions that are created in the loader are assigned the init pid as the creator. To solve issues with staryp, initially set the `erts_init_process_id` to `ERTS_INVALID_PID` and skip the described optimisation if the value is still uninitialised.
Diffstat (limited to 'erts/emulator/beam/beam_load.c')
-rw-r--r--erts/emulator/beam/beam_load.c52
1 files changed, 43 insertions, 9 deletions
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index e61199a8fd..50cbb37f3e 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -4245,21 +4245,55 @@ gen_make_fun2(LoaderState* stp, GenOpArg idx)
{
ErlFunEntry* fe;
GenOp* op;
+ Uint arity, num_free;
if (idx.val >= stp->num_lambdas) {
- stp->lambda_error = "missing or short chunk 'FunT'";
- fe = 0;
+ stp->lambda_error = "missing or short chunk 'FunT'";
+ fe = 0;
+ num_free = 0;
+ arity = 0;
} else {
- fe = stp->lambdas[idx.val].fe;
+ fe = stp->lambdas[idx.val].fe;
+ num_free = stp->lambdas[idx.val].num_free;
+ arity = fe->arity;
}
NEW_GENOP(stp, op);
- op->op = genop_i_make_fun_2;
- op->arity = 2;
- op->a[0].type = TAG_u;
- op->a[0].val = (BeamInstr) fe;
- op->a[1].type = TAG_u;
- op->a[1].val = stp->lambdas[idx.val].num_free;
+
+ /*
+ * It's possible this is called before init process is started,
+ * skip the optimisation in such case.
+ */
+ if (num_free == 0 && erts_init_process_id != ERTS_INVALID_PID) {
+ Uint lit;
+ Eterm* hp;
+ ErlFunThing* funp;
+
+ lit = new_literal(stp, &hp, ERL_FUN_SIZE);
+ funp = (ErlFunThing *) hp;
+ erts_refc_inc(&fe->refc, 2);
+ funp->thing_word = HEADER_FUN;
+ funp->next = NULL;
+ funp->fe = fe;
+ funp->num_free = 0;
+ funp->creator = erts_init_process_id;
+ funp->arity = arity;
+
+ op->op = genop_move_2;
+ op->arity = 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;
+ op->a[0].type = TAG_u;
+ op->a[0].val = (BeamInstr) fe;
+ op->a[1].type = TAG_u;
+ op->a[1].val = num_free;
+ }
+
op->next = NULL;
return op;
}