From 331bb6cab54e6697e12cc9c5a4ca0ae618c37dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 23 May 2012 16:08:59 +0200 Subject: BEAM loader: Support preservation of extra operand in transforms It was not possible to preserve extra arguments in transformations. The following (hypothetical) example will now work: some_op Lit=c SizeArg Rest=* => move Lit x | some_op x SizeArg Rest --- erts/emulator/beam/beam_load.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'erts/emulator/beam') diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 938fd8f2c9..58207ec75b 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -4376,6 +4376,7 @@ transform_engine(LoaderState* st) Uint* restart; /* Where to restart if current match fails. */ GenOpArg def_vars[TE_MAX_VARS]; /* Default buffer for variables. */ GenOpArg* var = def_vars; + int num_vars = 0; int i; /* General index. */ Uint mask; GenOp* instr; @@ -4578,9 +4579,9 @@ transform_engine(LoaderState* st) { int n = *pc++; int formal_arity = gen_opc[instr->op].arity; - int num_vars = n + (instr->arity - formal_arity); int j = formal_arity; + num_vars = n + (instr->arity - formal_arity); var = erts_alloc(ERTS_ALC_T_LOADER_TMP, num_vars * sizeof(GenOpArg)); for (i = 0; i < n; i++) { @@ -4592,7 +4593,6 @@ transform_engine(LoaderState* st) } break; #endif - case TOP_next_arg: ap++; break; @@ -4680,6 +4680,20 @@ transform_engine(LoaderState* st) instr->a[ap].val = var[i].val; ap++; break; +#if defined(TOP_store_rest_args) + case TOP_store_rest_args: + { + int n = *pc++; + int num_extra = num_vars - n; + + ASSERT(n <= num_vars); + GENOP_ARITY(instr, instr->arity+num_extra); + memcpy(instr->a, instr->def_args, ap*sizeof(GenOpArg)); + memcpy(instr->a+ap, var+n, num_extra*sizeof(GenOpArg)); + ap += num_extra; + } + break; +#endif case TOP_try_me_else: restart = pc + 1; restart += *pc++; -- cgit v1.2.3