Browse Source

Merge branch 'add-shuffle-torture-flag'

pull/156/head
Sami Vaarala 10 years ago
parent
commit
bb00d0cab9
  1. 1
      Makefile
  2. 3
      RELEASES.rst
  3. 7
      doc/feature-options.rst
  4. 6
      doc/release-checklist.rst
  5. 5
      src/duk_features.h.in
  6. 151
      src/duk_js_compiler.c
  7. 19
      src/duk_js_executor.c
  8. 3
      util/matrix_compile.py

1
Makefile

@ -188,6 +188,7 @@ CCOPTS_FEATURES += -DDUK_OPT_SELF_TESTS
#CCOPTS_FEATURES += -DDUK_OPT_NO_PC2LINE
#CCOPTS_FEATURES += -DDUK_OPT_NO_VERBOSE_ERRORS
#CCOPTS_FEATURES += -DDUK_OPT_GC_TORTURE
#CCOPTS_FEATURES += -DDUK_OPT_SHUFFLE_TORTURE
#CCOPTS_FEATURES += -DDUK_OPT_NO_MS_RESIZE_STRINGTABLE
CCOPTS_FEATURES += -DDUK_OPT_DEBUG_BUFSIZE=512
#CCOPTS_FEATURES += -DDUK_OPT_NO_STRICT_DECL

3
RELEASES.rst

@ -843,6 +843,9 @@ Planned
* Fix for-in statement shuffle bug which caused enumeration to fail
in large functions which enable register shuffling (GH-132)
* Fix shuffle handling issue for PUTPROP opcode, discovered by shuffle
torture tests (GH-135)
* Add support for TI-Nspire (using Ndless, see GH-113)
2.0.0 (XXXX-XX-XX)

7
doc/feature-options.rst

@ -825,6 +825,13 @@ DUK_OPT_NO_ZERO_BUFFER_DATA
By default Duktape zeroes data allocated for buffer values. Define
this to disable the zeroing (perhaps for performance reasons).
DUK_OPT_SHUFFLE_TORTURE
-----------------------
Development time option: force compiler to shuffle every possible opcode
to stress shuffle behavior which is otherwise difficult to test for
comprehensively.
Using DUK_OPT_HAVE_CUSTOM_H and duk_custom.h
============================================

6
doc/release-checklist.rst

@ -121,6 +121,12 @@ Checklist for ordinary releases
- Run with assertions enabled at least on x86-64
* Run testcases with torture options
- DUK_OPT_GC_TORTURE
- DUK_OPT_SHUFFLE_TORTURE
* Memory usage testing
- Leaks are mostly detected by Valgrind, but bugs in valstack or object

5
src/duk_features.h.in

@ -2648,6 +2648,11 @@ typedef FILE duk_file;
#define DUK_USE_ESBC_MAX_LINENUMBER 0x7fff0000L
#define DUK_USE_ESBC_MAX_BYTES 0x7fff0000L
#undef DUK_USE_SHUFFLE_TORTURE
#if defined(DUK_OPT_SHUFFLE_TORTURE)
#define DUK_USE_SHUFFLE_TORTURE
#endif
/*
* User panic handler, panic exit behavior for default panic handler
*/

151
src/duk_js_compiler.c

@ -108,6 +108,7 @@ DUK_LOCAL_DECL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_ui
DUK_LOCAL_DECL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc);
DUK_LOCAL_DECL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags);
DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc);
DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
@ -1128,9 +1129,9 @@ DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op
/* Important main primitive. */
DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c) {
duk_instr_t ins = 0;
duk_int_t a_out = 0;
duk_int_t b_out = 0;
duk_int_t c_out = 0;
duk_int_t a_out = -1;
duk_int_t b_out = -1;
duk_int_t c_out = -1;
duk_int_t tmp;
DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
@ -1154,7 +1155,11 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
/* Slot A */
#if defined(DUK_USE_SHUFFLE_TORTURE)
if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
#else
if (a <= DUK_BC_A_MAX) {
#endif
;
} else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld", (long) a));
@ -1171,7 +1176,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
* is expressed indirectly, but there is no output shuffling.
*/
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) == 0);
duk__emit_load_int32(comp_ctx, tmp, a);
duk__emit_load_int32_noshuffle(comp_ctx, tmp, a);
DUK_ASSERT(DUK_OP_CSVARI == DUK_OP_CSVAR + 1);
DUK_ASSERT(DUK_OP_CSREGI == DUK_OP_CSREG + 1);
DUK_ASSERT(DUK_OP_CSPROPI == DUK_OP_CSPROP + 1);
@ -1195,7 +1200,11 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
DUK_ASSERT((op_flags & 0xff) != DUK_OP_CALL);
DUK_ASSERT((op_flags & 0xff) != DUK_OP_NEW);
b = b & ~DUK__CONST_MARKER;
#if defined(DUK_USE_SHUFFLE_TORTURE)
if (0) {
#else
if (b <= 0xff) {
#endif
ins |= DUK_ENC_OP_A_B_C(0, 0, 0x100, 0); /* const flag for B */
} else if (b <= DUK_BC_BC_MAX) {
comp_ctx->curr_func.needs_shuffle = 1;
@ -1207,7 +1216,11 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
goto error_outofregs;
}
} else {
#if defined(DUK_USE_SHUFFLE_TORTURE)
if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) {
#else
if (b <= 0xff) {
#endif
;
} else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) {
if (b > DUK_BC_B_MAX) {
@ -1231,7 +1244,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
* an indirect version of the opcode is used.
*/
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
duk__emit_load_int32(comp_ctx, tmp, b);
duk__emit_load_int32_noshuffle(comp_ctx, tmp, b);
DUK_ASSERT(DUK_OP_CALLI == DUK_OP_CALL + 1);
DUK_ASSERT(DUK_OP_NEWI == DUK_OP_NEW + 1);
DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1);
@ -1254,7 +1267,11 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
c = c & ~DUK__CONST_MARKER;
#if defined(DUK_USE_SHUFFLE_TORTURE)
if (0) {
#else
if (c <= 0xff) {
#endif
ins |= DUK_ENC_OP_A_B_C(0, 0, 0, 0x100); /* const flag for C */
} else if (c <= DUK_BC_BC_MAX) {
comp_ctx->curr_func.needs_shuffle = 1;
@ -1266,7 +1283,11 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
goto error_outofregs;
}
} else {
#if defined(DUK_USE_SHUFFLE_TORTURE)
if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) {
#else
if (c <= 0xff) {
#endif
;
} else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) {
if (c > DUK_BC_C_MAX) {
@ -1289,7 +1310,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
* normally. Use an indirect variant instead.
*/
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
duk__emit_load_int32(comp_ctx, tmp, c);
duk__emit_load_int32_noshuffle(comp_ctx, tmp, c);
DUK_ASSERT(DUK_EXTRAOP_INITGETI == DUK_EXTRAOP_INITGET + 1);
DUK_ASSERT(DUK_EXTRAOP_INITSETI == DUK_EXTRAOP_INITSET + 1);
a++; /* indirect opcode follows direct */
@ -1327,21 +1348,23 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
}
/* Output shuffling: only one output register is realistically possible.
* Zero is OK to check against: if the target register was zero, it is
* never shuffled.
*
* (Zero would normally be an OK marker value: if the target register
* was zero, it would never be shuffled. But with DUK_USE_SHUFFLE_TORTURE
* this is no longer true, so use -1 as a marker instead.)
*/
if (a_out != 0) {
DUK_ASSERT(b_out == 0);
DUK_ASSERT(c_out == 0);
if (a_out >= 0) {
DUK_ASSERT(b_out < 0);
DUK_ASSERT(c_out < 0);
duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out));
} else if (b_out != 0) {
DUK_ASSERT(a_out == 0);
DUK_ASSERT(c_out == 0);
} else if (b_out >= 0) {
DUK_ASSERT(a_out < 0);
DUK_ASSERT(c_out < 0);
duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out));
} else if (c_out != 0) {
DUK_ASSERT(b_out == 0);
DUK_ASSERT(c_out == 0);
} else if (c_out >= 0) {
DUK_ASSERT(b_out < 0);
DUK_ASSERT(c_out < 0);
duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out));
}
@ -1352,12 +1375,12 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
}
DUK_LOCAL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b) {
duk__emit_a_b_c(comp_ctx, op_flags, a, b, 0);
duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, b, 0);
}
#if 0 /* unused */
DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
duk__emit_a_b_c(comp_ctx, op_flags, a, 0, 0);
duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, 0, 0);
}
#endif
@ -1381,7 +1404,11 @@ DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_fl
goto error_outofregs;
}
#if defined(DUK_USE_SHUFFLE_TORTURE)
if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
#else
if (a <= DUK_BC_A_MAX) {
#endif
ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc);
duk__emit(comp_ctx, ins);
} else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
@ -1435,9 +1462,11 @@ DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, du
DUK_LOCAL void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b, duk_regconst_t c) {
DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
/* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */
/* Setting "no shuffle A" is covered by the assert, but it's needed
* with DUK_USE_SHUFFLE_TORTURE.
*/
duk__emit_a_b_c(comp_ctx,
DUK_OP_EXTRA | (extraop_flags & ~0xff), /* transfer flags */
DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
extraop_flags & 0xff,
b,
c);
@ -1446,9 +1475,11 @@ DUK_LOCAL void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_
DUK_LOCAL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b) {
DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
/* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */
/* Setting "no shuffle A" is covered by the assert, but it's needed
* with DUK_USE_SHUFFLE_TORTURE.
*/
duk__emit_a_b_c(comp_ctx,
DUK_OP_EXTRA | (extraop_flags & ~0xff), /* transfer flags */
DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
extraop_flags & 0xff,
b,
0);
@ -1457,9 +1488,11 @@ DUK_LOCAL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t
DUK_LOCAL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc) {
DUK_ASSERT_DISABLE(extraop >= DUK_BC_EXTRAOP_MIN); /* unsigned */
DUK_ASSERT(extraop <= DUK_BC_EXTRAOP_MAX);
/* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */
/* Setting "no shuffle A" is covered by the assert, but it's needed
* with DUK_USE_SHUFFLE_TORTURE.
*/
duk__emit_a_bc(comp_ctx,
DUK_OP_EXTRA,
DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A,
extraop,
bc);
}
@ -1467,15 +1500,18 @@ DUK_LOCAL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t
DUK_LOCAL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags) {
DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
/* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */
/* Setting "no shuffle A" is covered by the assert, but it's needed
* with DUK_USE_SHUFFLE_TORTURE.
*/
duk__emit_a_b_c(comp_ctx,
DUK_OP_EXTRA | (extraop_flags & ~0xff), /* transfer flags */
DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_B |
DUK__EMIT_FLAG_NO_SHUFFLE_C | (extraop_flags & ~0xff), /* transfer flags */
extraop_flags & 0xff,
0,
0);
}
DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val, duk_small_uint_t op_flags) {
/* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
* would only shuffle once (instead of twice). The current code works
* though, and has a smaller compiler footprint.
@ -1484,18 +1520,39 @@ DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, d
if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) &&
(val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) {
DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld", (long) reg, (long) val));
duk__emit_a_bc(comp_ctx, DUK_OP_LDINT, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS));
duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS));
} else {
duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT;
duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1);
DUK_ASSERT(lo >= 0);
DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld",
(long) reg, (long) val, (long) hi, (long) lo));
duk__emit_a_bc(comp_ctx, DUK_OP_LDINT, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS));
duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX, reg, (duk_regconst_t) lo);
duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS));
duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX | op_flags, reg, (duk_regconst_t) lo);
}
}
DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/);
}
#if defined(DUK_USE_SHUFFLE_TORTURE)
/* Used by duk__emit*() calls so that we don't shuffle the loadints that
* are needed to handle indirect opcodes.
*/
DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/);
}
#else
DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
/* When torture not enabled, can just use the same helper because
* 'reg' won't get spilled.
*/
DUK_ASSERT(reg <= DUK_BC_A_MAX);
duk__emit_load_int32(comp_ctx, reg, val);
}
#endif
DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) {
duk_hbuffer_dynamic *h;
duk_int_t curr_pc;
@ -1602,11 +1659,19 @@ DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t trycatc
}
DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
duk__emit_a_b_c(comp_ctx, DUK_OP_IF, 0 /*false*/, regconst, 0);
duk__emit_a_b_c(comp_ctx,
DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
0 /*false*/,
regconst,
0 /*unused*/);
}
DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
duk__emit_a_b_c(comp_ctx, DUK_OP_IF, 1 /*true*/, regconst, 0);
duk__emit_a_b_c(comp_ctx,
DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
1 /*true*/,
regconst,
0 /*unused*/);
}
DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
@ -3581,7 +3646,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
(duk_regconst_t) reg_res,
(duk_regconst_t) reg_res);
duk__emit_a_b_c(comp_ctx,
DUK_OP_PUTPROP,
DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
(duk_regconst_t) reg_obj,
rc_key,
(duk_regconst_t) reg_res);
@ -4119,7 +4184,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
duk__emit_a_b(comp_ctx,
DUK_OP_IF,
DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A,
(duk_regconst_t) args_truthval,
(duk_regconst_t) reg_temp); /* skip jump conditionally */
pc_jump = duk__emit_jump_empty(comp_ctx);
@ -4285,7 +4350,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
}
duk__emit_a_b_c(comp_ctx,
DUK_OP_PUTPROP,
DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
(duk_regconst_t) reg_obj,
rc_key,
rc_res);
@ -4414,7 +4479,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
(duk_regconst_t) reg_temp,
(duk_regconst_t) reg_res);
duk__emit_a_b_c(comp_ctx,
DUK_OP_PUTPROP,
DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
(duk_regconst_t) reg_obj,
rc_key,
(duk_regconst_t) reg_temp);
@ -4926,7 +4991,7 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
DUK_OP_PUTPROP,
DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
(duk_regconst_t) reg_obj,
rc_key,
(duk_regconst_t) (reg_temps + 0));
@ -5608,7 +5673,7 @@ DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
#endif
duk__emit_a_b(comp_ctx,
DUK_OP_RETURN,
DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
(duk_regconst_t) ret_flags /*flags*/,
rc_val /*reg*/);
}
@ -6695,7 +6760,7 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
}
duk__emit_a_b_c(comp_ctx,
DUK_OP_DECLVAR,
DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
(duk_regconst_t) declvar_flags /*flags*/,
rc_name /*name*/,
(duk_regconst_t) reg_temp /*value*/);
@ -6780,7 +6845,7 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
}
duk__emit_a_b_c(comp_ctx,
DUK_OP_DECLVAR,
DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
(duk_regconst_t) declvar_flags /*flags*/,
rc_name /*name*/,
(duk_regconst_t) 0 /*value*/);
@ -7073,12 +7138,12 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0); /* fast returns are always OK here */
if (reg_stmt_value >= 0) {
duk__emit_a_b(comp_ctx,
DUK_OP_RETURN,
DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
(duk_regconst_t) (DUK_BC_RETURN_FLAG_HAVE_RETVAL | DUK_BC_RETURN_FLAG_FAST) /*flags*/,
(duk_regconst_t) reg_stmt_value /*reg*/);
} else {
duk__emit_a_b(comp_ctx,
DUK_OP_RETURN,
DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
(duk_regconst_t) DUK_BC_RETURN_FLAG_FAST /*flags*/,
(duk_regconst_t) 0 /*reg(ignored)*/);
}

19
src/duk_js_executor.c

@ -2063,14 +2063,31 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
DUK_ASSERT(bcode + act->pc >= DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, fun));
DUK_ASSERT(bcode + act->pc < DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, fun));
DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld ins=0x%08lx, op=%ld, valstack_top=%ld/%ld --> %!I",
DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld --> %!I",
(long) act->pc,
(unsigned long) bcode[act->pc],
(long) DUK_DEC_OP(bcode[act->pc]),
(long) (thr->valstack_top - thr->valstack),
(long) (thr->valstack_end - thr->valstack),
(long) (fun ? fun->nregs : -1),
(duk_instr_t) bcode[act->pc]));
#if defined(DUK_USE_ASSERTIONS)
/* Quite heavy assert: check that valstack is in correctly
* initialized state. Improper shuffle instructions can
* write beyond valstack_end so this check catches them in
* the act.
*/
{
duk_tval *tv;
tv = thr->valstack_top;
while (tv != thr->valstack_end) {
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED_UNUSED(tv));
tv++;
}
}
#endif
ins = bcode[act->pc++];
/* Typing: use duk_small_(u)int_fast_t when decoding small

3
util/matrix_compile.py

@ -278,12 +278,13 @@ def create_matrix(fn_duk):
'-Os'
])
# Feature options in suitable chunks that can be subsetted arbitrarilt.
# Feature options in suitable chunks that can be subsetted arbitrarily.
duktape_options = Subset([
Select([ '-DDUK_OPT_NO_REFERENCE_COUNTING',
'-DDUK_OPT_NO_MARK_AND_SWEEP',
'-DDUK_OPT_GC_TORTURE' ]),
'-DDUK_OPT_SHUFFLE_TORTURE',
'-DDUK_OPT_NO_VOLUNTARY_GC',
'-DDUK_OPT_SEGFAULT_ON_PANIC',
'-DDUK_OPT_DPRINT_COLORS',

Loading…
Cancel
Save