Browse Source

rework compiler handling of intermediate value flags in anticipation for adding more flags

pull/1/head
Sami Vaarala 11 years ago
parent
commit
ebf14dcd23
  1. 102
      src/duk_js_compiler.c

102
src/duk_js_compiler.c

@ -113,8 +113,7 @@ static int getconst(duk_compiler_ctx *comp_ctx);
static int ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ispec *x,
int forced_reg,
int allow_const,
int require_temp);
int flags);
static int ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, int forced_reg);
static void ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, int forced_reg);
static void ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
@ -122,8 +121,7 @@ static void ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
static int ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ivalue *x,
int forced_reg,
int allow_const,
int require_temp);
int flags);
static int ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
#if 0 /* unused */
static int ivalue_totempreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
@ -1203,6 +1201,14 @@ static void peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
#define ALLOCTEMP(comp_ctx) alloctemp((comp_ctx))
#define ALLOCTEMPS(comp_ctx,count) alloctemps((comp_ctx),(count))
/* Flags for intermediate value coercions. A flag for using a forced reg
* is not needed, the forced_reg argument suffices and generates better
* code (it is checked as it is used).
*/
#define IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */
#define IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result */
#define IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
/* FIXME: some code might benefit from SETTEMP_IFTEMP(ctx,x) */
static void copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
@ -1296,8 +1302,9 @@ static int getconst(duk_compiler_ctx *comp_ctx) {
tv1 = duk_get_tval(ctx, -1);
DUK_ASSERT(tv1 != NULL);
/* sanity workaround for handling functions with a large number of
* constants at least somewhat reasonably.
/* Sanity workaround for handling functions with a large number of
* constants at least somewhat reasonably. Otherwise checking whether
* we already have the constant would grow very slow (as it is O(N^2)).
*/
n_check = (n > GETCONST_MAX_CONSTS_CHECK ? GETCONST_MAX_CONSTS_CHECK : n);
for (i = 0; i < n_check; i++) {
@ -1348,15 +1355,18 @@ static int getconst(duk_compiler_ctx *comp_ctx) {
static int ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ispec *x,
int forced_reg,
int allow_const,
int require_temp) {
int flags) {
duk_hthread *thr = comp_ctx->thr;
duk_context *ctx = (duk_context *) thr;
DUK_DDDPRINT("ispec_toregconst_raw(): x={%d:%d:%!T}, "
"forced_reg=%d, allow_const=%d, require_temp=%d",
"forced_reg=%d, flags 0x%08x: allow_const=%d require_temp=%d require_short=%d",
x->t, x->regconst, duk_get_tval(ctx, x->valstack_idx),
forced_reg, allow_const, require_temp);
forced_reg,
(int) flags,
(flags & IVAL_FLAG_ALLOW_CONST) ? 1 : 0,
(flags & IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0,
(flags & IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0);
switch (x->t) {
case DUK_ISPEC_VALUE: {
@ -1411,7 +1421,7 @@ static int ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_dup(ctx, x->valstack_idx);
constidx = getconst(comp_ctx);
if (allow_const) {
if (flags & IVAL_FLAG_ALLOW_CONST) {
return constidx;
}
@ -1437,7 +1447,7 @@ static int ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
dval = DUK_TVAL_GET_NUMBER(tv);
if (!allow_const) {
if (!(flags & IVAL_FLAG_ALLOW_CONST)) {
/* A number can be loaded either through a constant or
* using LDINT+LDINTX. Which is better depends on the
* context and how many times a certain constant would
@ -1460,7 +1470,7 @@ static int ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_dup(ctx, x->valstack_idx);
constidx = getconst(comp_ctx);
if (allow_const) {
if (flags & IVAL_FLAG_ALLOW_CONST) {
return constidx;
} else {
dest = (forced_reg >= 0 ? forced_reg : ALLOCTEMP(comp_ctx));
@ -1471,7 +1481,7 @@ static int ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
} /* end switch */
}
case DUK_ISPEC_REGCONST: {
if ((x->regconst & CONST_MARKER) && !allow_const) {
if ((x->regconst & CONST_MARKER) && !(flags & IVAL_FLAG_ALLOW_CONST)) {
int dest = (forced_reg >= 0 ? forced_reg : ALLOCTEMP(comp_ctx));
emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, x->regconst);
return dest;
@ -1482,7 +1492,7 @@ static int ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
}
return forced_reg;
} else {
if (require_temp && !ISTEMP(comp_ctx, x->regconst)) {
if ((flags & IVAL_FLAG_REQUIRE_TEMP) && !ISTEMP(comp_ctx, x->regconst)) {
int dest = ALLOCTEMP(comp_ctx);
emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, x->regconst);
return dest;
@ -1502,12 +1512,11 @@ static int ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
}
static int ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, int forced_reg) {
return ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*allow_const*/, 0 /*require_temp*/);
return ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
}
/* Coerce an duk_ivalue to a 'plain' value by generating the necessary
* arithmetic operations, property access, or variable access bytecode.
*
* The duk_ivalue argument ('x') is converted into a plain value as a
* side effect.
*/
@ -1579,8 +1588,8 @@ static void ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, int fo
}
}
arg1 = ispec_toregconst_raw(comp_ctx, &x->x1, -1, 1, 0); /* no forced reg, allow const, no require temp */
arg2 = ispec_toregconst_raw(comp_ctx, &x->x2, -1, 1, 0); /* same flags */
arg1 = ispec_toregconst_raw(comp_ctx, &x->x1, -1, IVAL_FLAG_ALLOW_CONST | IVAL_FLAG_REQUIRE_SHORT /*flags*/);
arg2 = ispec_toregconst_raw(comp_ctx, &x->x2, -1, IVAL_FLAG_ALLOW_CONST | IVAL_FLAG_REQUIRE_SHORT /*flags*/);
/* If forced reg, use it as destination. Otherwise try to
* use either coerced ispec if it is a temporary.
@ -1603,10 +1612,15 @@ static void ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, int fo
return;
}
case DUK_IVAL_PROP: {
int arg1 = ispec_toregconst_raw(comp_ctx, &x->x1, -1, 1, 0); /* no forced reg, allow const, no require temp */
int arg2 = ispec_toregconst_raw(comp_ctx, &x->x2, -1, 1, 0); /* same flags */
/* FIXME: very similar to DUK_IVAL_ARITH - merge? */
int arg1;
int arg2;
int dest;
/* need a short reg/const, does not have to be a mutable temp */
arg1 = ispec_toregconst_raw(comp_ctx, &x->x1, -1, IVAL_FLAG_ALLOW_CONST | IVAL_FLAG_REQUIRE_SHORT /*flags*/);
arg2 = ispec_toregconst_raw(comp_ctx, &x->x2, -1, IVAL_FLAG_ALLOW_CONST | IVAL_FLAG_REQUIRE_SHORT /*flags*/);
if (forced_reg >= 0) {
dest = forced_reg;
} else if (ISTEMP(comp_ctx, arg1)) {
@ -1678,28 +1692,30 @@ static void ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
static int ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ivalue *x,
int forced_reg,
int allow_const,
int require_temp) {
int flags) {
duk_hthread *thr = comp_ctx->thr;
duk_context *ctx = (duk_context *) thr;
int reg;
DUK_UNREF(thr);
DUK_UNREF(ctx);
DUK_DDDPRINT("ivalue_toregconst_raw(): x={t=%d,op=%d,x1={%d:%d:%!T},x2={%d:%d:%!T}}, "
"forced_reg=%d, allow_const=%d, require_temp=%d",
"forced_reg=%d, flags 0x%08x: allow_const=%d require_temp=%d require_short=%d",
x->t, x->op,
x->x1.t, x->x1.regconst, duk_get_tval(ctx, x->x1.valstack_idx),
x->x2.t, x->x2.regconst, duk_get_tval(ctx, x->x2.valstack_idx),
forced_reg, allow_const, require_temp);
forced_reg,
(int) flags,
(flags & IVAL_FLAG_ALLOW_CONST) ? 1 : 0,
(flags & IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0,
(flags & IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0);
/* first coerce to a plain value */
ivalue_toplain_raw(comp_ctx, x, forced_reg);
DUK_ASSERT(x->t == DUK_IVAL_PLAIN);
/* then to a register */
reg = ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, allow_const, require_temp);
reg = ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
x->x1.t = DUK_ISPEC_REGCONST;
x->x1.regconst = reg;
@ -1707,21 +1723,21 @@ static int ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
}
static int ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
return ivalue_toregconst_raw(comp_ctx, x, -1, 0, 0); /* no forced reg, don't allow const, don't require temp */
return ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
}
#if 0 /* unused */
static int ivalue_totempreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
return ivalue_toregconst_raw(comp_ctx, x, -1, 0, 1); /* no forced reg, don't allow const, require temp */
return ivalue_toregconst_raw(comp_ctx, x, -1, IVAL_FLAG_REQUIRE_TEMP /*flags*/);
}
#endif
static int ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, int forced_reg) {
return ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0, 0); /* forced reg, don't allow const, don't require temp */
return ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
}
static int ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
return ivalue_toregconst_raw(comp_ctx, x, -1, 1, 0); /* no forced reg, allow const, don't require temp */
return ivalue_toregconst_raw(comp_ctx, x, -1, IVAL_FLAG_ALLOW_CONST /*flags*/);
}
/* The issues below can be solved with better flags */
@ -2707,8 +2723,8 @@ static void expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
SETTEMP(comp_ctx, temp_at_entry);
reg_temp = ALLOCTEMP(comp_ctx);
reg_obj = ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*allow_const*/, 0 /*require_temp*/); /* don't allow const */
reg_key = ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, 1 /*allow_const*/, 0 /*require_temp*/);
reg_obj = ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
reg_key = ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, IVAL_FLAG_ALLOW_CONST /*flags*/);
emit_a_b_c(comp_ctx, DUK_OP_DELPROP, reg_temp, reg_obj, reg_key);
res->t = DUK_IVAL_PLAIN;
@ -2821,7 +2837,7 @@ static void expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
*/
int tr;
tr = ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, 0 /*allow_const*/, 1 /*require_temp*/);
tr = ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, IVAL_FLAG_REQUIRE_TEMP /*flags*/);
emit_a_b(comp_ctx, args >> 8, tr, tr);
res->t = DUK_IVAL_PLAIN;
res->x1.t = DUK_ISPEC_REGCONST;
@ -2833,7 +2849,7 @@ static void expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
{
/* FIXME: refactor into unary2: above? */
int tr;
tr = ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, 0 /*allow_const*/, 1 /*require_temp*/);
tr = ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, IVAL_FLAG_REQUIRE_TEMP /*flags*/);
emit_extraop_b_c(comp_ctx, args >> 8, tr, tr);
res->t = DUK_IVAL_PLAIN;
res->x1.t = DUK_ISPEC_REGCONST;
@ -2877,8 +2893,8 @@ static void expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
} else if (res->t == DUK_IVAL_PROP) {
int reg_obj; /* allocate to reg only (not const) */
int reg_key;
reg_obj = ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*allow_const*/, 0 /*require_temp*/);
reg_key = ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, 1 /*allow_const*/, 0 /*require_temp*/);
reg_obj = ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
reg_key = ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, IVAL_FLAG_ALLOW_CONST /*flags*/);
emit_a_b_c(comp_ctx, DUK_OP_GETPROP, reg_res, reg_obj, reg_key);
emit_a_b(comp_ctx, args_op, reg_res, reg_res);
emit_a_b_c(comp_ctx, DUK_OP_PUTPROP, reg_obj, reg_key, reg_res);
@ -3498,8 +3514,8 @@ static void expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *r
* it goes into the 'A' field of the opcode.
*/
reg_obj = ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*allow_const*/, 0 /*require_temp*/);
reg_key = ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, 1 /*allow_const*/, 0 /*require_temp*/);
reg_obj = ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
reg_key = ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, IVAL_FLAG_ALLOW_CONST /*flags*/);
if (args_op == DUK_OP_INVALID) {
reg_res = res->x1.regconst;
@ -3597,8 +3613,8 @@ static void expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *r
int reg_obj; /* allocate to reg only (not const) */
int reg_key;
int reg_temp = ALLOCTEMP(comp_ctx);
reg_obj = ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*allow_const*/, 0 /*require_temp*/);
reg_key = ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, 1 /*allow_const*/, 0 /*require_temp*/);
reg_obj = ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
reg_key = ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, IVAL_FLAG_ALLOW_CONST /*flags*/);
emit_a_b_c(comp_ctx, DUK_OP_GETPROP, reg_res, reg_obj, reg_key);
emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_TONUM, reg_res, reg_res);
emit_a_b(comp_ctx, args_op, reg_temp, reg_res);
@ -4082,8 +4098,8 @@ static void parse_for_statement(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int
*/
int reg_obj;
int reg_key;
reg_obj = ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*allow_const*/, 0 /*require_temp*/);
reg_key = ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, 1 /*allow_const*/, 0 /*require_temp*/);
reg_obj = ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
reg_key = ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, IVAL_FLAG_ALLOW_CONST /*flags*/);
emit_a_b_c(comp_ctx, DUK_OP_PUTPROP, reg_obj, reg_key, reg_temps + 0);
} else {
ivalue_toplain_ignore(comp_ctx, res); /* just in case */

Loading…
Cancel
Save