4 * Parses an input string and generates a function template result.
5 * Compilation may happen in multiple contexts (global code, eval
6 * code, function code).
8 * The parser uses a traditional top-down recursive parsing for the
9 * statement level, and an operator precedence based top-down approach
10 * for the expression level. The attempt is to minimize the C stack
11 * depth. Bytecode is generated directly without an intermediate
12 * representation (tree), at the cost of needing two passes over each
15 * The top-down recursive parser functions are named "duk__parse_XXX".
17 * Recursion limits are in key functions to prevent arbitrary C recursion:
18 * function body parsing, statement parsing, and expression parsing.
20 * See doc/compiler.rst for discussion on the design.
24 * - duk_regconst_t: unsigned, no marker value for "none"
25 * - duk_reg_t: signed, < 0 = none
26 * - PC values: duk_int_t, negative values used as markers
29 #include "duk_internal.h"
31 /* if highest bit of a register number is set, it refers to a constant instead */
32 #define DUK__CONST_MARKER DUK_JS_CONST_MARKER
34 /* for array and object literals */
35 #define DUK__MAX_ARRAY_INIT_VALUES 20
36 #define DUK__MAX_OBJECT_INIT_PAIRS 10
38 /* XXX: hack, remove when const lookup is not O(n) */
39 #define DUK__GETCONST_MAX_CONSTS_CHECK 256
41 /* These limits are based on bytecode limits. Max temps is limited
42 * by duk_hcompiledfunction nargs/nregs fields being 16 bits.
44 #define DUK__MAX_CONSTS DUK_BC_BC_MAX
45 #define DUK__MAX_FUNCS DUK_BC_BC_MAX
46 #define DUK__MAX_TEMPS 0xffffL
48 /* Initial bytecode size allocation. */
49 #define DUK__BC_INITIAL_INSTS 256
51 #define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \
52 DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
53 duk__recursion_increase((comp_ctx)); \
56 #define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \
57 DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
58 duk__recursion_decrease((comp_ctx)); \
61 /* Value stack slot limits: these are quite approximate right now, and
62 * because they overlap in control flow, some could be eliminated.
64 #define DUK__COMPILE_ENTRY_SLOTS 8
65 #define DUK__FUNCTION_INIT_REQUIRE_SLOTS 16
66 #define DUK__FUNCTION_BODY_REQUIRE_SLOTS 16
67 #define DUK__PARSE_STATEMENTS_SLOTS 16
68 #define DUK__PARSE_EXPR_SLOTS 16
70 /* Temporary structure used to pass a stack allocated region through
74 duk_small_uint_t flags
;
75 duk_compiler_ctx comp_ctx_alloc
;
76 duk_lexer_point lex_pt_alloc
;
77 } duk__compiler_stkstate
;
84 DUK_LOCAL_DECL
void duk__advance_helper(duk_compiler_ctx
*comp_ctx
, duk_small_int_t expect
);
85 DUK_LOCAL_DECL
void duk__advance_expect(duk_compiler_ctx
*comp_ctx
, duk_small_int_t expect
);
86 DUK_LOCAL_DECL
void duk__advance(duk_compiler_ctx
*ctx
);
88 /* function helpers */
89 DUK_LOCAL_DECL
void duk__init_func_valstack_slots(duk_compiler_ctx
*comp_ctx
);
90 DUK_LOCAL_DECL
void duk__reset_func_for_pass2(duk_compiler_ctx
*comp_ctx
);
91 DUK_LOCAL_DECL
void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx
*comp_ctx
, duk_reg_t
*out_stmt_value_reg
);
92 DUK_LOCAL_DECL
void duk__convert_to_func_template(duk_compiler_ctx
*comp_ctx
, duk_bool_t force_no_namebind
);
93 DUK_LOCAL_DECL duk_int_t
duk__cleanup_varmap(duk_compiler_ctx
*comp_ctx
);
96 DUK_LOCAL_DECL duk_int_t
duk__get_current_pc(duk_compiler_ctx
*comp_ctx
);
97 DUK_LOCAL_DECL duk_compiler_instr
*duk__get_instr_ptr(duk_compiler_ctx
*comp_ctx
, duk_int_t pc
);
98 DUK_LOCAL_DECL
void duk__emit(duk_compiler_ctx
*comp_ctx
, duk_instr_t ins
);
100 DUK_LOCAL_DECL
void duk__emit_op_only(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t op
);
102 DUK_LOCAL_DECL
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
);
103 DUK_LOCAL_DECL
void duk__emit_a_b(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t op_flags
, duk_regconst_t a
, duk_regconst_t b
);
105 DUK_LOCAL_DECL
void duk__emit_a(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t op_flags
, duk_regconst_t a
);
107 DUK_LOCAL_DECL
void duk__emit_a_bc(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t op_flags
, duk_regconst_t a
, duk_regconst_t bc
);
108 DUK_LOCAL_DECL
void duk__emit_abc(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t op
, duk_regconst_t abc
);
109 DUK_LOCAL_DECL
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
);
110 DUK_LOCAL_DECL
void duk__emit_extraop_b(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t extraop_flags
, duk_regconst_t b
);
111 DUK_LOCAL_DECL
void duk__emit_extraop_bc(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t extraop
, duk_regconst_t bc
);
112 DUK_LOCAL_DECL
void duk__emit_extraop_only(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t extraop_flags
);
113 DUK_LOCAL_DECL
void duk__emit_load_int32(duk_compiler_ctx
*comp_ctx
, duk_reg_t reg
, duk_int32_t val
);
114 DUK_LOCAL_DECL
void duk__emit_load_int32_noshuffle(duk_compiler_ctx
*comp_ctx
, duk_reg_t reg
, duk_int32_t val
);
115 DUK_LOCAL_DECL
void duk__emit_jump(duk_compiler_ctx
*comp_ctx
, duk_int_t target_pc
);
116 DUK_LOCAL_DECL duk_int_t
duk__emit_jump_empty(duk_compiler_ctx
*comp_ctx
);
117 DUK_LOCAL_DECL
void duk__insert_jump_entry(duk_compiler_ctx
*comp_ctx
, duk_int_t jump_pc
);
118 DUK_LOCAL_DECL
void duk__patch_jump(duk_compiler_ctx
*comp_ctx
, duk_int_t jump_pc
, duk_int_t target_pc
);
119 DUK_LOCAL_DECL
void duk__patch_jump_here(duk_compiler_ctx
*comp_ctx
, duk_int_t jump_pc
);
120 DUK_LOCAL_DECL
void duk__patch_trycatch(duk_compiler_ctx
*comp_ctx
, duk_int_t ldconst_pc
, duk_int_t trycatch_pc
, duk_regconst_t reg_catch
, duk_regconst_t const_varname
, duk_small_uint_t flags
);
121 DUK_LOCAL_DECL
void duk__emit_if_false_skip(duk_compiler_ctx
*comp_ctx
, duk_regconst_t regconst
);
122 DUK_LOCAL_DECL
void duk__emit_if_true_skip(duk_compiler_ctx
*comp_ctx
, duk_regconst_t regconst
);
123 DUK_LOCAL_DECL
void duk__emit_invalid(duk_compiler_ctx
*comp_ctx
);
125 /* ivalue/ispec helpers */
126 DUK_LOCAL_DECL
void duk__copy_ispec(duk_compiler_ctx
*comp_ctx
, duk_ispec
*src
, duk_ispec
*dst
);
127 DUK_LOCAL_DECL
void duk__copy_ivalue(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*src
, duk_ivalue
*dst
);
128 DUK_LOCAL_DECL duk_bool_t
duk__is_whole_get_int32(duk_double_t x
, duk_int32_t
*ival
);
129 DUK_LOCAL_DECL duk_reg_t
duk__alloctemps(duk_compiler_ctx
*comp_ctx
, duk_small_int_t num
);
130 DUK_LOCAL_DECL duk_reg_t
duk__alloctemp(duk_compiler_ctx
*comp_ctx
);
131 DUK_LOCAL_DECL
void duk__settemp_checkmax(duk_compiler_ctx
*comp_ctx
, duk_reg_t temp_next
);
132 DUK_LOCAL_DECL duk_regconst_t
duk__getconst(duk_compiler_ctx
*comp_ctx
);
134 duk_regconst_t
duk__ispec_toregconst_raw(duk_compiler_ctx
*comp_ctx
,
136 duk_reg_t forced_reg
,
137 duk_small_uint_t flags
);
138 DUK_LOCAL_DECL
void duk__ispec_toforcedreg(duk_compiler_ctx
*comp_ctx
, duk_ispec
*x
, duk_reg_t forced_reg
);
139 DUK_LOCAL_DECL
void duk__ivalue_toplain_raw(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
, duk_reg_t forced_reg
);
140 DUK_LOCAL_DECL
void duk__ivalue_toplain(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
);
141 DUK_LOCAL_DECL
void duk__ivalue_toplain_ignore(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
);
143 duk_regconst_t
duk__ivalue_toregconst_raw(duk_compiler_ctx
*comp_ctx
,
145 duk_reg_t forced_reg
,
146 duk_small_uint_t flags
);
147 DUK_LOCAL_DECL duk_reg_t
duk__ivalue_toreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
);
149 DUK_LOCAL_DECL duk_reg_t
duk__ivalue_totemp(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
);
151 DUK_LOCAL_DECL
void duk__ivalue_toforcedreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
, duk_int_t forced_reg
);
152 DUK_LOCAL_DECL duk_regconst_t
duk__ivalue_toregconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
);
153 DUK_LOCAL_DECL duk_regconst_t
duk__ivalue_totempconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
);
155 /* identifier handling */
156 DUK_LOCAL_DECL duk_reg_t
duk__lookup_active_register_binding(duk_compiler_ctx
*comp_ctx
);
157 DUK_LOCAL_DECL duk_bool_t
duk__lookup_lhs(duk_compiler_ctx
*ctx
, duk_reg_t
*out_reg_varbind
, duk_regconst_t
*out_rc_varname
);
160 DUK_LOCAL_DECL
void duk__add_label(duk_compiler_ctx
*comp_ctx
, duk_hstring
*h_label
, duk_int_t pc_label
, duk_int_t label_id
);
161 DUK_LOCAL_DECL
void duk__update_label_flags(duk_compiler_ctx
*comp_ctx
, duk_int_t label_id
, duk_small_uint_t flags
);
162 DUK_LOCAL_DECL
void duk__lookup_active_label(duk_compiler_ctx
*comp_ctx
, duk_hstring
*h_label
, duk_bool_t is_break
, duk_int_t
*out_label_id
, duk_int_t
*out_label_catch_depth
, duk_int_t
*out_label_pc
, duk_bool_t
*out_is_closest
);
163 DUK_LOCAL_DECL
void duk__reset_labels_to_length(duk_compiler_ctx
*comp_ctx
, duk_int_t len
);
165 /* top-down expression parser */
166 DUK_LOCAL_DECL
void duk__expr_nud(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
167 DUK_LOCAL_DECL
void duk__expr_led(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*left
, duk_ivalue
*res
);
168 DUK_LOCAL_DECL duk_small_uint_t
duk__expr_lbp(duk_compiler_ctx
*comp_ctx
);
169 DUK_LOCAL_DECL duk_bool_t
duk__expr_is_empty(duk_compiler_ctx
*comp_ctx
);
171 /* exprtop is the top level variant which resets nud/led counts */
172 DUK_LOCAL_DECL
void duk__expr(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
173 DUK_LOCAL_DECL
void duk__exprtop(duk_compiler_ctx
*ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
175 /* convenience helpers */
177 DUK_LOCAL_DECL duk_reg_t
duk__expr_toreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
180 DUK_LOCAL_DECL duk_reg_t
duk__expr_totemp(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
182 DUK_LOCAL_DECL
void duk__expr_toforcedreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
, duk_reg_t forced_reg
);
183 DUK_LOCAL_DECL duk_regconst_t
duk__expr_toregconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
185 DUK_LOCAL_DECL duk_regconst_t
duk__expr_totempconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
187 DUK_LOCAL_DECL
void duk__expr_toplain(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
188 DUK_LOCAL_DECL
void duk__expr_toplain_ignore(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
189 DUK_LOCAL_DECL duk_reg_t
duk__exprtop_toreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
191 DUK_LOCAL_DECL duk_reg_t
duk__exprtop_totemp(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
193 DUK_LOCAL_DECL
void duk__exprtop_toforcedreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
, duk_reg_t forced_reg
);
194 DUK_LOCAL_DECL duk_regconst_t
duk__exprtop_toregconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
196 DUK_LOCAL_DECL
void duk__exprtop_toplain_ignore(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
);
199 /* expression parsing helpers */
200 DUK_LOCAL_DECL duk_int_t
duk__parse_arguments(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
201 DUK_LOCAL_DECL
void duk__nud_array_literal(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
202 DUK_LOCAL_DECL
void duk__nud_object_literal(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
203 DUK_LOCAL_DECL duk_bool_t
duk__nud_object_literal_key_check(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t new_key_flags
);
205 /* statement parsing */
206 DUK_LOCAL_DECL
void duk__parse_var_decl(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t expr_flags
, duk_reg_t
*out_reg_varbind
, duk_regconst_t
*out_rc_varname
);
207 DUK_LOCAL_DECL
void duk__parse_var_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t expr_flags
);
208 DUK_LOCAL_DECL
void duk__parse_for_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_int_t pc_label_site
);
209 DUK_LOCAL_DECL
void duk__parse_switch_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_int_t pc_label_site
);
210 DUK_LOCAL_DECL
void duk__parse_if_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
211 DUK_LOCAL_DECL
void duk__parse_do_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_int_t pc_label_site
);
212 DUK_LOCAL_DECL
void duk__parse_while_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_int_t pc_label_site
);
213 DUK_LOCAL_DECL
void duk__parse_break_or_continue_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
214 DUK_LOCAL_DECL
void duk__parse_return_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
215 DUK_LOCAL_DECL
void duk__parse_throw_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
216 DUK_LOCAL_DECL
void duk__parse_try_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
217 DUK_LOCAL_DECL
void duk__parse_with_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
);
218 DUK_LOCAL_DECL
void duk__parse_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_bool_t allow_source_elem
);
219 DUK_LOCAL_DECL duk_int_t
duk__stmt_label_site(duk_compiler_ctx
*comp_ctx
, duk_int_t label_id
);
220 DUK_LOCAL_DECL
void duk__parse_stmts(duk_compiler_ctx
*comp_ctx
, duk_bool_t allow_source_elem
, duk_bool_t expect_eof
);
222 DUK_LOCAL_DECL
void duk__parse_func_body(duk_compiler_ctx
*comp_ctx
, duk_bool_t expect_eof
, duk_bool_t implicit_return_value
, duk_small_int_t expect_token
);
223 DUK_LOCAL_DECL
void duk__parse_func_formals(duk_compiler_ctx
*comp_ctx
);
224 DUK_LOCAL_DECL
void duk__parse_func_like_raw(duk_compiler_ctx
*comp_ctx
, duk_bool_t is_decl
, duk_bool_t is_setget
);
225 DUK_LOCAL_DECL duk_int_t
duk__parse_func_like_fnum(duk_compiler_ctx
*comp_ctx
, duk_bool_t is_decl
, duk_bool_t is_setget
);
228 * Parser control values for tokens. The token table is ordered by the
229 * DUK_TOK_XXX defines.
231 * The binding powers are for lbp() use (i.e. for use in led() context).
232 * Binding powers are positive for typing convenience, and bits at the
233 * top should be reserved for flags. Binding power step must be higher
234 * than 1 so that binding power "lbp - 1" can be used for right associative
235 * operators. Currently a step of 2 is used (which frees one more bit for
239 /* XXX: actually single step levels would work just fine, clean up */
241 /* binding power "levels" (see doc/compiler.rst) */
242 #define DUK__BP_INVALID 0 /* always terminates led() */
243 #define DUK__BP_EOF 2
244 #define DUK__BP_CLOSING 4 /* token closes expression, e.g. ')', ']' */
245 #define DUK__BP_FOR_EXPR DUK__BP_CLOSING /* bp to use when parsing a top level Expression */
246 #define DUK__BP_COMMA 6
247 #define DUK__BP_ASSIGNMENT 8
248 #define DUK__BP_CONDITIONAL 10
249 #define DUK__BP_LOR 12
250 #define DUK__BP_LAND 14
251 #define DUK__BP_BOR 16
252 #define DUK__BP_BXOR 18
253 #define DUK__BP_BAND 20
254 #define DUK__BP_EQUALITY 22
255 #define DUK__BP_RELATIONAL 24
256 #define DUK__BP_SHIFT 26
257 #define DUK__BP_ADDITIVE 28
258 #define DUK__BP_MULTIPLICATIVE 30
259 #define DUK__BP_POSTFIX 32
260 #define DUK__BP_CALL 34
261 #define DUK__BP_MEMBER 36
263 #define DUK__TOKEN_LBP_BP_MASK 0x1f
264 #define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */
265 #define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */
266 #define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* spare */
268 #define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
270 #define DUK__MK_LBP(bp) ((bp) >> 1) /* bp is assumed to be even */
271 #define DUK__MK_LBP_FLAGS(bp,flags) (((bp) >> 1) | (flags))
273 DUK_LOCAL
const duk_uint8_t duk__token_lbp
[] = {
274 DUK__MK_LBP(DUK__BP_EOF
), /* DUK_TOK_EOF */
275 DUK__MK_LBP_FLAGS(DUK__BP_INVALID
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_IDENTIFIER */
276 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_BREAK */
277 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_CASE */
278 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_CATCH */
279 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_CONTINUE */
280 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_DEBUGGER */
281 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_DEFAULT */
282 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_DELETE */
283 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_DO */
284 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_ELSE */
285 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_FINALLY */
286 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_FOR */
287 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_FUNCTION */
288 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_IF */
289 DUK__MK_LBP(DUK__BP_RELATIONAL
), /* DUK_TOK_IN */
290 DUK__MK_LBP(DUK__BP_RELATIONAL
), /* DUK_TOK_INSTANCEOF */
291 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_NEW */
292 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_RETURN */
293 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_SWITCH */
294 DUK__MK_LBP_FLAGS(DUK__BP_INVALID
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_THIS */
295 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_THROW */
296 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_TRY */
297 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_TYPEOF */
298 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_VAR */
299 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_CONST */
300 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_VOID */
301 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_WHILE */
302 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_WITH */
303 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_CLASS */
304 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_ENUM */
305 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_EXPORT */
306 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_EXTENDS */
307 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_IMPORT */
308 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_SUPER */
309 DUK__MK_LBP_FLAGS(DUK__BP_INVALID
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_NULL */
310 DUK__MK_LBP_FLAGS(DUK__BP_INVALID
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_TRUE */
311 DUK__MK_LBP_FLAGS(DUK__BP_INVALID
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_FALSE */
312 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_GET */
313 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_SET */
314 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_IMPLEMENTS */
315 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_INTERFACE */
316 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_LET */
317 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_PACKAGE */
318 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_PRIVATE */
319 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_PROTECTED */
320 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_PUBLIC */
321 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_STATIC */
322 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_YIELD */
323 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_LCURLY */
324 DUK__MK_LBP_FLAGS(DUK__BP_INVALID
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_RCURLY */
325 DUK__MK_LBP(DUK__BP_MEMBER
), /* DUK_TOK_LBRACKET */
326 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_RBRACKET */
327 DUK__MK_LBP(DUK__BP_CALL
), /* DUK_TOK_LPAREN */
328 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_RPAREN */
329 DUK__MK_LBP(DUK__BP_MEMBER
), /* DUK_TOK_PERIOD */
330 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_SEMICOLON */
331 DUK__MK_LBP(DUK__BP_COMMA
), /* DUK_TOK_COMMA */
332 DUK__MK_LBP(DUK__BP_RELATIONAL
), /* DUK_TOK_LT */
333 DUK__MK_LBP(DUK__BP_RELATIONAL
), /* DUK_TOK_GT */
334 DUK__MK_LBP(DUK__BP_RELATIONAL
), /* DUK_TOK_LE */
335 DUK__MK_LBP(DUK__BP_RELATIONAL
), /* DUK_TOK_GE */
336 DUK__MK_LBP(DUK__BP_EQUALITY
), /* DUK_TOK_EQ */
337 DUK__MK_LBP(DUK__BP_EQUALITY
), /* DUK_TOK_NEQ */
338 DUK__MK_LBP(DUK__BP_EQUALITY
), /* DUK_TOK_SEQ */
339 DUK__MK_LBP(DUK__BP_EQUALITY
), /* DUK_TOK_SNEQ */
340 DUK__MK_LBP(DUK__BP_ADDITIVE
), /* DUK_TOK_ADD */
341 DUK__MK_LBP(DUK__BP_ADDITIVE
), /* DUK_TOK_SUB */
342 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE
), /* DUK_TOK_MUL */
343 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE
), /* DUK_TOK_DIV */
344 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE
), /* DUK_TOK_MOD */
345 DUK__MK_LBP(DUK__BP_POSTFIX
), /* DUK_TOK_INCREMENT */
346 DUK__MK_LBP(DUK__BP_POSTFIX
), /* DUK_TOK_DECREMENT */
347 DUK__MK_LBP(DUK__BP_SHIFT
), /* DUK_TOK_ALSHIFT */
348 DUK__MK_LBP(DUK__BP_SHIFT
), /* DUK_TOK_ARSHIFT */
349 DUK__MK_LBP(DUK__BP_SHIFT
), /* DUK_TOK_RSHIFT */
350 DUK__MK_LBP(DUK__BP_BAND
), /* DUK_TOK_BAND */
351 DUK__MK_LBP(DUK__BP_BOR
), /* DUK_TOK_BOR */
352 DUK__MK_LBP(DUK__BP_BXOR
), /* DUK_TOK_BXOR */
353 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_LNOT */
354 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_BNOT */
355 DUK__MK_LBP(DUK__BP_LAND
), /* DUK_TOK_LAND */
356 DUK__MK_LBP(DUK__BP_LOR
), /* DUK_TOK_LOR */
357 DUK__MK_LBP(DUK__BP_CONDITIONAL
), /* DUK_TOK_QUESTION */
358 DUK__MK_LBP(DUK__BP_INVALID
), /* DUK_TOK_COLON */
359 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_EQUALSIGN */
360 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_ADD_EQ */
361 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_SUB_EQ */
362 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_MUL_EQ */
363 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_DIV_EQ */
364 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_MOD_EQ */
365 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_ALSHIFT_EQ */
366 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_ARSHIFT_EQ */
367 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_RSHIFT_EQ */
368 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_BAND_EQ */
369 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_BOR_EQ */
370 DUK__MK_LBP(DUK__BP_ASSIGNMENT
), /* DUK_TOK_BXOR_EQ */
371 DUK__MK_LBP_FLAGS(DUK__BP_INVALID
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_NUMBER */
372 DUK__MK_LBP_FLAGS(DUK__BP_INVALID
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_STRING */
373 DUK__MK_LBP_FLAGS(DUK__BP_INVALID
, DUK__TOKEN_LBP_FLAG_NO_REGEXP
), /* DUK_TOK_REGEXP */
380 DUK_LOCAL
void duk__recursion_increase(duk_compiler_ctx
*comp_ctx
) {
381 DUK_ASSERT(comp_ctx
!= NULL
);
382 DUK_ASSERT(comp_ctx
->recursion_depth
>= 0);
383 if (comp_ctx
->recursion_depth
>= comp_ctx
->recursion_limit
) {
384 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_COMPILER_RECURSION_LIMIT
);
386 comp_ctx
->recursion_depth
++;
389 DUK_LOCAL
void duk__recursion_decrease(duk_compiler_ctx
*comp_ctx
) {
390 DUK_ASSERT(comp_ctx
!= NULL
);
391 DUK_ASSERT(comp_ctx
->recursion_depth
> 0);
392 comp_ctx
->recursion_depth
--;
395 DUK_LOCAL duk_bool_t
duk__hstring_is_eval_or_arguments(duk_compiler_ctx
*comp_ctx
, duk_hstring
*h
) {
397 DUK_ASSERT(h
!= NULL
);
398 return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h
);
401 DUK_LOCAL duk_bool_t
duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx
*comp_ctx
, duk_hstring
*h
) {
402 DUK_ASSERT(h
!= NULL
);
403 return (comp_ctx
->curr_func
.is_strict
&&
404 DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h
));
408 * Parser duk__advance() token eating functions
411 /* XXX: valstack handling is awkward. Add a valstack helper which
412 * avoids dup():ing; valstack_copy(src, dst)?
415 DUK_LOCAL
void duk__advance_helper(duk_compiler_ctx
*comp_ctx
, duk_small_int_t expect
) {
416 duk_hthread
*thr
= comp_ctx
->thr
;
417 duk_context
*ctx
= (duk_context
*) thr
;
420 DUK_ASSERT(comp_ctx
->curr_token
.t
>= 0 && comp_ctx
->curr_token
.t
<= DUK_TOK_MAXVAL
); /* MAXVAL is inclusive */
423 * Use current token to decide whether a RegExp can follow.
425 * We can use either 't' or 't_nores'; the latter would not
426 * recognize keywords. Some keywords can be followed by a
427 * RegExp (e.g. "return"), so using 't' is better. This is
428 * not trivial, see doc/compiler.rst.
432 if (duk__token_lbp
[comp_ctx
->curr_token
.t
] & DUK__TOKEN_LBP_FLAG_NO_REGEXP
) {
435 if (comp_ctx
->curr_func
.reject_regexp_in_adv
) {
436 comp_ctx
->curr_func
.reject_regexp_in_adv
= 0;
440 if (expect
>= 0 && comp_ctx
->curr_token
.t
!= expect
) {
441 DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
442 (long) expect
, (long) comp_ctx
->curr_token
.t
));
443 DUK_ERROR_SYNTAX(thr
, DUK_STR_PARSE_ERROR
);
446 /* make current token the previous; need to fiddle with valstack "backing store" */
447 DUK_MEMCPY(&comp_ctx
->prev_token
, &comp_ctx
->curr_token
, sizeof(duk_token
));
448 duk_copy(ctx
, comp_ctx
->tok11_idx
, comp_ctx
->tok21_idx
);
449 duk_copy(ctx
, comp_ctx
->tok12_idx
, comp_ctx
->tok22_idx
);
451 /* parse new token */
452 duk_lexer_parse_js_input_element(&comp_ctx
->lex
,
453 &comp_ctx
->curr_token
,
454 comp_ctx
->curr_func
.is_strict
,
457 DUK_DDD(DUK_DDDPRINT("advance: curr: tok=%ld/%ld,%ld,term=%ld,%!T,%!T "
458 "prev: tok=%ld/%ld,%ld,term=%ld,%!T,%!T",
459 (long) comp_ctx
->curr_token
.t
,
460 (long) comp_ctx
->curr_token
.t_nores
,
461 (long) comp_ctx
->curr_token
.start_line
,
462 (long) comp_ctx
->curr_token
.lineterm
,
463 (duk_tval
*) duk_get_tval(ctx
, comp_ctx
->tok11_idx
),
464 (duk_tval
*) duk_get_tval(ctx
, comp_ctx
->tok12_idx
),
465 (long) comp_ctx
->prev_token
.t
,
466 (long) comp_ctx
->prev_token
.t_nores
,
467 (long) comp_ctx
->prev_token
.start_line
,
468 (long) comp_ctx
->prev_token
.lineterm
,
469 (duk_tval
*) duk_get_tval(ctx
, comp_ctx
->tok21_idx
),
470 (duk_tval
*) duk_get_tval(ctx
, comp_ctx
->tok22_idx
)));
473 /* advance, expecting current token to be a specific token; parse next token in regexp context */
474 DUK_LOCAL
void duk__advance_expect(duk_compiler_ctx
*comp_ctx
, duk_small_int_t expect
) {
475 duk__advance_helper(comp_ctx
, expect
);
478 /* advance, whatever the current token is; parse next token in regexp context */
479 DUK_LOCAL
void duk__advance(duk_compiler_ctx
*comp_ctx
) {
480 duk__advance_helper(comp_ctx
, -1);
484 * Helpers for duk_compiler_func.
487 /* init function state: inits valstack allocations */
488 DUK_LOCAL
void duk__init_func_valstack_slots(duk_compiler_ctx
*comp_ctx
) {
489 duk_compiler_func
*func
= &comp_ctx
->curr_func
;
490 duk_hthread
*thr
= comp_ctx
->thr
;
491 duk_context
*ctx
= (duk_context
*) thr
;
494 entry_top
= duk_get_top(ctx
);
496 DUK_MEMZERO(func
, sizeof(*func
)); /* intentional overlap with earlier memzero */
497 #ifdef DUK_USE_EXPLICIT_NULL_INIT
499 func
->h_consts
= NULL
;
500 func
->h_funcs
= NULL
;
501 func
->h_decls
= NULL
;
502 func
->h_labelnames
= NULL
;
503 func
->h_labelinfos
= NULL
;
504 func
->h_argnames
= NULL
;
505 func
->h_varmap
= NULL
;
508 duk_require_stack(ctx
, DUK__FUNCTION_INIT_REQUIRE_SLOTS
);
510 DUK_BW_INIT_PUSHBUF(thr
, &func
->bw_code
, DUK__BC_INITIAL_INSTS
* sizeof(duk_compiler_instr
));
511 /* code_idx = entry_top + 0 */
514 func
->consts_idx
= entry_top
+ 1;
515 func
->h_consts
= DUK_GET_HOBJECT_POSIDX(ctx
, entry_top
+ 1);
516 DUK_ASSERT(func
->h_consts
!= NULL
);
519 func
->funcs_idx
= entry_top
+ 2;
520 func
->h_funcs
= DUK_GET_HOBJECT_POSIDX(ctx
, entry_top
+ 2);
521 DUK_ASSERT(func
->h_funcs
!= NULL
);
522 DUK_ASSERT(func
->fnum_next
== 0);
525 func
->decls_idx
= entry_top
+ 3;
526 func
->h_decls
= DUK_GET_HOBJECT_POSIDX(ctx
, entry_top
+ 3);
527 DUK_ASSERT(func
->h_decls
!= NULL
);
530 func
->labelnames_idx
= entry_top
+ 4;
531 func
->h_labelnames
= DUK_GET_HOBJECT_POSIDX(ctx
, entry_top
+ 4);
532 DUK_ASSERT(func
->h_labelnames
!= NULL
);
534 duk_push_dynamic_buffer(ctx
, 0);
535 func
->labelinfos_idx
= entry_top
+ 5;
536 func
->h_labelinfos
= (duk_hbuffer_dynamic
*) duk_get_hbuffer(ctx
, entry_top
+ 5);
537 DUK_ASSERT(func
->h_labelinfos
!= NULL
);
538 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func
->h_labelinfos
) && !DUK_HBUFFER_HAS_EXTERNAL(func
->h_labelinfos
));
541 func
->argnames_idx
= entry_top
+ 6;
542 func
->h_argnames
= DUK_GET_HOBJECT_POSIDX(ctx
, entry_top
+ 6);
543 DUK_ASSERT(func
->h_argnames
!= NULL
);
545 duk_push_object_internal(ctx
);
546 func
->varmap_idx
= entry_top
+ 7;
547 func
->h_varmap
= DUK_GET_HOBJECT_POSIDX(ctx
, entry_top
+ 7);
548 DUK_ASSERT(func
->h_varmap
!= NULL
);
551 /* reset function state (prepare for pass 2) */
552 DUK_LOCAL
void duk__reset_func_for_pass2(duk_compiler_ctx
*comp_ctx
) {
553 duk_compiler_func
*func
= &comp_ctx
->curr_func
;
554 duk_hthread
*thr
= comp_ctx
->thr
;
555 duk_context
*ctx
= (duk_context
*) thr
;
557 /* reset bytecode buffer but keep current size; pass 2 will
558 * require same amount or more.
560 DUK_BW_RESET_SIZE(thr
, &func
->bw_code
);
562 duk_hobject_set_length_zero(thr
, func
->h_consts
);
563 /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
565 /* duk_hobject_set_length_zero(thr, func->h_funcs); */
566 duk_hobject_set_length_zero(thr
, func
->h_labelnames
);
567 duk_hbuffer_reset(thr
, func
->h_labelinfos
);
568 /* keep func->h_argnames; it is fixed for all passes */
570 /* truncated in case pass 3 needed */
571 duk_push_object_internal(ctx
);
572 duk_replace(ctx
, func
->varmap_idx
);
573 func
->h_varmap
= DUK_GET_HOBJECT_POSIDX(ctx
, func
->varmap_idx
);
574 DUK_ASSERT(func
->h_varmap
!= NULL
);
577 /* cleanup varmap from any null entries, compact it, etc; returns number
578 * of final entries after cleanup.
580 DUK_LOCAL duk_int_t
duk__cleanup_varmap(duk_compiler_ctx
*comp_ctx
) {
581 duk_hthread
*thr
= comp_ctx
->thr
;
582 duk_context
*ctx
= (duk_context
*) thr
;
583 duk_hobject
*h_varmap
;
586 duk_uint32_t i
, e_next
;
591 h_varmap
= DUK_GET_HOBJECT_NEGIDX(ctx
, -1);
592 DUK_ASSERT(h_varmap
!= NULL
);
595 e_next
= DUK_HOBJECT_GET_ENEXT(h_varmap
);
596 for (i
= 0; i
< e_next
; i
++) {
597 h_key
= DUK_HOBJECT_E_GET_KEY(thr
->heap
, h_varmap
, i
);
602 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr
->heap
, h_varmap
, i
));
604 /* The entries can either be register numbers or 'null' values.
605 * Thus, no need to DECREF them and get side effects. DECREF'ing
606 * the keys (strings) can cause memory to be freed but no side
607 * effects as strings don't have finalizers. This is why we can
608 * rely on the object properties not changing from underneath us.
611 tv
= DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr
->heap
, h_varmap
, i
);
612 if (!DUK_TVAL_IS_NUMBER(tv
)) {
613 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv
));
614 DUK_HOBJECT_E_SET_KEY(thr
->heap
, h_varmap
, i
, NULL
);
615 DUK_HSTRING_DECREF(thr
, h_key
);
616 /* when key is NULL, value is garbage so no need to set */
622 duk_compact(ctx
, -1);
627 /* convert duk_compiler_func into a function template, leaving the result
630 /* XXX: awkward and bloated asm -- use faster internal accesses */
631 DUK_LOCAL
void duk__convert_to_func_template(duk_compiler_ctx
*comp_ctx
, duk_bool_t force_no_namebind
) {
632 duk_compiler_func
*func
= &comp_ctx
->curr_func
;
633 duk_hthread
*thr
= comp_ctx
->thr
;
634 duk_context
*ctx
= (duk_context
*) thr
;
635 duk_hcompiledfunction
*h_res
;
636 duk_hbuffer_fixed
*h_data
;
637 duk_size_t consts_count
;
638 duk_size_t funcs_count
;
639 duk_size_t code_count
;
640 duk_size_t code_size
;
641 duk_size_t data_size
;
644 duk_hobject
**p_func
;
645 duk_instr_t
*p_instr
;
646 duk_compiler_instr
*q_instr
;
649 DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template"));
652 * Push result object and init its flags
655 /* Valstack should suffice here, required on function valstack init */
657 (void) duk_push_compiledfunction(ctx
);
658 h_res
= (duk_hcompiledfunction
*) DUK_GET_HOBJECT_NEGIDX(ctx
, -1); /* XXX: specific getter */
659 DUK_ASSERT(h_res
!= NULL
);
661 if (func
->is_function
) {
662 DUK_DDD(DUK_DDDPRINT("function -> set NEWENV"));
663 DUK_HOBJECT_SET_NEWENV((duk_hobject
*) h_res
);
665 if (!func
->is_arguments_shadowed
) {
666 /* arguments object would be accessible; note that shadowing
667 * bindings are arguments or function declarations, neither
668 * of which are deletable, so this is safe.
671 if (func
->id_access_arguments
|| func
->may_direct_eval
) {
672 DUK_DDD(DUK_DDDPRINT("function may access 'arguments' object directly or "
673 "indirectly -> set CREATEARGS"));
674 DUK_HOBJECT_SET_CREATEARGS((duk_hobject
*) h_res
);
677 } else if (func
->is_eval
&& func
->is_strict
) {
678 DUK_DDD(DUK_DDDPRINT("strict eval code -> set NEWENV"));
679 DUK_HOBJECT_SET_NEWENV((duk_hobject
*) h_res
);
681 /* non-strict eval: env is caller's env or global env (direct vs. indirect call)
682 * global code: env is is global env
684 DUK_DDD(DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV"));
685 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject
*) h_res
));
688 if (func
->is_function
&& !func
->is_decl
&& func
->h_name
!= NULL
&& !force_no_namebind
) {
689 /* Object literal set/get functions have a name (property
690 * name) but must not have a lexical name binding, see
691 * test-bug-getset-func-name.js.
693 DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING"));
694 DUK_HOBJECT_SET_NAMEBINDING((duk_hobject
*) h_res
);
697 if (func
->is_strict
) {
698 DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT"));
699 DUK_HOBJECT_SET_STRICT((duk_hobject
*) h_res
);
702 if (func
->is_notail
) {
703 DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL"));
704 DUK_HOBJECT_SET_NOTAIL((duk_hobject
*) h_res
);
708 * Build function fixed size 'data' buffer, which contains bytecode,
709 * constants, and inner function references.
711 * During the building phase 'data' is reachable but incomplete.
712 * Only incref's occur during building (no refzero or GC happens),
713 * so the building process is atomic.
716 consts_count
= duk_hobject_get_length(thr
, func
->h_consts
);
717 funcs_count
= duk_hobject_get_length(thr
, func
->h_funcs
) / 3;
718 code_count
= DUK_BW_GET_SIZE(thr
, &func
->bw_code
) / sizeof(duk_compiler_instr
);
719 code_size
= code_count
* sizeof(duk_instr_t
);
721 data_size
= consts_count
* sizeof(duk_tval
) +
722 funcs_count
* sizeof(duk_hobject
*) +
725 DUK_DDD(DUK_DDDPRINT("consts_count=%ld, funcs_count=%ld, code_size=%ld -> "
726 "data_size=%ld*%ld + %ld*%ld + %ld = %ld",
727 (long) consts_count
, (long) funcs_count
, (long) code_size
,
728 (long) consts_count
, (long) sizeof(duk_tval
),
729 (long) funcs_count
, (long) sizeof(duk_hobject
*),
730 (long) code_size
, (long) data_size
));
732 duk_push_fixed_buffer(ctx
, data_size
);
733 h_data
= (duk_hbuffer_fixed
*) duk_get_hbuffer(ctx
, -1);
734 DUK_ASSERT(h_data
!= NULL
);
736 DUK_HCOMPILEDFUNCTION_SET_DATA(thr
->heap
, h_res
, (duk_hbuffer
*) h_data
);
737 DUK_HEAPHDR_INCREF(thr
, h_data
);
739 p_const
= (duk_tval
*) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr
->heap
, h_data
);
740 for (i
= 0; i
< consts_count
; i
++) {
741 DUK_ASSERT(i
<= DUK_UARRIDX_MAX
); /* const limits */
742 tv
= duk_hobject_find_existing_array_entry_tval_ptr(thr
->heap
, func
->h_consts
, (duk_uarridx_t
) i
);
743 DUK_ASSERT(tv
!= NULL
);
744 DUK_TVAL_SET_TVAL(p_const
, tv
);
746 DUK_TVAL_INCREF(thr
, tv
); /* may be a string constant */
748 DUK_DDD(DUK_DDDPRINT("constant: %!T", (duk_tval
*) tv
));
751 p_func
= (duk_hobject
**) p_const
;
752 DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr
->heap
, h_res
, p_func
);
753 for (i
= 0; i
< funcs_count
; i
++) {
755 DUK_ASSERT(i
* 3 <= DUK_UARRIDX_MAX
); /* func limits */
756 tv
= duk_hobject_find_existing_array_entry_tval_ptr(thr
->heap
, func
->h_funcs
, (duk_uarridx_t
) (i
* 3));
757 DUK_ASSERT(tv
!= NULL
);
758 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv
));
759 h
= DUK_TVAL_GET_OBJECT(tv
);
760 DUK_ASSERT(h
!= NULL
);
761 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(h
));
763 DUK_HOBJECT_INCREF(thr
, h
);
765 DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO",
766 (void *) h
, (duk_heaphdr
*) h
));
769 p_instr
= (duk_instr_t
*) p_func
;
770 DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr
->heap
, h_res
, p_instr
);
772 /* copy bytecode instructions one at a time */
773 q_instr
= (duk_compiler_instr
*) (void *) DUK_BW_GET_BASEPTR(thr
, &func
->bw_code
);
774 for (i
= 0; i
< code_count
; i
++) {
775 p_instr
[i
] = q_instr
[i
].ins
;
777 /* Note: 'q_instr' is still used below */
779 DUK_ASSERT((duk_uint8_t
*) (p_instr
+ code_count
) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr
->heap
, h_data
) + data_size
);
781 duk_pop(ctx
); /* 'data' (and everything in it) is reachable through h_res now */
784 * Init object properties
786 * Properties should be added in decreasing order of access frequency.
787 * (Not very critical for function templates.)
790 DUK_DDD(DUK_DDDPRINT("init function properties"));
794 /* _Varmap: omitted if function is guaranteed not to do slow path identifier
795 * accesses or if it would turn out to be empty of actual register mappings
796 * after a cleanup. When debugging is enabled, we always need the varmap to
797 * be able to lookup variables at any point.
799 #if defined(DUK_USE_DEBUGGER_SUPPORT)
802 if (func
->id_access_slow
|| /* directly uses slow accesses */
803 func
->may_direct_eval
|| /* may indirectly slow access through a direct eval */
804 funcs_count
> 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
807 duk_dup(ctx
, func
->varmap_idx
);
808 num_used
= duk__cleanup_varmap(comp_ctx
);
809 DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)",
810 (duk_tval
*) duk_get_tval(ctx
, -1), (long) num_used
));
813 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_VARMAP
, DUK_PROPDESC_FLAGS_NONE
);
815 DUK_DDD(DUK_DDDPRINT("varmap is empty after cleanup -> no need to add"));
820 /* _Formals: omitted if function is guaranteed not to need a (non-strict) arguments object */
822 /* XXX: Add a proper condition. If formals list is omitted, recheck
823 * handling for 'length' in duk_js_push_closure(); it currently relies
824 * on _Formals being set. Removal may need to be conditional to debugging
825 * being enabled/disabled too.
827 duk_dup(ctx
, func
->argnames_idx
);
828 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_FORMALS
, DUK_PROPDESC_FLAGS_NONE
);
833 duk_push_hstring(ctx
, func
->h_name
);
834 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_NAME
, DUK_PROPDESC_FLAGS_NONE
);
838 #if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
840 /* XXX: Currently function source code is not stored, as it is not
841 * required by the standard. Source code should not be stored by
842 * default (user should enable it explicitly), and the source should
843 * probably be compressed with a trivial text compressor; average
844 * compression of 20-30% is quite easy to achieve even with a trivial
845 * compressor (RLE + backwards lookup).
847 * Debugging needs source code to be useful: sometimes input code is
848 * not found in files as it may be generated and then eval()'d, given
849 * by dynamic C code, etc.
853 * - Need tokenizer indices for start and end to substring
854 * - Always normalize function declaration part?
855 * - If we keep _Formals, only need to store body
859 * For global or eval code this is straightforward. For functions
860 * created with the Function constructor we only get the source for
861 * the body and must manufacture the "function ..." part.
863 * For instance, for constructed functions (v8):
865 * > a = new Function("foo", "bar", "print(foo)");
868 * 'function anonymous(foo,bar) {\nprint(foo)\n}'
870 * Similarly for e.g. getters (v8):
872 * > x = { get a(foo,bar) { print(foo); } }
874 * > Object.getOwnPropertyDescriptor(x, 'a').get.toString()
875 * 'function a(foo,bar) { print(foo); }'
879 duk_push_string(ctx
, "XXX");
880 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_SOURCE
, DUK_PROPDESC_FLAGS_NONE
);
883 #endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
886 #if defined(DUK_USE_PC2LINE)
889 * Size-optimized pc->line mapping.
892 DUK_ASSERT(code_count
<= DUK_COMPILER_MAX_BYTECODE_LENGTH
);
893 duk_hobject_pc2line_pack(thr
, q_instr
, (duk_uint_fast32_t
) code_count
); /* -> pushes fixed buffer */
894 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_PC2LINE
, DUK_PROPDESC_FLAGS_NONE
);
896 /* XXX: if assertions enabled, walk through all valid PCs
897 * and check line mapping.
900 #endif /* DUK_USE_PC2LINE */
903 if (comp_ctx
->h_filename
) {
905 * Source filename (or equivalent), for identifying thrown errors.
908 duk_push_hstring(ctx
, comp_ctx
->h_filename
);
909 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_FILE_NAME
, DUK_PROPDESC_FLAGS_NONE
);
913 * Init remaining result fields
915 * 'nregs' controls how large a register frame is allocated.
917 * 'nargs' controls how many formal arguments are written to registers:
918 * r0, ... r(nargs-1). The remaining registers are initialized to
922 DUK_ASSERT(func
->temp_max
>= 0);
923 h_res
->nregs
= (duk_uint16_t
) func
->temp_max
;
924 h_res
->nargs
= (duk_uint16_t
) duk_hobject_get_length(thr
, func
->h_argnames
);
925 DUK_ASSERT(h_res
->nregs
>= h_res
->nargs
); /* pass2 allocation handles this */
926 #if defined(DUK_USE_DEBUGGER_SUPPORT)
927 h_res
->start_line
= (duk_uint32_t
) func
->min_line
;
928 h_res
->end_line
= (duk_uint32_t
) func
->max_line
;
931 DUK_DD(DUK_DDPRINT("converted function: %!ixT",
932 (duk_tval
*) duk_get_tval(ctx
, -1)));
935 * Compact the function template.
938 duk_compact(ctx
, -1);
944 #ifdef DUK_USE_DDDPRINT
946 duk_hcompiledfunction
*h
;
947 duk_instr_t
*p
, *p_start
, *p_end
;
949 h
= (duk_hcompiledfunction
*) duk_get_hobject(ctx
, -1);
950 p_start
= (duk_instr_t
*) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr
->heap
, h
);
951 p_end
= (duk_instr_t
*) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr
->heap
, h
);
955 DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I ; 0x%08lx op=%ld (%!C) a=%ld b=%ld c=%ld",
956 (long) (p
- p_start
),
958 (unsigned long) (*p
),
959 (long) DUK_DEC_OP(*p
),
960 (long) DUK_DEC_OP(*p
),
961 (long) DUK_DEC_A(*p
),
962 (long) DUK_DEC_B(*p
),
963 (long) DUK_DEC_C(*p
)));
971 * Code emission helpers
973 * Some emission helpers understand the range of target and source reg/const
974 * values and automatically emit shuffling code if necessary. This is the
975 * case when the slot in question (A, B, C) is used in the standard way and
976 * for opcodes the emission helpers explicitly understand (like DUK_OP_CALL).
978 * The standard way is that:
979 * - slot A is a target register
980 * - slot B is a source register/constant
981 * - slot C is a source register/constant
983 * If a slot is used in a non-standard way the caller must indicate this
984 * somehow. If a slot is used as a target instead of a source (or vice
985 * versa), this can be indicated with a flag to trigger proper shuffling
986 * (e.g. DUK__EMIT_FLAG_B_IS_TARGET). If the value in the slot is not
987 * register/const related at all, the caller must ensure that the raw value
988 * fits into the corresponding slot so as to not trigger shuffling. The
989 * caller must set a "no shuffle" flag to ensure compilation fails if
990 * shuffling were to be triggered because of an internal error.
992 * For slots B and C the raw slot size is 9 bits but one bit is reserved for
993 * the reg/const indicator. To use the full 9-bit range for a raw value,
994 * shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag.
995 * Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots.
997 * There is call handling specific understanding in the A-B-C emitter to
998 * convert call setup and call instructions into indirect ones if necessary.
1001 /* Code emission flags, passed in the 'opcode' field. Opcode + flags
1002 * fit into 16 bits for now, so use duk_small_uint.t.
1004 #define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8)
1005 #define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9)
1006 #define DUK__EMIT_FLAG_NO_SHUFFLE_C (1 << 10)
1007 #define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */
1008 #define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */
1009 #define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */
1010 #define DUK__EMIT_FLAG_B_IS_TARGETSOURCE (1 << 14) /* slot B is both a target and a source (used by extraops like DUK_EXTRAOP_INSTOF */
1011 #define DUK__EMIT_FLAG_RESERVE_JUMPSLOT (1 << 15) /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */
1013 /* XXX: clarify on when and where DUK__CONST_MARKER is allowed */
1014 /* XXX: opcode specific assertions on when consts are allowed */
1016 /* XXX: macro smaller than call? */
1017 DUK_LOCAL duk_int_t
duk__get_current_pc(duk_compiler_ctx
*comp_ctx
) {
1018 duk_compiler_func
*func
;
1019 func
= &comp_ctx
->curr_func
;
1020 return (duk_int_t
) (DUK_BW_GET_SIZE(comp_ctx
->thr
, &func
->bw_code
) / sizeof(duk_compiler_instr
));
1023 DUK_LOCAL duk_compiler_instr
*duk__get_instr_ptr(duk_compiler_ctx
*comp_ctx
, duk_int_t pc
) {
1024 DUK_ASSERT(pc
>= 0);
1025 DUK_ASSERT((duk_size_t
) pc
< (duk_size_t
) (DUK_BW_GET_SIZE(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
) / sizeof(duk_compiler_instr
)));
1026 return ((duk_compiler_instr
*) (void *) DUK_BW_GET_BASEPTR(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
)) + pc
;
1029 /* emit instruction; could return PC but that's not needed in the majority
1032 DUK_LOCAL
void duk__emit(duk_compiler_ctx
*comp_ctx
, duk_instr_t ins
) {
1033 #if defined(DUK_USE_PC2LINE)
1036 duk_compiler_instr
*instr
;
1038 DUK_DDD(DUK_DDDPRINT("duk__emit: 0x%08lx curr_token.start_line=%ld prev_token.start_line=%ld pc=%ld --> %!I",
1039 (unsigned long) ins
,
1040 (long) comp_ctx
->curr_token
.start_line
,
1041 (long) comp_ctx
->prev_token
.start_line
,
1042 (long) duk__get_current_pc(comp_ctx
),
1043 (duk_instr_t
) ins
));
1045 instr
= (duk_compiler_instr
*) (void *) DUK_BW_ENSURE_GETPTR(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
, sizeof(duk_compiler_instr
));
1046 DUK_BW_ADD_PTR(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
, sizeof(duk_compiler_instr
));
1048 #if defined(DUK_USE_PC2LINE)
1049 /* The line number tracking is a bit inconsistent right now, which
1050 * affects debugger accuracy. Mostly call sites emit opcodes when
1051 * they have parsed a token (say a terminating semicolon) and called
1052 * duk__advance(). In this case the line number of the previous
1053 * token is the most accurate one (except in prologue where
1054 * prev_token.start_line is 0). This is probably not 100% correct
1057 /* approximation, close enough */
1058 line
= comp_ctx
->prev_token
.start_line
;
1060 line
= comp_ctx
->curr_token
.start_line
;
1065 #if defined(DUK_USE_PC2LINE)
1068 #if defined(DUK_USE_DEBUGGER_SUPPORT)
1069 if (line
< comp_ctx
->curr_func
.min_line
) {
1070 comp_ctx
->curr_func
.min_line
= line
;
1072 if (line
> comp_ctx
->curr_func
.max_line
) {
1073 comp_ctx
->curr_func
.max_line
= line
;
1077 /* Limit checks for bytecode byte size and line number. */
1078 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
) > DUK_USE_ESBC_MAX_BYTES
)) {
1081 #if defined(DUK_USE_PC2LINE) && defined(DUK_USE_ESBC_LIMITS)
1082 #if defined(DUK_USE_BUFLEN16)
1083 /* Buffer length is bounded to 0xffff automatically, avoid compile warning. */
1084 if (DUK_UNLIKELY(line
> DUK_USE_ESBC_MAX_LINENUMBER
)) {
1088 if (DUK_UNLIKELY(line
> DUK_USE_ESBC_MAX_LINENUMBER
)) {
1097 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_BYTECODE_LIMIT
);
1100 /* Update function min/max line from current token. Needed to improve
1101 * function line range information for debugging, so that e.g. opening
1102 * curly brace is covered by line range even when no opcodes are emitted
1103 * for the line containing the brace.
1105 DUK_LOCAL
void duk__update_lineinfo_currtoken(duk_compiler_ctx
*comp_ctx
) {
1106 #if defined(DUK_USE_DEBUGGER_SUPPORT)
1109 line
= comp_ctx
->curr_token
.start_line
;
1113 if (line
< comp_ctx
->curr_func
.min_line
) {
1114 comp_ctx
->curr_func
.min_line
= line
;
1116 if (line
> comp_ctx
->curr_func
.max_line
) {
1117 comp_ctx
->curr_func
.max_line
= line
;
1120 DUK_UNREF(comp_ctx
);
1125 DUK_LOCAL
void duk__emit_op_only(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t op
) {
1126 duk__emit(comp_ctx
, DUK_ENC_OP_ABC(op
, 0));
1130 /* Important main primitive. */
1131 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
) {
1132 duk_instr_t ins
= 0;
1133 duk_int_t a_out
= -1;
1134 duk_int_t b_out
= -1;
1135 duk_int_t c_out
= -1;
1138 DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
1139 (unsigned long) op_flags
, (long) a
, (long) b
, (long) c
));
1141 /* We could rely on max temp/const checks: if they don't exceed BC
1142 * limit, nothing here can either (just asserts would be enough).
1143 * Currently we check for the limits, which provides additional
1144 * protection against creating invalid bytecode due to compiler
1148 DUK_ASSERT_DISABLE((op_flags
& 0xff) >= DUK_BC_OP_MIN
); /* unsigned */
1149 DUK_ASSERT((op_flags
& 0xff) <= DUK_BC_OP_MAX
);
1151 /* Input shuffling happens before the actual operation, while output
1152 * shuffling happens afterwards. Output shuffling decisions are still
1153 * made at the same time to reduce branch clutter; output shuffle decisions
1154 * are recorded into X_out variables.
1159 #if defined(DUK_USE_SHUFFLE_TORTURE)
1160 if (a
<= DUK_BC_A_MAX
&& (op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_A
)) {
1162 if (a
<= DUK_BC_A_MAX
) {
1165 } else if (op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_A
) {
1166 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld", (long) a
));
1167 goto error_outofregs
;
1168 } else if (a
<= DUK_BC_BC_MAX
) {
1169 comp_ctx
->curr_func
.needs_shuffle
= 1;
1170 tmp
= comp_ctx
->curr_func
.shuffle1
;
1171 if (op_flags
& DUK__EMIT_FLAG_A_IS_SOURCE
) {
1172 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_LDREG
, tmp
, a
));
1174 duk_small_int_t op
= op_flags
& 0xff;
1175 if (op
== DUK_OP_CSVAR
|| op
== DUK_OP_CSREG
|| op
== DUK_OP_CSPROP
) {
1176 /* Special handling for call setup instructions. The target
1177 * is expressed indirectly, but there is no output shuffling.
1179 DUK_ASSERT((op_flags
& DUK__EMIT_FLAG_A_IS_SOURCE
) == 0);
1180 duk__emit_load_int32_noshuffle(comp_ctx
, tmp
, a
);
1181 DUK_ASSERT(DUK_OP_CSVARI
== DUK_OP_CSVAR
+ 1);
1182 DUK_ASSERT(DUK_OP_CSREGI
== DUK_OP_CSREG
+ 1);
1183 DUK_ASSERT(DUK_OP_CSPROPI
== DUK_OP_CSPROP
+ 1);
1184 op_flags
++; /* indirect opcode follows direct */
1186 /* Output shuffle needed after main operation */
1192 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %ld", (long) a
));
1193 goto error_outofregs
;
1198 if (b
& DUK__CONST_MARKER
) {
1199 DUK_ASSERT((op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_B
) == 0);
1200 DUK_ASSERT((op_flags
& DUK__EMIT_FLAG_B_IS_TARGET
) == 0);
1201 DUK_ASSERT((op_flags
& 0xff) != DUK_OP_CALL
);
1202 DUK_ASSERT((op_flags
& 0xff) != DUK_OP_NEW
);
1203 b
= b
& ~DUK__CONST_MARKER
;
1204 #if defined(DUK_USE_SHUFFLE_TORTURE)
1209 ins
|= DUK_ENC_OP_A_B_C(0, 0, 0x100, 0); /* const flag for B */
1210 } else if (b
<= DUK_BC_BC_MAX
) {
1211 comp_ctx
->curr_func
.needs_shuffle
= 1;
1212 tmp
= comp_ctx
->curr_func
.shuffle2
;
1213 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_LDCONST
, tmp
, b
));
1216 DUK_D(DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %ld", (long) b
));
1217 goto error_outofregs
;
1220 #if defined(DUK_USE_SHUFFLE_TORTURE)
1221 if (b
<= 0xff && (op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_B
)) {
1226 } else if (op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_B
) {
1227 if (b
> DUK_BC_B_MAX
) {
1228 /* Note: 0xff != DUK_BC_B_MAX */
1229 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %ld", (long) b
));
1230 goto error_outofregs
;
1232 } else if (b
<= DUK_BC_BC_MAX
) {
1233 comp_ctx
->curr_func
.needs_shuffle
= 1;
1234 tmp
= comp_ctx
->curr_func
.shuffle2
;
1235 if (op_flags
& DUK__EMIT_FLAG_B_IS_TARGET
) {
1236 /* Output shuffle needed after main operation */
1239 if (!(op_flags
& DUK__EMIT_FLAG_B_IS_TARGET
) || (op_flags
& DUK__EMIT_FLAG_B_IS_TARGETSOURCE
)) {
1240 duk_small_int_t op
= op_flags
& 0xff;
1241 if (op
== DUK_OP_CALL
|| op
== DUK_OP_NEW
||
1242 op
== DUK_OP_MPUTOBJ
|| op
== DUK_OP_MPUTARR
) {
1243 /* Special handling for CALL/NEW/MPUTOBJ/MPUTARR shuffling.
1244 * For each, slot B identifies the first register of a range
1245 * of registers, so normal shuffling won't work. Instead,
1246 * an indirect version of the opcode is used.
1248 DUK_ASSERT((op_flags
& DUK__EMIT_FLAG_B_IS_TARGET
) == 0);
1249 duk__emit_load_int32_noshuffle(comp_ctx
, tmp
, b
);
1250 DUK_ASSERT(DUK_OP_CALLI
== DUK_OP_CALL
+ 1);
1251 DUK_ASSERT(DUK_OP_NEWI
== DUK_OP_NEW
+ 1);
1252 DUK_ASSERT(DUK_OP_MPUTOBJI
== DUK_OP_MPUTOBJ
+ 1);
1253 DUK_ASSERT(DUK_OP_MPUTARRI
== DUK_OP_MPUTARR
+ 1);
1254 op_flags
++; /* indirect opcode follows direct */
1256 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_LDREG
, tmp
, b
));
1261 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %ld", (long) b
));
1262 goto error_outofregs
;
1268 if (c
& DUK__CONST_MARKER
) {
1269 DUK_ASSERT((op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_C
) == 0);
1270 DUK_ASSERT((op_flags
& DUK__EMIT_FLAG_C_IS_TARGET
) == 0);
1271 c
= c
& ~DUK__CONST_MARKER
;
1272 #if defined(DUK_USE_SHUFFLE_TORTURE)
1277 ins
|= DUK_ENC_OP_A_B_C(0, 0, 0, 0x100); /* const flag for C */
1278 } else if (c
<= DUK_BC_BC_MAX
) {
1279 comp_ctx
->curr_func
.needs_shuffle
= 1;
1280 tmp
= comp_ctx
->curr_func
.shuffle3
;
1281 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_LDCONST
, tmp
, c
));
1284 DUK_D(DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %ld", (long) c
));
1285 goto error_outofregs
;
1288 #if defined(DUK_USE_SHUFFLE_TORTURE)
1289 if (c
<= 0xff && (op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_C
)) {
1294 } else if (op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_C
) {
1295 if (c
> DUK_BC_C_MAX
) {
1296 /* Note: 0xff != DUK_BC_C_MAX */
1297 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %ld", (long) c
));
1298 goto error_outofregs
;
1300 } else if (c
<= DUK_BC_BC_MAX
) {
1301 comp_ctx
->curr_func
.needs_shuffle
= 1;
1302 tmp
= comp_ctx
->curr_func
.shuffle3
;
1303 if (op_flags
& DUK__EMIT_FLAG_C_IS_TARGET
) {
1304 /* Output shuffle needed after main operation */
1307 duk_small_int_t op
= op_flags
& 0xff;
1308 if (op
== DUK_OP_EXTRA
&&
1309 (a
== DUK_EXTRAOP_INITGET
|| a
== DUK_EXTRAOP_INITSET
)) {
1310 /* Special shuffling for INITGET/INITSET, where slot C
1311 * identifies a register pair and cannot be shuffled
1312 * normally. Use an indirect variant instead.
1314 DUK_ASSERT((op_flags
& DUK__EMIT_FLAG_C_IS_TARGET
) == 0);
1315 duk__emit_load_int32_noshuffle(comp_ctx
, tmp
, c
);
1316 DUK_ASSERT(DUK_EXTRAOP_INITGETI
== DUK_EXTRAOP_INITGET
+ 1);
1317 DUK_ASSERT(DUK_EXTRAOP_INITSETI
== DUK_EXTRAOP_INITSET
+ 1);
1318 a
++; /* indirect opcode follows direct */
1320 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_LDREG
, tmp
, c
));
1325 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %ld", (long) c
));
1326 goto error_outofregs
;
1330 /* Main operation */
1332 DUK_ASSERT_DISABLE(a
>= DUK_BC_A_MIN
); /* unsigned */
1333 DUK_ASSERT(a
<= DUK_BC_A_MAX
);
1334 DUK_ASSERT_DISABLE(b
>= DUK_BC_B_MIN
); /* unsigned */
1335 DUK_ASSERT(b
<= DUK_BC_B_MAX
);
1336 DUK_ASSERT_DISABLE(c
>= DUK_BC_C_MIN
); /* unsigned */
1337 DUK_ASSERT(c
<= DUK_BC_C_MAX
);
1339 ins
|= DUK_ENC_OP_A_B_C(op_flags
& 0xff, a
, b
, c
);
1340 duk__emit(comp_ctx
, ins
);
1342 /* NEXTENUM needs a jump slot right after the main instruction.
1343 * When the JUMP is taken, output spilling is not needed so this
1344 * workaround is possible. The jump slot PC is exceptionally
1345 * plumbed through comp_ctx to minimize call sites.
1347 if (op_flags
& DUK__EMIT_FLAG_RESERVE_JUMPSLOT
) {
1348 comp_ctx
->emit_jumpslot_pc
= duk__get_current_pc(comp_ctx
);
1349 duk__emit_abc(comp_ctx
, DUK_OP_JUMP
, 0);
1352 /* Output shuffling: only one output register is realistically possible.
1354 * (Zero would normally be an OK marker value: if the target register
1355 * was zero, it would never be shuffled. But with DUK_USE_SHUFFLE_TORTURE
1356 * this is no longer true, so use -1 as a marker instead.)
1360 DUK_ASSERT(b_out
< 0);
1361 DUK_ASSERT(c_out
< 0);
1362 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_STREG
, a
, a_out
));
1363 } else if (b_out
>= 0) {
1364 DUK_ASSERT(a_out
< 0);
1365 DUK_ASSERT(c_out
< 0);
1366 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_STREG
, b
, b_out
));
1367 } else if (c_out
>= 0) {
1368 DUK_ASSERT(b_out
< 0);
1369 DUK_ASSERT(c_out
< 0);
1370 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_STREG
, c
, c_out
));
1376 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_REG_LIMIT
);
1379 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
) {
1380 duk__emit_a_b_c(comp_ctx
, op_flags
| DUK__EMIT_FLAG_NO_SHUFFLE_C
, a
, b
, 0);
1384 DUK_LOCAL
void duk__emit_a(duk_compiler_ctx
*comp_ctx
, int op_flags
, int a
) {
1385 duk__emit_a_b_c(comp_ctx
, op_flags
| DUK__EMIT_FLAG_NO_SHUFFLE_B
| DUK__EMIT_FLAG_NO_SHUFFLE_C
, a
, 0, 0);
1389 DUK_LOCAL
void duk__emit_a_bc(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t op_flags
, duk_regconst_t a
, duk_regconst_t bc
) {
1393 /* allow caller to give a const number with the DUK__CONST_MARKER */
1394 bc
= bc
& (~DUK__CONST_MARKER
);
1396 DUK_ASSERT_DISABLE((op_flags
& 0xff) >= DUK_BC_OP_MIN
); /* unsigned */
1397 DUK_ASSERT((op_flags
& 0xff) <= DUK_BC_OP_MAX
);
1398 DUK_ASSERT_DISABLE(bc
>= DUK_BC_BC_MIN
); /* unsigned */
1399 DUK_ASSERT(bc
<= DUK_BC_BC_MAX
);
1400 DUK_ASSERT((bc
& DUK__CONST_MARKER
) == 0);
1402 if (bc
<= DUK_BC_BC_MAX
) {
1405 /* No BC shuffling now. */
1406 goto error_outofregs
;
1409 #if defined(DUK_USE_SHUFFLE_TORTURE)
1410 if (a
<= DUK_BC_A_MAX
&& (op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_A
)) {
1412 if (a
<= DUK_BC_A_MAX
) {
1414 ins
= DUK_ENC_OP_A_BC(op_flags
& 0xff, a
, bc
);
1415 duk__emit(comp_ctx
, ins
);
1416 } else if (op_flags
& DUK__EMIT_FLAG_NO_SHUFFLE_A
) {
1417 goto error_outofregs
;
1418 } else if (a
<= DUK_BC_BC_MAX
) {
1419 comp_ctx
->curr_func
.needs_shuffle
= 1;
1420 tmp
= comp_ctx
->curr_func
.shuffle1
;
1421 ins
= DUK_ENC_OP_A_BC(op_flags
& 0xff, tmp
, bc
);
1422 if (op_flags
& DUK__EMIT_FLAG_A_IS_SOURCE
) {
1423 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_LDREG
, tmp
, a
));
1424 duk__emit(comp_ctx
, ins
);
1426 duk__emit(comp_ctx
, ins
);
1427 duk__emit(comp_ctx
, DUK_ENC_OP_A_BC(DUK_OP_STREG
, tmp
, a
));
1430 goto error_outofregs
;
1435 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_REG_LIMIT
);
1438 DUK_LOCAL
void duk__emit_abc(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t op
, duk_regconst_t abc
) {
1441 DUK_ASSERT_DISABLE(op
>= DUK_BC_OP_MIN
); /* unsigned */
1442 DUK_ASSERT(op
<= DUK_BC_OP_MAX
);
1443 DUK_ASSERT_DISABLE(abc
>= DUK_BC_ABC_MIN
); /* unsigned */
1444 DUK_ASSERT(abc
<= DUK_BC_ABC_MAX
);
1445 DUK_ASSERT((abc
& DUK__CONST_MARKER
) == 0);
1447 if (abc
<= DUK_BC_ABC_MAX
) {
1450 goto error_outofregs
;
1452 ins
= DUK_ENC_OP_ABC(op
, abc
);
1453 DUK_DDD(DUK_DDDPRINT("duk__emit_abc: 0x%08lx line=%ld pc=%ld op=%ld (%!C) abc=%ld (%!I)",
1454 (unsigned long) ins
, (long) comp_ctx
->curr_token
.start_line
,
1455 (long) duk__get_current_pc(comp_ctx
), (long) op
, (long) op
,
1456 (long) abc
, (duk_instr_t
) ins
));
1457 duk__emit(comp_ctx
, ins
);
1461 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_REG_LIMIT
);
1464 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
) {
1465 DUK_ASSERT_DISABLE((extraop_flags
& 0xff) >= DUK_BC_EXTRAOP_MIN
); /* unsigned */
1466 DUK_ASSERT((extraop_flags
& 0xff) <= DUK_BC_EXTRAOP_MAX
);
1467 /* Setting "no shuffle A" is covered by the assert, but it's needed
1468 * with DUK_USE_SHUFFLE_TORTURE.
1470 duk__emit_a_b_c(comp_ctx
,
1471 DUK_OP_EXTRA
| DUK__EMIT_FLAG_NO_SHUFFLE_A
| (extraop_flags
& ~0xff), /* transfer flags */
1472 extraop_flags
& 0xff,
1477 DUK_LOCAL
void duk__emit_extraop_b(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t extraop_flags
, duk_regconst_t b
) {
1478 DUK_ASSERT_DISABLE((extraop_flags
& 0xff) >= DUK_BC_EXTRAOP_MIN
); /* unsigned */
1479 DUK_ASSERT((extraop_flags
& 0xff) <= DUK_BC_EXTRAOP_MAX
);
1480 /* Setting "no shuffle A" is covered by the assert, but it's needed
1481 * with DUK_USE_SHUFFLE_TORTURE.
1483 duk__emit_a_b_c(comp_ctx
,
1484 DUK_OP_EXTRA
| DUK__EMIT_FLAG_NO_SHUFFLE_A
| (extraop_flags
& ~0xff), /* transfer flags */
1485 extraop_flags
& 0xff,
1490 DUK_LOCAL
void duk__emit_extraop_bc(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t extraop
, duk_regconst_t bc
) {
1491 DUK_ASSERT_DISABLE(extraop
>= DUK_BC_EXTRAOP_MIN
); /* unsigned */
1492 DUK_ASSERT(extraop
<= DUK_BC_EXTRAOP_MAX
);
1493 /* Setting "no shuffle A" is covered by the assert, but it's needed
1494 * with DUK_USE_SHUFFLE_TORTURE.
1496 duk__emit_a_bc(comp_ctx
,
1497 DUK_OP_EXTRA
| DUK__EMIT_FLAG_NO_SHUFFLE_A
,
1502 DUK_LOCAL
void duk__emit_extraop_only(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t extraop_flags
) {
1503 DUK_ASSERT_DISABLE((extraop_flags
& 0xff) >= DUK_BC_EXTRAOP_MIN
); /* unsigned */
1504 DUK_ASSERT((extraop_flags
& 0xff) <= DUK_BC_EXTRAOP_MAX
);
1505 /* Setting "no shuffle A" is covered by the assert, but it's needed
1506 * with DUK_USE_SHUFFLE_TORTURE.
1508 duk__emit_a_b_c(comp_ctx
,
1509 DUK_OP_EXTRA
| DUK__EMIT_FLAG_NO_SHUFFLE_A
| DUK__EMIT_FLAG_NO_SHUFFLE_B
|
1510 DUK__EMIT_FLAG_NO_SHUFFLE_C
| (extraop_flags
& ~0xff), /* transfer flags */
1511 extraop_flags
& 0xff,
1516 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
) {
1517 /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
1518 * would only shuffle once (instead of twice). The current code works
1519 * though, and has a smaller compiler footprint.
1522 if ((val
>= (duk_int32_t
) DUK_BC_BC_MIN
- (duk_int32_t
) DUK_BC_LDINT_BIAS
) &&
1523 (val
<= (duk_int32_t
) DUK_BC_BC_MAX
- (duk_int32_t
) DUK_BC_LDINT_BIAS
)) {
1524 DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld", (long) reg
, (long) val
));
1525 duk__emit_a_bc(comp_ctx
, DUK_OP_LDINT
| op_flags
, reg
, (duk_regconst_t
) (val
+ (duk_int32_t
) DUK_BC_LDINT_BIAS
));
1527 duk_int32_t hi
= val
>> DUK_BC_LDINTX_SHIFT
;
1528 duk_int32_t lo
= val
& ((((duk_int32_t
) 1) << DUK_BC_LDINTX_SHIFT
) - 1);
1529 DUK_ASSERT(lo
>= 0);
1530 DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld",
1531 (long) reg
, (long) val
, (long) hi
, (long) lo
));
1532 duk__emit_a_bc(comp_ctx
, DUK_OP_LDINT
| op_flags
, reg
, (duk_regconst_t
) (hi
+ (duk_int32_t
) DUK_BC_LDINT_BIAS
));
1533 duk__emit_a_bc(comp_ctx
, DUK_OP_LDINTX
| op_flags
, reg
, (duk_regconst_t
) lo
);
1537 DUK_LOCAL
void duk__emit_load_int32(duk_compiler_ctx
*comp_ctx
, duk_reg_t reg
, duk_int32_t val
) {
1538 duk__emit_load_int32_raw(comp_ctx
, reg
, val
, 0 /*op_flags*/);
1541 #if defined(DUK_USE_SHUFFLE_TORTURE)
1542 /* Used by duk__emit*() calls so that we don't shuffle the loadints that
1543 * are needed to handle indirect opcodes.
1545 DUK_LOCAL
void duk__emit_load_int32_noshuffle(duk_compiler_ctx
*comp_ctx
, duk_reg_t reg
, duk_int32_t val
) {
1546 duk__emit_load_int32_raw(comp_ctx
, reg
, val
, DUK__EMIT_FLAG_NO_SHUFFLE_A
/*op_flags*/);
1549 DUK_LOCAL
void duk__emit_load_int32_noshuffle(duk_compiler_ctx
*comp_ctx
, duk_reg_t reg
, duk_int32_t val
) {
1550 /* When torture not enabled, can just use the same helper because
1551 * 'reg' won't get spilled.
1553 DUK_ASSERT(reg
<= DUK_BC_A_MAX
);
1554 duk__emit_load_int32(comp_ctx
, reg
, val
);
1558 DUK_LOCAL
void duk__emit_jump(duk_compiler_ctx
*comp_ctx
, duk_int_t target_pc
) {
1562 curr_pc
= (duk_int_t
) (DUK_BW_GET_SIZE(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
) / sizeof(duk_compiler_instr
));
1563 offset
= (duk_int_t
) target_pc
- (duk_int_t
) curr_pc
- 1;
1564 DUK_ASSERT(offset
+ DUK_BC_JUMP_BIAS
>= DUK_BC_ABC_MIN
);
1565 DUK_ASSERT(offset
+ DUK_BC_JUMP_BIAS
<= DUK_BC_ABC_MAX
);
1566 duk__emit_abc(comp_ctx
, DUK_OP_JUMP
, (duk_regconst_t
) (offset
+ DUK_BC_JUMP_BIAS
));
1569 DUK_LOCAL duk_int_t
duk__emit_jump_empty(duk_compiler_ctx
*comp_ctx
) {
1572 ret
= duk__get_current_pc(comp_ctx
); /* useful for patching jumps later */
1573 duk__emit_abc(comp_ctx
, DUK_OP_JUMP
, 0);
1577 /* Insert an empty jump in the middle of code emitted earlier. This is
1578 * currently needed for compiling for-in.
1580 DUK_LOCAL
void duk__insert_jump_entry(duk_compiler_ctx
*comp_ctx
, duk_int_t jump_pc
) {
1581 #if defined(DUK_USE_PC2LINE)
1584 duk_compiler_instr
*instr
;
1587 offset
= jump_pc
* sizeof(duk_compiler_instr
),
1588 instr
= (duk_compiler_instr
*) (void *)
1589 DUK_BW_INSERT_ENSURE_AREA(comp_ctx
->thr
,
1590 &comp_ctx
->curr_func
.bw_code
,
1592 sizeof(duk_compiler_instr
));
1594 #if defined(DUK_USE_PC2LINE)
1595 line
= comp_ctx
->curr_token
.start_line
; /* approximation, close enough */
1597 instr
->ins
= DUK_ENC_OP_ABC(DUK_OP_JUMP
, 0);
1598 #if defined(DUK_USE_PC2LINE)
1602 DUK_BW_ADD_PTR(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
, sizeof(duk_compiler_instr
));
1603 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
) > DUK_USE_ESBC_MAX_BYTES
)) {
1609 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_BYTECODE_LIMIT
);
1612 /* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional
1613 * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this).
1615 DUK_LOCAL
void duk__patch_jump(duk_compiler_ctx
*comp_ctx
, duk_int_t jump_pc
, duk_int_t target_pc
) {
1616 duk_compiler_instr
*instr
;
1619 /* allow negative PCs, behave as a no-op */
1621 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld",
1622 (long) jump_pc
, (long) target_pc
));
1625 DUK_ASSERT(jump_pc
>= 0);
1627 /* XXX: range assert */
1628 instr
= duk__get_instr_ptr(comp_ctx
, jump_pc
);
1629 DUK_ASSERT(instr
!= NULL
);
1631 /* XXX: range assert */
1632 offset
= target_pc
- jump_pc
- 1;
1634 instr
->ins
= DUK_ENC_OP_ABC(DUK_OP_JUMP
, offset
+ DUK_BC_JUMP_BIAS
);
1635 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): jump_pc=%ld, target_pc=%ld, offset=%ld",
1636 (long) jump_pc
, (long) target_pc
, (long) offset
));
1639 DUK_LOCAL
void duk__patch_jump_here(duk_compiler_ctx
*comp_ctx
, duk_int_t jump_pc
) {
1640 duk__patch_jump(comp_ctx
, jump_pc
, duk__get_current_pc(comp_ctx
));
1643 DUK_LOCAL
void duk__patch_trycatch(duk_compiler_ctx
*comp_ctx
, duk_int_t ldconst_pc
, duk_int_t trycatch_pc
, duk_regconst_t reg_catch
, duk_regconst_t const_varname
, duk_small_uint_t flags
) {
1644 duk_compiler_instr
*instr
;
1646 DUK_ASSERT((reg_catch
& DUK__CONST_MARKER
) == 0);
1648 instr
= duk__get_instr_ptr(comp_ctx
, ldconst_pc
);
1649 DUK_ASSERT(DUK_DEC_OP(instr
->ins
) == DUK_OP_LDCONST
);
1650 DUK_ASSERT(instr
!= NULL
);
1651 if (const_varname
& DUK__CONST_MARKER
) {
1652 /* Have a catch variable. */
1653 const_varname
= const_varname
& (~DUK__CONST_MARKER
);
1654 if (reg_catch
> DUK_BC_BC_MAX
|| const_varname
> DUK_BC_BC_MAX
) {
1655 /* Catch attempts to use out-of-range reg/const. Without this
1656 * check Duktape 0.12.0 could generate invalid code which caused
1657 * an assert failure on execution. This error is triggered e.g.
1658 * for functions with a lot of constants and a try-catch statement.
1659 * Shuffling or opcode semantics change is needed to fix the issue.
1660 * See: test-bug-trycatch-many-constants.js.
1662 DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)",
1663 (long) flags
, (long) reg_catch
, (long) const_varname
, (long) const_varname
));
1664 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_REG_LIMIT
);
1666 instr
->ins
|= DUK_ENC_OP_A_BC(0, 0, const_varname
);
1668 /* No catch variable, e.g. a try-finally; replace LDCONST with
1669 * NOP to avoid a bogus LDCONST.
1671 instr
->ins
= DUK_ENC_OP_A(DUK_OP_EXTRA
, DUK_EXTRAOP_NOP
);
1674 instr
= duk__get_instr_ptr(comp_ctx
, trycatch_pc
);
1675 DUK_ASSERT(instr
!= NULL
);
1676 DUK_ASSERT_DISABLE(flags
>= DUK_BC_A_MIN
);
1677 DUK_ASSERT(flags
<= DUK_BC_A_MAX
);
1678 instr
->ins
= DUK_ENC_OP_A_BC(DUK_OP_TRYCATCH
, flags
, reg_catch
);
1681 DUK_LOCAL
void duk__emit_if_false_skip(duk_compiler_ctx
*comp_ctx
, duk_regconst_t regconst
) {
1682 duk__emit_a_b_c(comp_ctx
,
1683 DUK_OP_IF
| DUK__EMIT_FLAG_NO_SHUFFLE_A
| DUK__EMIT_FLAG_NO_SHUFFLE_C
,
1689 DUK_LOCAL
void duk__emit_if_true_skip(duk_compiler_ctx
*comp_ctx
, duk_regconst_t regconst
) {
1690 duk__emit_a_b_c(comp_ctx
,
1691 DUK_OP_IF
| DUK__EMIT_FLAG_NO_SHUFFLE_A
| DUK__EMIT_FLAG_NO_SHUFFLE_C
,
1697 DUK_LOCAL
void duk__emit_invalid(duk_compiler_ctx
*comp_ctx
) {
1698 duk__emit_extraop_bc(comp_ctx
, DUK_EXTRAOP_INVALID
, 0);
1702 * Peephole optimizer for finished bytecode.
1704 * Does not remove opcodes; currently only straightens out unconditional
1705 * jump chains which are generated by several control structures.
1708 DUK_LOCAL
void duk__peephole_optimize_bytecode(duk_compiler_ctx
*comp_ctx
) {
1709 duk_compiler_instr
*bc
;
1710 duk_small_uint_t iter
;
1712 duk_int_t count_opt
;
1714 bc
= (duk_compiler_instr
*) (void *) DUK_BW_GET_BASEPTR(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
);
1715 #if defined(DUK_USE_BUFLEN16)
1716 /* No need to assert, buffer size maximum is 0xffff. */
1718 DUK_ASSERT((duk_size_t
) DUK_BW_GET_SIZE(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
) / sizeof(duk_compiler_instr
) <= (duk_size_t
) DUK_INT_MAX
); /* bytecode limits */
1720 n
= (duk_int_t
) (DUK_BW_GET_SIZE(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
) / sizeof(duk_compiler_instr
));
1722 for (iter
= 0; iter
< DUK_COMPILER_PEEPHOLE_MAXITER
; iter
++) {
1725 for (i
= 0; i
< n
; i
++) {
1727 duk_int_t target_pc1
;
1728 duk_int_t target_pc2
;
1731 if (DUK_DEC_OP(ins
) != DUK_OP_JUMP
) {
1735 target_pc1
= i
+ 1 + DUK_DEC_ABC(ins
) - DUK_BC_JUMP_BIAS
;
1736 DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i
, (long) target_pc1
));
1737 DUK_ASSERT(target_pc1
>= 0);
1738 DUK_ASSERT(target_pc1
< n
);
1740 /* Note: if target_pc1 == i, we'll optimize a jump to itself.
1741 * This does not need to be checked for explicitly; the case
1742 * is rare and max iter breaks us out.
1745 ins
= bc
[target_pc1
].ins
;
1746 if (DUK_DEC_OP(ins
) != DUK_OP_JUMP
) {
1750 target_pc2
= target_pc1
+ 1 + DUK_DEC_ABC(ins
) - DUK_BC_JUMP_BIAS
;
1752 DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld",
1753 (long) i
, (long) target_pc1
, (long) target_pc2
));
1755 bc
[i
].ins
= DUK_ENC_OP_ABC(DUK_OP_JUMP
, target_pc2
- (i
+ 1) + DUK_BC_JUMP_BIAS
);
1760 DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld", (long) count_opt
, (long) (iter
+ 1)));
1762 if (count_opt
== 0) {
1769 * Intermediate value helpers
1772 #define DUK__ISREG(comp_ctx,x) (((x) & DUK__CONST_MARKER) == 0)
1773 #define DUK__ISCONST(comp_ctx,x) (((x) & DUK__CONST_MARKER) != 0)
1774 #define DUK__ISTEMP(comp_ctx,x) (DUK__ISREG((comp_ctx), (x)) && (duk_regconst_t) (x) >= (duk_regconst_t) ((comp_ctx)->curr_func.temp_first))
1775 #define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next)
1776 #define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */
1777 #define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x))
1778 #define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx))
1779 #define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count))
1781 /* Flags for intermediate value coercions. A flag for using a forced reg
1782 * is not needed, the forced_reg argument suffices and generates better
1783 * code (it is checked as it is used).
1785 #define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */
1786 #define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */
1787 #define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
1789 /* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(ctx,x) */
1791 #if 0 /* enable manually for dumping */
1792 #define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0)
1793 #define DUK__DUMP_IVALUE(compctx,ivalue) do { duk__dump_ivalue((compctx), (ivalue)); } while (0)
1795 DUK_LOCAL
void duk__dump_ispec(duk_compiler_ctx
*comp_ctx
, duk_ispec
*x
) {
1796 DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T",
1797 (long) x
->t
, (unsigned long) x
->regconst
, (long) x
->valstack_idx
,
1798 duk_get_tval((duk_context
*) comp_ctx
->thr
, x
->valstack_idx
)));
1800 DUK_LOCAL
void duk__dump_ivalue(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
) {
1801 DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld "
1802 "x1={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T} "
1803 "x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}",
1804 (long) x
->t
, (long) x
->op
,
1805 (long) x
->x1
.t
, (unsigned long) x
->x1
.regconst
, (long) x
->x1
.valstack_idx
,
1806 duk_get_tval((duk_context
*) comp_ctx
->thr
, x
->x1
.valstack_idx
),
1807 (long) x
->x2
.t
, (unsigned long) x
->x2
.regconst
, (long) x
->x2
.valstack_idx
,
1808 duk_get_tval((duk_context
*) comp_ctx
->thr
, x
->x2
.valstack_idx
)));
1811 #define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
1812 #define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0)
1815 DUK_LOCAL
void duk__copy_ispec(duk_compiler_ctx
*comp_ctx
, duk_ispec
*src
, duk_ispec
*dst
) {
1816 duk_context
*ctx
= (duk_context
*) comp_ctx
->thr
;
1819 dst
->regconst
= src
->regconst
;
1820 duk_copy(ctx
, src
->valstack_idx
, dst
->valstack_idx
);
1823 DUK_LOCAL
void duk__copy_ivalue(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*src
, duk_ivalue
*dst
) {
1824 duk_context
*ctx
= (duk_context
*) comp_ctx
->thr
;
1828 dst
->x1
.t
= src
->x1
.t
;
1829 dst
->x1
.regconst
= src
->x1
.regconst
;
1830 dst
->x2
.t
= src
->x2
.t
;
1831 dst
->x2
.regconst
= src
->x2
.regconst
;
1832 duk_copy(ctx
, src
->x1
.valstack_idx
, dst
->x1
.valstack_idx
);
1833 duk_copy(ctx
, src
->x2
.valstack_idx
, dst
->x2
.valstack_idx
);
1837 DUK_LOCAL duk_bool_t
duk__is_whole_get_int32(duk_double_t x
, duk_int32_t
*ival
) {
1841 c
= DUK_FPCLASSIFY(x
);
1842 if (c
== DUK_FP_NORMAL
|| (c
== DUK_FP_ZERO
&& !DUK_SIGNBIT(x
))) {
1843 /* Don't allow negative zero as it will cause trouble with
1844 * LDINT+LDINTX. But positive zero is OK.
1846 t
= (duk_int32_t
) x
;
1847 if ((duk_double_t
) t
== x
) {
1856 DUK_LOCAL duk_reg_t
duk__alloctemps(duk_compiler_ctx
*comp_ctx
, duk_small_int_t num
) {
1859 res
= comp_ctx
->curr_func
.temp_next
;
1860 comp_ctx
->curr_func
.temp_next
+= num
;
1862 if (comp_ctx
->curr_func
.temp_next
> DUK__MAX_TEMPS
) { /* == DUK__MAX_TEMPS is OK */
1863 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_TEMP_LIMIT
);
1866 /* maintain highest 'used' temporary, needed to figure out nregs of function */
1867 if (comp_ctx
->curr_func
.temp_next
> comp_ctx
->curr_func
.temp_max
) {
1868 comp_ctx
->curr_func
.temp_max
= comp_ctx
->curr_func
.temp_next
;
1874 DUK_LOCAL duk_reg_t
duk__alloctemp(duk_compiler_ctx
*comp_ctx
) {
1875 return duk__alloctemps(comp_ctx
, 1);
1878 DUK_LOCAL
void duk__settemp_checkmax(duk_compiler_ctx
*comp_ctx
, duk_reg_t temp_next
) {
1879 comp_ctx
->curr_func
.temp_next
= temp_next
;
1880 if (temp_next
> comp_ctx
->curr_func
.temp_max
) {
1881 comp_ctx
->curr_func
.temp_max
= temp_next
;
1885 /* get const for value at valstack top */
1886 DUK_LOCAL duk_regconst_t
duk__getconst(duk_compiler_ctx
*comp_ctx
) {
1887 duk_hthread
*thr
= comp_ctx
->thr
;
1888 duk_context
*ctx
= (duk_context
*) thr
;
1889 duk_compiler_func
*f
= &comp_ctx
->curr_func
;
1891 duk_int_t i
, n
, n_check
;
1893 n
= (duk_int_t
) duk_get_length(ctx
, f
->consts_idx
);
1895 tv1
= DUK_GET_TVAL_NEGIDX(ctx
, -1);
1896 DUK_ASSERT(tv1
!= NULL
);
1898 #if defined(DUK_USE_FASTINT)
1899 /* Explicit check for fastint downgrade. */
1900 DUK_TVAL_CHKFAST_INPLACE(tv1
);
1903 /* Sanity workaround for handling functions with a large number of
1904 * constants at least somewhat reasonably. Otherwise checking whether
1905 * we already have the constant would grow very slow (as it is O(N^2)).
1907 n_check
= (n
> DUK__GETCONST_MAX_CONSTS_CHECK
? DUK__GETCONST_MAX_CONSTS_CHECK
: n
);
1908 for (i
= 0; i
< n_check
; i
++) {
1909 duk_tval
*tv2
= DUK_HOBJECT_A_GET_VALUE_PTR(thr
->heap
, f
->h_consts
, i
);
1911 /* Strict equality is NOT enough, because we cannot use the same
1912 * constant for e.g. +0 and -0.
1914 if (duk_js_samevalue(tv1
, tv2
)) {
1915 DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld",
1916 (duk_tval
*) tv1
, (long) i
));
1918 return (duk_regconst_t
) (i
| DUK__CONST_MARKER
);
1922 if (n
> DUK__MAX_CONSTS
) {
1923 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_CONST_LIMIT
);
1926 DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
1927 (duk_tval
*) tv1
, (long) n
));
1928 (void) duk_put_prop_index(ctx
, f
->consts_idx
, n
); /* invalidates tv1, tv2 */
1929 return (duk_regconst_t
) (n
| DUK__CONST_MARKER
);
1932 /* Get the value represented by an duk_ispec to a register or constant.
1933 * The caller can control the result by indicating whether or not:
1935 * (1) a constant is allowed (sometimes the caller needs the result to
1938 * (2) a temporary register is required (usually when caller requires
1939 * the register to be safely mutable; normally either a bound
1940 * register or a temporary register are both OK)
1942 * (3) a forced register target needs to be used
1944 * Bytecode may be emitted to generate the necessary value. The return
1945 * value is either a register or a constant.
1949 duk_regconst_t
duk__ispec_toregconst_raw(duk_compiler_ctx
*comp_ctx
,
1951 duk_reg_t forced_reg
,
1952 duk_small_uint_t flags
) {
1953 duk_hthread
*thr
= comp_ctx
->thr
;
1954 duk_context
*ctx
= (duk_context
*) thr
;
1956 DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, "
1957 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
1960 (duk_tval
*) duk_get_tval(ctx
, x
->valstack_idx
),
1962 (unsigned long) flags
,
1963 (long) ((flags
& DUK__IVAL_FLAG_ALLOW_CONST
) ? 1 : 0),
1964 (long) ((flags
& DUK__IVAL_FLAG_REQUIRE_TEMP
) ? 1 : 0),
1965 (long) ((flags
& DUK__IVAL_FLAG_REQUIRE_SHORT
) ? 1 : 0)));
1968 case DUK_ISPEC_VALUE
: {
1971 tv
= DUK_GET_TVAL_POSIDX(ctx
, x
->valstack_idx
);
1972 DUK_ASSERT(tv
!= NULL
);
1974 switch (DUK_TVAL_GET_TAG(tv
)) {
1975 case DUK_TAG_UNDEFINED
: {
1976 /* Note: although there is no 'undefined' literal, undefined
1977 * values can occur during compilation as a result of e.g.
1978 * the 'void' operator.
1980 duk_reg_t dest
= (forced_reg
>= 0 ? forced_reg
: DUK__ALLOCTEMP(comp_ctx
));
1981 duk__emit_extraop_bc(comp_ctx
, DUK_EXTRAOP_LDUNDEF
, (duk_regconst_t
) dest
);
1982 return (duk_regconst_t
) dest
;
1984 case DUK_TAG_NULL
: {
1985 duk_reg_t dest
= (forced_reg
>= 0 ? forced_reg
: DUK__ALLOCTEMP(comp_ctx
));
1986 duk__emit_extraop_bc(comp_ctx
, DUK_EXTRAOP_LDNULL
, (duk_regconst_t
) dest
);
1987 return (duk_regconst_t
) dest
;
1989 case DUK_TAG_BOOLEAN
: {
1990 duk_reg_t dest
= (forced_reg
>= 0 ? forced_reg
: DUK__ALLOCTEMP(comp_ctx
));
1991 duk__emit_extraop_bc(comp_ctx
,
1992 (DUK_TVAL_GET_BOOLEAN(tv
) ? DUK_EXTRAOP_LDTRUE
: DUK_EXTRAOP_LDFALSE
),
1993 (duk_regconst_t
) dest
);
1994 return (duk_regconst_t
) dest
;
1996 case DUK_TAG_POINTER
: {
2000 case DUK_TAG_STRING
: {
2003 duk_regconst_t constidx
;
2005 h
= DUK_TVAL_GET_STRING(tv
);
2007 DUK_ASSERT(h
!= NULL
);
2009 #if 0 /* XXX: to be implemented? */
2010 /* Use special opcodes to load short strings */
2011 if (DUK_HSTRING_GET_BYTELEN(h
) <= 2) {
2012 /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */
2013 } else if (DUK_HSTRING_GET_BYTELEN(h
) <= 6) {
2014 /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
2017 duk_dup(ctx
, x
->valstack_idx
);
2018 constidx
= duk__getconst(comp_ctx
);
2020 if (flags
& DUK__IVAL_FLAG_ALLOW_CONST
) {
2024 dest
= (forced_reg
>= 0 ? forced_reg
: DUK__ALLOCTEMP(comp_ctx
));
2025 duk__emit_a_bc(comp_ctx
, DUK_OP_LDCONST
, (duk_regconst_t
) dest
, constidx
);
2026 return (duk_regconst_t
) dest
;
2028 case DUK_TAG_OBJECT
: {
2032 case DUK_TAG_BUFFER
: {
2036 case DUK_TAG_LIGHTFUNC
: {
2040 #if defined(DUK_USE_FASTINT)
2041 case DUK_TAG_FASTINT
:
2046 duk_regconst_t constidx
;
2050 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv
));
2051 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv
));
2052 dval
= DUK_TVAL_GET_NUMBER(tv
);
2054 if (!(flags
& DUK__IVAL_FLAG_ALLOW_CONST
)) {
2055 /* A number can be loaded either through a constant, using
2056 * LDINT, or using LDINT+LDINTX. LDINT is always a size win,
2057 * LDINT+LDINTX is not if the constant is used multiple times.
2058 * Currently always prefer LDINT+LDINTX over a double constant.
2061 if (duk__is_whole_get_int32(dval
, &ival
)) {
2062 dest
= (forced_reg
>= 0 ? forced_reg
: DUK__ALLOCTEMP(comp_ctx
));
2063 duk__emit_load_int32(comp_ctx
, dest
, ival
);
2064 return (duk_regconst_t
) dest
;
2068 duk_dup(ctx
, x
->valstack_idx
);
2069 constidx
= duk__getconst(comp_ctx
);
2071 if (flags
& DUK__IVAL_FLAG_ALLOW_CONST
) {
2074 dest
= (forced_reg
>= 0 ? forced_reg
: DUK__ALLOCTEMP(comp_ctx
));
2075 duk__emit_a_bc(comp_ctx
, DUK_OP_LDCONST
, (duk_regconst_t
) dest
, constidx
);
2076 return (duk_regconst_t
) dest
;
2081 case DUK_ISPEC_REGCONST
: {
2082 if (forced_reg
>= 0) {
2083 if (x
->regconst
& DUK__CONST_MARKER
) {
2084 duk__emit_a_bc(comp_ctx
, DUK_OP_LDCONST
, forced_reg
, x
->regconst
);
2085 } else if (x
->regconst
!= (duk_regconst_t
) forced_reg
) {
2086 duk__emit_a_bc(comp_ctx
, DUK_OP_LDREG
, forced_reg
, x
->regconst
);
2088 ; /* already in correct reg */
2090 return (duk_regconst_t
) forced_reg
;
2093 DUK_ASSERT(forced_reg
< 0);
2094 if (x
->regconst
& DUK__CONST_MARKER
) {
2095 if (!(flags
& DUK__IVAL_FLAG_ALLOW_CONST
)) {
2096 duk_reg_t dest
= DUK__ALLOCTEMP(comp_ctx
);
2097 duk__emit_a_bc(comp_ctx
, DUK_OP_LDCONST
, (duk_regconst_t
) dest
, x
->regconst
);
2098 return (duk_regconst_t
) dest
;
2103 DUK_ASSERT(forced_reg
< 0 && !(x
->regconst
& DUK__CONST_MARKER
));
2104 if ((flags
& DUK__IVAL_FLAG_REQUIRE_TEMP
) && !DUK__ISTEMP(comp_ctx
, x
->regconst
)) {
2105 duk_reg_t dest
= DUK__ALLOCTEMP(comp_ctx
);
2106 duk__emit_a_bc(comp_ctx
, DUK_OP_LDREG
, (duk_regconst_t
) dest
, x
->regconst
);
2107 return (duk_regconst_t
) dest
;
2116 DUK_ERROR_INTERNAL_DEFMSG(thr
);
2120 DUK_LOCAL
void duk__ispec_toforcedreg(duk_compiler_ctx
*comp_ctx
, duk_ispec
*x
, duk_reg_t forced_reg
) {
2121 DUK_ASSERT(forced_reg
>= 0);
2122 (void) duk__ispec_toregconst_raw(comp_ctx
, x
, forced_reg
, 0 /*flags*/);
2125 /* Coerce an duk_ivalue to a 'plain' value by generating the necessary
2126 * arithmetic operations, property access, or variable access bytecode.
2127 * The duk_ivalue argument ('x') is converted into a plain value as a
2130 DUK_LOCAL
void duk__ivalue_toplain_raw(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
, duk_reg_t forced_reg
) {
2131 duk_hthread
*thr
= comp_ctx
->thr
;
2132 duk_context
*ctx
= (duk_context
*) thr
;
2134 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
2136 (long) x
->t
, (long) x
->op
,
2137 (long) x
->x1
.t
, (long) x
->x1
.regconst
,
2138 (duk_tval
*) duk_get_tval(ctx
, x
->x1
.valstack_idx
),
2139 (long) x
->x2
.t
, (long) x
->x2
.regconst
,
2140 (duk_tval
*) duk_get_tval(ctx
, x
->x2
.valstack_idx
),
2141 (long) forced_reg
));
2144 case DUK_IVAL_PLAIN
: {
2147 /* XXX: support unary arithmetic ivalues (useful?) */
2148 case DUK_IVAL_ARITH
:
2149 case DUK_IVAL_ARITH_EXTRAOP
: {
2150 duk_regconst_t arg1
;
2151 duk_regconst_t arg2
;
2156 DUK_DDD(DUK_DDDPRINT("arith to plain conversion"));
2158 /* inline arithmetic check for constant values */
2159 /* XXX: use the exactly same arithmetic function here as in executor */
2160 if (x
->x1
.t
== DUK_ISPEC_VALUE
&& x
->x2
.t
== DUK_ISPEC_VALUE
&& x
->t
== DUK_IVAL_ARITH
) {
2161 tv1
= DUK_GET_TVAL_POSIDX(ctx
, x
->x1
.valstack_idx
);
2162 tv2
= DUK_GET_TVAL_POSIDX(ctx
, x
->x2
.valstack_idx
);
2163 DUK_ASSERT(tv1
!= NULL
);
2164 DUK_ASSERT(tv2
!= NULL
);
2166 DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T",
2170 if (DUK_TVAL_IS_NUMBER(tv1
) && DUK_TVAL_IS_NUMBER(tv2
)) {
2171 duk_double_t d1
= DUK_TVAL_GET_NUMBER(tv1
);
2172 duk_double_t d2
= DUK_TVAL_GET_NUMBER(tv2
);
2174 duk_bool_t accept
= 1;
2176 DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld",
2177 (double) d1
, (double) d2
, (long) x
->op
));
2179 case DUK_OP_ADD
: d3
= d1
+ d2
; break;
2180 case DUK_OP_SUB
: d3
= d1
- d2
; break;
2181 case DUK_OP_MUL
: d3
= d1
* d2
; break;
2182 case DUK_OP_DIV
: d3
= d1
/ d2
; break;
2183 default: accept
= 0; break;
2187 duk_double_union du
;
2189 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du
);
2192 x
->t
= DUK_IVAL_PLAIN
;
2193 DUK_ASSERT(x
->x1
.t
== DUK_ISPEC_VALUE
);
2194 DUK_TVAL_SET_NUMBER(tv1
, d3
); /* old value is number: no refcount */
2197 } else if (x
->op
== DUK_OP_ADD
&& DUK_TVAL_IS_STRING(tv1
) && DUK_TVAL_IS_STRING(tv2
)) {
2198 /* inline string concatenation */
2199 duk_dup(ctx
, x
->x1
.valstack_idx
);
2200 duk_dup(ctx
, x
->x2
.valstack_idx
);
2202 duk_replace(ctx
, x
->x1
.valstack_idx
);
2203 x
->t
= DUK_IVAL_PLAIN
;
2204 DUK_ASSERT(x
->x1
.t
== DUK_ISPEC_VALUE
);
2209 arg1
= duk__ispec_toregconst_raw(comp_ctx
, &x
->x1
, -1, DUK__IVAL_FLAG_ALLOW_CONST
| DUK__IVAL_FLAG_REQUIRE_SHORT
/*flags*/);
2210 arg2
= duk__ispec_toregconst_raw(comp_ctx
, &x
->x2
, -1, DUK__IVAL_FLAG_ALLOW_CONST
| DUK__IVAL_FLAG_REQUIRE_SHORT
/*flags*/);
2212 /* If forced reg, use it as destination. Otherwise try to
2213 * use either coerced ispec if it is a temporary.
2215 * When using extraops, avoid reusing arg2 as dest because that
2216 * would lead to an LDREG shuffle below. We still can't guarantee
2217 * dest != arg2 because we may have a forced_reg.
2219 if (forced_reg
>= 0) {
2221 } else if (DUK__ISTEMP(comp_ctx
, arg1
)) {
2222 dest
= (duk_reg_t
) arg1
;
2223 } else if (DUK__ISTEMP(comp_ctx
, arg2
) && x
->t
!= DUK_IVAL_ARITH_EXTRAOP
) {
2224 dest
= (duk_reg_t
) arg2
;
2226 dest
= DUK__ALLOCTEMP(comp_ctx
);
2229 /* Extraop arithmetic opcodes must have destination same as
2230 * first source. If second source matches destination we need
2231 * a temporary register to avoid clobbering the second source.
2233 * XXX: change calling code to avoid this situation in most cases.
2236 if (x
->t
== DUK_IVAL_ARITH_EXTRAOP
) {
2237 if (!(DUK__ISREG(comp_ctx
, arg1
) && (duk_reg_t
) arg1
== dest
)) {
2238 if (DUK__ISREG(comp_ctx
, arg2
) && (duk_reg_t
) arg2
== dest
) {
2239 /* arg2 would be clobbered so reassign it to a temp. */
2241 tempreg
= DUK__ALLOCTEMP(comp_ctx
);
2242 duk__emit_a_bc(comp_ctx
, DUK_OP_LDREG
, tempreg
, arg2
);
2246 if (DUK__ISREG(comp_ctx
, arg1
)) {
2247 duk__emit_a_bc(comp_ctx
, DUK_OP_LDREG
, dest
, arg1
);
2249 DUK_ASSERT(DUK__ISCONST(comp_ctx
, arg1
));
2250 duk__emit_a_bc(comp_ctx
, DUK_OP_LDCONST
, dest
, arg1
);
2254 /* Note: special DUK__EMIT_FLAG_B_IS_TARGETSOURCE
2255 * used to indicate that B is both a source and a
2256 * target register. When shuffled, it needs to be
2257 * both input and output shuffled.
2259 DUK_ASSERT(DUK__ISREG(comp_ctx
, dest
));
2260 duk__emit_extraop_b_c(comp_ctx
,
2261 x
->op
| DUK__EMIT_FLAG_B_IS_TARGET
|
2262 DUK__EMIT_FLAG_B_IS_TARGETSOURCE
,
2263 (duk_regconst_t
) dest
,
2264 (duk_regconst_t
) arg2
);
2267 DUK_ASSERT(DUK__ISREG(comp_ctx
, dest
));
2268 duk__emit_a_b_c(comp_ctx
, x
->op
, (duk_regconst_t
) dest
, arg1
, arg2
);
2271 x
->t
= DUK_IVAL_PLAIN
;
2272 x
->x1
.t
= DUK_ISPEC_REGCONST
;
2273 x
->x1
.regconst
= (duk_regconst_t
) dest
;
2276 case DUK_IVAL_PROP
: {
2277 /* XXX: very similar to DUK_IVAL_ARITH - merge? */
2278 duk_regconst_t arg1
;
2279 duk_regconst_t arg2
;
2282 /* Need a short reg/const, does not have to be a mutable temp. */
2283 arg1
= duk__ispec_toregconst_raw(comp_ctx
, &x
->x1
, -1, DUK__IVAL_FLAG_ALLOW_CONST
| DUK__IVAL_FLAG_REQUIRE_SHORT
/*flags*/);
2284 arg2
= duk__ispec_toregconst_raw(comp_ctx
, &x
->x2
, -1, DUK__IVAL_FLAG_ALLOW_CONST
| DUK__IVAL_FLAG_REQUIRE_SHORT
/*flags*/);
2286 /* Pick a destination register. If either base value or key
2287 * happens to be a temp value, reuse it as the destination.
2289 * XXX: The temp must be a "mutable" one, i.e. such that no
2290 * other expression is using it anymore. Here this should be
2291 * the case because the value of a property access expression
2292 * is neither the base nor the key, but the lookup result.
2295 if (forced_reg
>= 0) {
2297 } else if (DUK__ISTEMP(comp_ctx
, arg1
)) {
2298 dest
= (duk_reg_t
) arg1
;
2299 } else if (DUK__ISTEMP(comp_ctx
, arg2
)) {
2300 dest
= (duk_reg_t
) arg2
;
2302 dest
= DUK__ALLOCTEMP(comp_ctx
);
2305 duk__emit_a_b_c(comp_ctx
, DUK_OP_GETPROP
, (duk_regconst_t
) dest
, arg1
, arg2
);
2307 x
->t
= DUK_IVAL_PLAIN
;
2308 x
->x1
.t
= DUK_ISPEC_REGCONST
;
2309 x
->x1
.regconst
= (duk_regconst_t
) dest
;
2312 case DUK_IVAL_VAR
: {
2313 /* x1 must be a string */
2315 duk_reg_t reg_varbind
;
2316 duk_regconst_t rc_varname
;
2318 DUK_ASSERT(x
->x1
.t
== DUK_ISPEC_VALUE
);
2320 duk_dup(ctx
, x
->x1
.valstack_idx
);
2321 if (duk__lookup_lhs(comp_ctx
, ®_varbind
, &rc_varname
)) {
2322 x
->t
= DUK_IVAL_PLAIN
;
2323 x
->x1
.t
= DUK_ISPEC_REGCONST
;
2324 x
->x1
.regconst
= (duk_regconst_t
) reg_varbind
;
2326 dest
= (forced_reg
>= 0 ? forced_reg
: DUK__ALLOCTEMP(comp_ctx
));
2327 duk__emit_a_bc(comp_ctx
, DUK_OP_GETVAR
, (duk_regconst_t
) dest
, rc_varname
);
2328 x
->t
= DUK_IVAL_PLAIN
;
2329 x
->x1
.t
= DUK_ISPEC_REGCONST
;
2330 x
->x1
.regconst
= (duk_regconst_t
) dest
;
2336 DUK_D(DUK_DPRINT("invalid ivalue type: %ld", (long) x
->t
));
2341 DUK_ERROR_INTERNAL_DEFMSG(thr
);
2345 /* evaluate to plain value, no forced register (temp/bound reg both ok) */
2346 DUK_LOCAL
void duk__ivalue_toplain(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
) {
2347 duk__ivalue_toplain_raw(comp_ctx
, x
, -1 /*forced_reg*/);
2350 /* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
2351 DUK_LOCAL
void duk__ivalue_toplain_ignore(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
) {
2354 /* If duk__ivalue_toplain_raw() allocates a temp, forget it and
2355 * restore next temp state.
2357 temp
= DUK__GETTEMP(comp_ctx
);
2358 duk__ivalue_toplain_raw(comp_ctx
, x
, -1 /*forced_reg*/);
2359 DUK__SETTEMP(comp_ctx
, temp
);
2362 /* Coerce an duk_ivalue to a register or constant; result register may
2363 * be a temp or a bound register.
2365 * The duk_ivalue argument ('x') is converted into a regconst as a
2369 duk_regconst_t
duk__ivalue_toregconst_raw(duk_compiler_ctx
*comp_ctx
,
2371 duk_reg_t forced_reg
,
2372 duk_small_uint_t flags
) {
2373 duk_hthread
*thr
= comp_ctx
->thr
;
2374 duk_context
*ctx
= (duk_context
*) thr
;
2379 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
2380 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
2381 (long) x
->t
, (long) x
->op
,
2382 (long) x
->x1
.t
, (long) x
->x1
.regconst
,
2383 (duk_tval
*) duk_get_tval(ctx
, x
->x1
.valstack_idx
),
2384 (long) x
->x2
.t
, (long) x
->x2
.regconst
,
2385 (duk_tval
*) duk_get_tval(ctx
, x
->x2
.valstack_idx
),
2387 (unsigned long) flags
,
2388 (long) ((flags
& DUK__IVAL_FLAG_ALLOW_CONST
) ? 1 : 0),
2389 (long) ((flags
& DUK__IVAL_FLAG_REQUIRE_TEMP
) ? 1 : 0),
2390 (long) ((flags
& DUK__IVAL_FLAG_REQUIRE_SHORT
) ? 1 : 0)));
2392 /* first coerce to a plain value */
2393 duk__ivalue_toplain_raw(comp_ctx
, x
, forced_reg
);
2394 DUK_ASSERT(x
->t
== DUK_IVAL_PLAIN
);
2396 /* then to a register */
2397 reg
= duk__ispec_toregconst_raw(comp_ctx
, &x
->x1
, forced_reg
, flags
);
2398 x
->x1
.t
= DUK_ISPEC_REGCONST
;
2399 x
->x1
.regconst
= reg
;
2404 DUK_LOCAL duk_reg_t
duk__ivalue_toreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
) {
2405 return duk__ivalue_toregconst_raw(comp_ctx
, x
, -1, 0 /*flags*/);
2409 DUK_LOCAL duk_reg_t
duk__ivalue_totemp(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
) {
2410 return duk__ivalue_toregconst_raw(comp_ctx
, x
, -1, DUK__IVAL_FLAG_REQUIRE_TEMP
/*flags*/);
2414 DUK_LOCAL
void duk__ivalue_toforcedreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
, duk_int_t forced_reg
) {
2415 DUK_ASSERT(forced_reg
>= 0);
2416 (void) duk__ivalue_toregconst_raw(comp_ctx
, x
, forced_reg
, 0 /*flags*/);
2419 DUK_LOCAL duk_regconst_t
duk__ivalue_toregconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
) {
2420 return duk__ivalue_toregconst_raw(comp_ctx
, x
, -1, DUK__IVAL_FLAG_ALLOW_CONST
/*flags*/);
2423 DUK_LOCAL duk_regconst_t
duk__ivalue_totempconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*x
) {
2424 return duk__ivalue_toregconst_raw(comp_ctx
, x
, -1, DUK__IVAL_FLAG_ALLOW_CONST
| DUK__IVAL_FLAG_REQUIRE_TEMP
/*flags*/);
2427 /* The issues below can be solved with better flags */
2429 /* XXX: many operations actually want toforcedtemp() -- brand new temp? */
2430 /* XXX: need a toplain_ignore() which will only coerce a value to a temp
2431 * register if it might have a side effect. Side-effect free values do not
2432 * need to be coerced.
2436 * Identifier handling
2439 DUK_LOCAL duk_reg_t
duk__lookup_active_register_binding(duk_compiler_ctx
*comp_ctx
) {
2440 duk_hthread
*thr
= comp_ctx
->thr
;
2441 duk_context
*ctx
= (duk_context
*) thr
;
2442 duk_hstring
*h_varname
;
2445 DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
2446 (duk_tval
*) duk_get_tval(ctx
, -1)));
2449 * Special name handling
2452 h_varname
= duk_get_hstring(ctx
, -1);
2453 DUK_ASSERT(h_varname
!= NULL
);
2455 if (h_varname
== DUK_HTHREAD_STRING_LC_ARGUMENTS(thr
)) {
2456 DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'"));
2457 comp_ctx
->curr_func
.id_access_arguments
= 1;
2461 * Inside one or more 'with' statements fall back to slow path always.
2462 * (See e.g. test-stmt-with.js.)
2465 if (comp_ctx
->curr_func
.with_depth
> 0) {
2466 DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path"));
2471 * Any catch bindings ("catch (e)") also affect identifier binding.
2473 * Currently, the varmap is modified for the duration of the catch
2474 * clause to ensure any identifier accesses with the catch variable
2475 * name will use slow path.
2478 duk_get_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
);
2479 if (duk_is_number(ctx
, -1)) {
2480 ret
= duk_to_int(ctx
, -1);
2487 DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret
));
2491 DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path"));
2493 comp_ctx
->curr_func
.id_access_slow
= 1;
2494 return (duk_reg_t
) -1;
2497 /* Lookup an identifier name in the current varmap, indicating whether the
2498 * identifier is register-bound and if not, allocating a constant for the
2499 * identifier name. Returns 1 if register-bound, 0 otherwise. Caller can
2500 * also check (out_reg_varbind >= 0) to check whether or not identifier is
2501 * register bound. The caller must NOT use out_rc_varname at all unless
2502 * return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname
2503 * is unsigned and doesn't have a "unused" / none value.
2505 DUK_LOCAL duk_bool_t
duk__lookup_lhs(duk_compiler_ctx
*comp_ctx
, duk_reg_t
*out_reg_varbind
, duk_regconst_t
*out_rc_varname
) {
2506 duk_hthread
*thr
= comp_ctx
->thr
;
2507 duk_context
*ctx
= (duk_context
*) thr
;
2508 duk_reg_t reg_varbind
;
2509 duk_regconst_t rc_varname
;
2511 /* [ ... varname ] */
2514 reg_varbind
= duk__lookup_active_register_binding(comp_ctx
);
2516 if (reg_varbind
>= 0) {
2517 *out_reg_varbind
= reg_varbind
;
2518 *out_rc_varname
= 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */
2522 rc_varname
= duk__getconst(comp_ctx
);
2523 *out_reg_varbind
= -1;
2524 *out_rc_varname
= rc_varname
;
2532 * Labels are initially added with flags prohibiting both break and continue.
2533 * When the statement type is finally uncovered (after potentially multiple
2534 * labels), all the labels are updated to allow/prohibit break and continue.
2537 DUK_LOCAL
void duk__add_label(duk_compiler_ctx
*comp_ctx
, duk_hstring
*h_label
, duk_int_t pc_label
, duk_int_t label_id
) {
2538 duk_hthread
*thr
= comp_ctx
->thr
;
2539 duk_context
*ctx
= (duk_context
*) thr
;
2541 duk_size_t new_size
;
2543 duk_labelinfo
*li_start
, *li
;
2545 /* Duplicate (shadowing) labels are not allowed, except for the empty
2546 * labels (which are used as default labels for switch and iteration
2549 * We could also allow shadowing of non-empty pending labels without any
2550 * other issues than breaking the required label shadowing requirements
2551 * of the E5 specification, see Section 12.12.
2554 p
= (duk_uint8_t
*) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr
->heap
, comp_ctx
->curr_func
.h_labelinfos
);
2555 li_start
= (duk_labelinfo
*) (void *) p
;
2556 li
= (duk_labelinfo
*) (void *) (p
+ DUK_HBUFFER_GET_SIZE(comp_ctx
->curr_func
.h_labelinfos
));
2557 n
= (duk_size_t
) (li
- li_start
);
2559 while (li
> li_start
) {
2562 if (li
->h_label
== h_label
&& h_label
!= DUK_HTHREAD_STRING_EMPTY_STRING(thr
)) {
2563 DUK_ERROR_SYNTAX(thr
, DUK_STR_DUPLICATE_LABEL
);
2567 duk_push_hstring(ctx
, h_label
);
2568 DUK_ASSERT(n
<= DUK_UARRIDX_MAX
); /* label limits */
2569 (void) duk_put_prop_index(ctx
, comp_ctx
->curr_func
.labelnames_idx
, (duk_uarridx_t
) n
);
2571 new_size
= (n
+ 1) * sizeof(duk_labelinfo
);
2572 duk_hbuffer_resize(thr
, comp_ctx
->curr_func
.h_labelinfos
, new_size
);
2573 /* XXX: spare handling, slow now */
2575 /* relookup after possible realloc */
2576 p
= (duk_uint8_t
*) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr
->heap
, comp_ctx
->curr_func
.h_labelinfos
);
2577 li_start
= (duk_labelinfo
*) (void *) p
;
2578 DUK_UNREF(li_start
); /* silence scan-build warning */
2579 li
= (duk_labelinfo
*) (void *) (p
+ DUK_HBUFFER_GET_SIZE(comp_ctx
->curr_func
.h_labelinfos
));
2582 /* Labels can be used for iteration statements but also for other statements,
2583 * in particular a label can be used for a block statement. All cases of a
2584 * named label accept a 'break' so that flag is set here. Iteration statements
2585 * also allow 'continue', so that flag is updated when we figure out the
2589 li
->flags
= DUK_LABEL_FLAG_ALLOW_BREAK
;
2590 li
->label_id
= label_id
;
2591 li
->h_label
= h_label
;
2592 li
->catch_depth
= comp_ctx
->curr_func
.catch_depth
; /* catch depth from current func */
2593 li
->pc_label
= pc_label
;
2595 DUK_DDD(DUK_DDDPRINT("registered label: flags=0x%08lx, id=%ld, name=%!O, catch_depth=%ld, pc_label=%ld",
2596 (unsigned long) li
->flags
, (long) li
->label_id
, (duk_heaphdr
*) li
->h_label
,
2597 (long) li
->catch_depth
, (long) li
->pc_label
));
2600 /* Update all labels with matching label_id. */
2601 DUK_LOCAL
void duk__update_label_flags(duk_compiler_ctx
*comp_ctx
, duk_int_t label_id
, duk_small_uint_t flags
) {
2603 duk_labelinfo
*li_start
, *li
;
2605 p
= (duk_uint8_t
*) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(comp_ctx
->thr
->heap
, comp_ctx
->curr_func
.h_labelinfos
);
2606 li_start
= (duk_labelinfo
*) (void *) p
;
2607 li
= (duk_labelinfo
*) (void *) (p
+ DUK_HBUFFER_GET_SIZE(comp_ctx
->curr_func
.h_labelinfos
));
2609 /* Match labels starting from latest; once label_id no longer matches, we can
2610 * safely exit without checking the rest of the labels (only the topmost labels
2611 * are ever updated).
2613 while (li
> li_start
) {
2616 if (li
->label_id
!= label_id
) {
2620 DUK_DDD(DUK_DDDPRINT("updating (overwriting) label flags for li=%p, label_id=%ld, flags=%ld",
2621 (void *) li
, (long) label_id
, (long) flags
));
2627 /* Lookup active label information. Break/continue distinction is necessary to handle switch
2628 * statement related labels correctly: a switch will only catch a 'break', not a 'continue'.
2630 * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled
2631 * iteration and switch statements) can. A break will match the closest unlabelled or labelled
2632 * statement. A continue will match the closest unlabelled or labelled iteration statement. It is
2633 * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot
2634 * be duplicated, the continue cannot match any valid label outside the switch.
2636 * A side effect of these rules is that a LABEL statement related to a switch should never actually
2637 * catch a continue abrupt completion at run-time. Hence an INVALID opcode can be placed in the
2638 * continue slot of the switch's LABEL statement.
2641 /* XXX: awkward, especially the bunch of separate output values -> output struct? */
2642 DUK_LOCAL
void duk__lookup_active_label(duk_compiler_ctx
*comp_ctx
, duk_hstring
*h_label
, duk_bool_t is_break
, duk_int_t
*out_label_id
, duk_int_t
*out_label_catch_depth
, duk_int_t
*out_label_pc
, duk_bool_t
*out_is_closest
) {
2643 duk_hthread
*thr
= comp_ctx
->thr
;
2644 duk_context
*ctx
= (duk_context
*) thr
;
2646 duk_labelinfo
*li_start
, *li_end
, *li
;
2647 duk_bool_t match
= 0;
2649 DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
2650 (duk_heaphdr
*) h_label
, (long) is_break
));
2654 p
= (duk_uint8_t
*) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr
->heap
, comp_ctx
->curr_func
.h_labelinfos
);
2655 li_start
= (duk_labelinfo
*) (void *) p
;
2656 li_end
= (duk_labelinfo
*) (void *) (p
+ DUK_HBUFFER_GET_SIZE(comp_ctx
->curr_func
.h_labelinfos
));
2659 /* Match labels starting from latest label because there can be duplicate empty
2660 * labels in the label set.
2662 while (li
> li_start
) {
2665 if (li
->h_label
!= h_label
) {
2666 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] ->'%!O' != %!O",
2667 (long) (li
- li_start
),
2668 (duk_heaphdr
*) li
->h_label
,
2669 (duk_heaphdr
*) h_label
));
2673 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] -> '%!O' label name matches (still need to check type)",
2674 (long) (li
- li_start
), (duk_heaphdr
*) h_label
));
2676 /* currently all labels accept a break, so no explicit check for it now */
2677 DUK_ASSERT(li
->flags
& DUK_LABEL_FLAG_ALLOW_BREAK
);
2680 /* break matches always */
2683 } else if (li
->flags
& DUK_LABEL_FLAG_ALLOW_CONTINUE
) {
2684 /* iteration statements allow continue */
2688 /* continue matched this label -- we can only continue if this is the empty
2689 * label, for which duplication is allowed, and thus there is hope of
2690 * finding a match deeper in the label stack.
2692 if (h_label
!= DUK_HTHREAD_STRING_EMPTY_STRING(thr
)) {
2693 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_LABEL
);
2695 DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not "
2696 "allow a continue -> continue lookup deeper in label stack"));
2700 /* XXX: match flag is awkward, rework */
2702 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_LABEL
);
2705 DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld",
2706 (duk_heaphdr
*) h_label
, (long) li
->label_id
,
2707 (long) li
->catch_depth
, (long) li
->pc_label
));
2709 *out_label_id
= li
->label_id
;
2710 *out_label_catch_depth
= li
->catch_depth
;
2711 *out_label_pc
= li
->pc_label
;
2712 *out_is_closest
= (li
== li_end
- 1);
2715 DUK_LOCAL
void duk__reset_labels_to_length(duk_compiler_ctx
*comp_ctx
, duk_int_t len
) {
2716 duk_hthread
*thr
= comp_ctx
->thr
;
2717 duk_context
*ctx
= (duk_context
*) thr
;
2718 duk_size_t new_size
;
2720 /* XXX: duk_set_length */
2721 new_size
= sizeof(duk_labelinfo
) * (duk_size_t
) len
;
2722 duk_push_int(ctx
, len
);
2723 duk_put_prop_stridx(ctx
, comp_ctx
->curr_func
.labelnames_idx
, DUK_STRIDX_LENGTH
);
2724 duk_hbuffer_resize(thr
, comp_ctx
->curr_func
.h_labelinfos
, new_size
);
2728 * Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers.
2730 * - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal)
2731 * - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator)
2732 * - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token
2735 /* object literal key tracking flags */
2736 #define DUK__OBJ_LIT_KEY_PLAIN (1 << 0) /* key encountered as a plain property */
2737 #define DUK__OBJ_LIT_KEY_GET (1 << 1) /* key encountered as a getter */
2738 #define DUK__OBJ_LIT_KEY_SET (1 << 2) /* key encountered as a setter */
2740 DUK_LOCAL
void duk__nud_array_literal(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
2741 duk_hthread
*thr
= comp_ctx
->thr
;
2742 duk_reg_t reg_obj
; /* result reg */
2743 duk_reg_t reg_temp
; /* temp reg */
2744 duk_reg_t temp_start
; /* temp reg value for start of loop */
2745 duk_small_uint_t max_init_values
; /* max # of values initialized in one MPUTARR set */
2746 duk_small_uint_t num_values
; /* number of values in current MPUTARR set */
2747 duk_uarridx_t curr_idx
; /* current (next) array index */
2748 duk_uarridx_t start_idx
; /* start array index of current MPUTARR set */
2749 duk_uarridx_t init_idx
; /* last array index explicitly initialized, +1 */
2750 duk_bool_t require_comma
; /* next loop requires a comma */
2752 /* DUK_TOK_LBRACKET already eaten, current token is right after that */
2753 DUK_ASSERT(comp_ctx
->prev_token
.t
== DUK_TOK_LBRACKET
);
2755 max_init_values
= DUK__MAX_ARRAY_INIT_VALUES
; /* XXX: depend on available temps? */
2757 reg_obj
= DUK__ALLOCTEMP(comp_ctx
);
2758 duk__emit_extraop_b_c(comp_ctx
,
2759 DUK_EXTRAOP_NEWARR
| DUK__EMIT_FLAG_B_IS_TARGET
,
2761 0); /* XXX: patch initial size afterwards? */
2762 temp_start
= DUK__GETTEMP(comp_ctx
);
2765 * Emit initializers in sets of maximum max_init_values.
2766 * Corner cases such as single value initializers do not have
2767 * special handling now.
2769 * Elided elements must not be emitted as 'undefined' values,
2770 * because such values would be enumerable (which is incorrect).
2771 * Also note that trailing elisions must be reflected in the
2772 * length of the final array but cause no elements to be actually
2777 init_idx
= 0; /* tracks maximum initialized index + 1 */
2783 DUK__SETTEMP(comp_ctx
, temp_start
);
2785 if (comp_ctx
->curr_token
.t
== DUK_TOK_RBRACKET
) {
2790 if (comp_ctx
->curr_token
.t
== DUK_TOK_RBRACKET
) {
2791 /* the outer loop will recheck and exit */
2796 if (require_comma
) {
2797 if (comp_ctx
->curr_token
.t
== DUK_TOK_COMMA
) {
2798 /* comma after a value, expected */
2799 duk__advance(comp_ctx
);
2806 if (comp_ctx
->curr_token
.t
== DUK_TOK_COMMA
) {
2807 /* elision - flush */
2809 duk__advance(comp_ctx
);
2810 /* if num_values > 0, MPUTARR emitted by outer loop after break */
2814 /* else an array initializer element */
2817 if (num_values
== 0) {
2818 start_idx
= curr_idx
;
2819 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
2820 duk__emit_load_int32(comp_ctx
, reg_temp
, (duk_int32_t
) start_idx
);
2823 reg_temp
= DUK__ALLOCTEMP(comp_ctx
); /* alloc temp just in case, to update max temp */
2824 DUK__SETTEMP(comp_ctx
, reg_temp
);
2825 duk__expr_toforcedreg(comp_ctx
, res
, DUK__BP_COMMA
/*rbp_flags*/, reg_temp
/*forced_reg*/);
2826 DUK__SETTEMP(comp_ctx
, reg_temp
+ 1);
2832 if (num_values
>= max_init_values
) {
2833 /* MPUTARR emitted by outer loop */
2838 if (num_values
> 0) {
2839 /* - A is a source register (it's not a write target, but used
2840 * to identify the target object) but can be shuffled.
2841 * - B cannot be shuffled normally because it identifies a range
2842 * of registers, the emitter has special handling for this
2843 * (the "no shuffle" flag must not be set).
2844 * - C is a non-register number and cannot be shuffled, but
2845 * never needs to be.
2847 duk__emit_a_b_c(comp_ctx
,
2849 DUK__EMIT_FLAG_NO_SHUFFLE_C
|
2850 DUK__EMIT_FLAG_A_IS_SOURCE
,
2851 (duk_regconst_t
) reg_obj
,
2852 (duk_regconst_t
) temp_start
,
2853 (duk_regconst_t
) num_values
);
2854 init_idx
= start_idx
+ num_values
;
2856 /* num_values and temp_start reset at top of outer loop */
2860 DUK_ASSERT(comp_ctx
->curr_token
.t
== DUK_TOK_RBRACKET
);
2861 duk__advance(comp_ctx
);
2863 DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld",
2864 (long) curr_idx
, (long) init_idx
));
2866 /* trailing elisions? */
2867 if (curr_idx
> init_idx
) {
2868 /* yes, must set array length explicitly */
2869 DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length"));
2870 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
2871 duk__emit_load_int32(comp_ctx
, reg_temp
, (duk_int_t
) curr_idx
);
2872 duk__emit_extraop_b_c(comp_ctx
,
2873 DUK_EXTRAOP_SETALEN
,
2874 (duk_regconst_t
) reg_obj
,
2875 (duk_regconst_t
) reg_temp
);
2878 DUK__SETTEMP(comp_ctx
, temp_start
);
2880 res
->t
= DUK_IVAL_PLAIN
;
2881 res
->x1
.t
= DUK_ISPEC_REGCONST
;
2882 res
->x1
.regconst
= (duk_regconst_t
) reg_obj
;
2886 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_ARRAY_LITERAL
);
2889 /* duplicate/invalid key checks; returns 1 if syntax error */
2890 DUK_LOCAL duk_bool_t
duk__nud_object_literal_key_check(duk_compiler_ctx
*comp_ctx
, duk_small_uint_t new_key_flags
) {
2891 duk_hthread
*thr
= comp_ctx
->thr
;
2892 duk_context
*ctx
= (duk_context
*) thr
;
2893 duk_small_uint_t key_flags
;
2895 /* [ ... key_obj key ] */
2897 DUK_ASSERT(duk_is_string(ctx
, -1));
2900 * 'key_obj' tracks keys encountered so far by associating an
2901 * integer with flags with already encountered keys. The checks
2902 * below implement E5 Section 11.1.5, step 4 for production:
2904 * PropertyNameAndValueList: PropertyNameAndValueList , PropertyAssignment
2907 duk_dup(ctx
, -1); /* [ ... key_obj key key ] */
2908 duk_get_prop(ctx
, -3); /* [ ... key_obj key val ] */
2909 key_flags
= duk_to_int(ctx
, -1);
2910 duk_pop(ctx
); /* [ ... key_obj key ] */
2912 if (new_key_flags
& DUK__OBJ_LIT_KEY_PLAIN
) {
2913 if ((key_flags
& DUK__OBJ_LIT_KEY_PLAIN
) && comp_ctx
->curr_func
.is_strict
) {
2915 DUK_DDD(DUK_DDDPRINT("duplicate key: plain key appears twice in strict mode"));
2918 if (key_flags
& (DUK__OBJ_LIT_KEY_GET
| DUK__OBJ_LIT_KEY_SET
)) {
2920 DUK_DDD(DUK_DDDPRINT("duplicate key: plain key encountered after setter/getter"));
2924 if (key_flags
& DUK__OBJ_LIT_KEY_PLAIN
) {
2926 DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered after plain key"));
2929 if (key_flags
& new_key_flags
) {
2931 DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered twice"));
2936 new_key_flags
|= key_flags
;
2937 DUK_DDD(DUK_DDDPRINT("setting/updating key %!T flags: 0x%08lx -> 0x%08lx",
2938 (duk_tval
*) duk_get_tval(ctx
, -1),
2939 (unsigned long) key_flags
,
2940 (unsigned long) new_key_flags
));
2942 duk_push_int(ctx
, new_key_flags
); /* [ ... key_obj key key flags ] */
2943 duk_put_prop(ctx
, -4); /* [ ... key_obj key ] */
2948 DUK_LOCAL
void duk__nud_object_literal(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
2949 duk_hthread
*thr
= comp_ctx
->thr
;
2950 duk_context
*ctx
= (duk_context
*) thr
;
2951 duk_reg_t reg_obj
; /* result reg */
2952 duk_reg_t reg_key
; /* temp reg for key literal */
2953 duk_reg_t reg_temp
; /* temp reg */
2954 duk_reg_t temp_start
; /* temp reg value for start of loop */
2955 duk_small_uint_t max_init_pairs
; /* max # of key-value pairs initialized in one MPUTOBJ set */
2956 duk_small_uint_t num_pairs
; /* number of pairs in current MPUTOBJ set */
2957 duk_bool_t first
; /* first value: comma must not precede the value */
2958 duk_bool_t is_set
, is_get
; /* temps */
2960 DUK_ASSERT(comp_ctx
->prev_token
.t
== DUK_TOK_LCURLY
);
2962 max_init_pairs
= DUK__MAX_OBJECT_INIT_PAIRS
; /* XXX: depend on available temps? */
2964 reg_obj
= DUK__ALLOCTEMP(comp_ctx
);
2965 duk__emit_extraop_b_c(comp_ctx
,
2966 DUK_EXTRAOP_NEWOBJ
| DUK__EMIT_FLAG_B_IS_TARGET
,
2968 0); /* XXX: patch initial size afterwards? */
2969 temp_start
= DUK__GETTEMP(comp_ctx
);
2971 /* temp object for tracking / detecting duplicate keys */
2972 duk_push_object(ctx
);
2975 * Emit initializers in sets of maximum max_init_pairs keys.
2976 * Setter/getter is handled separately and terminates the
2977 * current set of initializer values. Corner cases such as
2978 * single value initializers do not have special handling now.
2984 DUK__SETTEMP(comp_ctx
, temp_start
);
2986 if (comp_ctx
->curr_token
.t
== DUK_TOK_RCURLY
) {
2992 * Three possible element formats:
2993 * 1) PropertyName : AssignmentExpression
2994 * 2) get PropertyName () { FunctionBody }
2995 * 3) set PropertyName ( PropertySetParameterList ) { FunctionBody }
2997 * PropertyName can be IdentifierName (includes reserved words), a string
2998 * literal, or a number literal. Note that IdentifierName allows 'get' and
2999 * 'set' too, so we need to look ahead to the next token to distinguish:
3005 * { get foo() { return 1 } }
3006 * { get get() { return 1 } } // 'get' as getter propertyname
3008 * Finally, a trailing comma is allowed.
3010 * Key name is coerced to string at compile time (and ends up as a
3011 * a string constant) even for numeric keys (e.g. "{1:'foo'}").
3012 * These could be emitted using e.g. LDINT, but that seems hardly
3013 * worth the effort and would increase code size.
3016 DUK_DDD(DUK_DDDPRINT("object literal inner loop, curr_token->t = %ld",
3017 (long) comp_ctx
->curr_token
.t
));
3019 if (comp_ctx
->curr_token
.t
== DUK_TOK_RCURLY
) {
3020 /* the outer loop will recheck and exit */
3023 if (num_pairs
>= max_init_pairs
) {
3024 /* MPUTOBJ emitted by outer loop */
3031 if (comp_ctx
->curr_token
.t
!= DUK_TOK_COMMA
) {
3034 duk__advance(comp_ctx
);
3035 if (comp_ctx
->curr_token
.t
== DUK_TOK_RCURLY
) {
3036 /* trailing comma followed by rcurly */
3041 /* advance to get one step of lookup */
3042 duk__advance(comp_ctx
);
3044 /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
3045 * currently treats them always like ordinary identifiers (DUK_TOK_GET
3046 * and DUK_TOK_SET are unused). They need to be detected based on the
3047 * identifier string content.
3050 is_get
= (comp_ctx
->prev_token
.t
== DUK_TOK_IDENTIFIER
&&
3051 comp_ctx
->prev_token
.str1
== DUK_HTHREAD_STRING_GET(thr
));
3052 is_set
= (comp_ctx
->prev_token
.t
== DUK_TOK_IDENTIFIER
&&
3053 comp_ctx
->prev_token
.str1
== DUK_HTHREAD_STRING_SET(thr
));
3054 if ((is_get
|| is_set
) && comp_ctx
->curr_token
.t
!= DUK_TOK_COLON
) {
3058 if (comp_ctx
->curr_token
.t_nores
== DUK_TOK_IDENTIFIER
||
3059 comp_ctx
->curr_token
.t_nores
== DUK_TOK_STRING
) {
3060 /* same handling for identifiers and strings */
3061 DUK_ASSERT(comp_ctx
->curr_token
.str1
!= NULL
);
3062 duk_push_hstring(ctx
, comp_ctx
->curr_token
.str1
);
3063 } else if (comp_ctx
->curr_token
.t
== DUK_TOK_NUMBER
) {
3064 duk_push_number(ctx
, comp_ctx
->curr_token
.num
);
3065 duk_to_string(ctx
, -1);
3070 DUK_ASSERT(duk_is_string(ctx
, -1));
3071 if (duk__nud_object_literal_key_check(comp_ctx
,
3072 (is_get
? DUK__OBJ_LIT_KEY_GET
: DUK__OBJ_LIT_KEY_SET
))) {
3075 reg_key
= duk__getconst(comp_ctx
);
3077 if (num_pairs
> 0) {
3078 /* - A is a source register (it's not a write target, but used
3079 * to identify the target object) but can be shuffled.
3080 * - B cannot be shuffled normally because it identifies a range
3081 * of registers, the emitter has special handling for this
3082 * (the "no shuffle" flag must not be set).
3083 * - C is a non-register number and cannot be shuffled, but
3084 * never needs to be.
3086 duk__emit_a_b_c(comp_ctx
,
3088 DUK__EMIT_FLAG_NO_SHUFFLE_C
|
3089 DUK__EMIT_FLAG_A_IS_SOURCE
,
3094 DUK__SETTEMP(comp_ctx
, temp_start
);
3097 /* curr_token = get/set name */
3098 fnum
= duk__parse_func_like_fnum(comp_ctx
, 0 /*is_decl*/, 1 /*is_setget*/);
3100 DUK_ASSERT(DUK__GETTEMP(comp_ctx
) == temp_start
);
3101 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
3102 duk__emit_a_bc(comp_ctx
,
3104 (duk_regconst_t
) reg_temp
,
3105 (duk_regconst_t
) reg_key
);
3106 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
3107 duk__emit_a_bc(comp_ctx
,
3109 (duk_regconst_t
) reg_temp
,
3110 (duk_regconst_t
) fnum
);
3112 /* Slot C is used in a non-standard fashion (range of regs),
3113 * emitter code has special handling for it (must not set the
3114 * "no shuffle" flag).
3116 duk__emit_extraop_b_c(comp_ctx
,
3117 (is_get
? DUK_EXTRAOP_INITGET
: DUK_EXTRAOP_INITSET
),
3119 temp_start
); /* temp_start+0 = key, temp_start+1 = closure */
3121 DUK__SETTEMP(comp_ctx
, temp_start
);
3123 /* normal key/value */
3124 if (comp_ctx
->prev_token
.t_nores
== DUK_TOK_IDENTIFIER
||
3125 comp_ctx
->prev_token
.t_nores
== DUK_TOK_STRING
) {
3126 /* same handling for identifiers and strings */
3127 DUK_ASSERT(comp_ctx
->prev_token
.str1
!= NULL
);
3128 duk_push_hstring(ctx
, comp_ctx
->prev_token
.str1
);
3129 } else if (comp_ctx
->prev_token
.t
== DUK_TOK_NUMBER
) {
3130 duk_push_number(ctx
, comp_ctx
->prev_token
.num
);
3131 duk_to_string(ctx
, -1);
3136 DUK_ASSERT(duk_is_string(ctx
, -1));
3137 if (duk__nud_object_literal_key_check(comp_ctx
, DUK__OBJ_LIT_KEY_PLAIN
)) {
3140 reg_key
= duk__getconst(comp_ctx
);
3142 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
3143 duk__emit_a_bc(comp_ctx
,
3145 (duk_regconst_t
) reg_temp
,
3146 (duk_regconst_t
) reg_key
);
3147 duk__advance_expect(comp_ctx
, DUK_TOK_COLON
);
3149 reg_temp
= DUK__ALLOCTEMP(comp_ctx
); /* alloc temp just in case, to update max temp */
3150 DUK__SETTEMP(comp_ctx
, reg_temp
);
3151 duk__expr_toforcedreg(comp_ctx
, res
, DUK__BP_COMMA
/*rbp_flags*/, reg_temp
/*forced_reg*/);
3152 DUK__SETTEMP(comp_ctx
, reg_temp
+ 1);
3158 if (num_pairs
> 0) {
3159 /* See MPUTOBJ comments above. */
3160 duk__emit_a_b_c(comp_ctx
,
3162 DUK__EMIT_FLAG_NO_SHUFFLE_C
|
3163 DUK__EMIT_FLAG_A_IS_SOURCE
,
3168 /* num_pairs and temp_start reset at top of outer loop */
3172 DUK_ASSERT(comp_ctx
->curr_token
.t
== DUK_TOK_RCURLY
);
3173 duk__advance(comp_ctx
);
3175 DUK__SETTEMP(comp_ctx
, temp_start
);
3177 res
->t
= DUK_IVAL_PLAIN
;
3178 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3179 res
->x1
.regconst
= (duk_regconst_t
) reg_obj
;
3181 DUK_DDD(DUK_DDDPRINT("final tracking object: %!T",
3182 (duk_tval
*) duk_get_tval(ctx
, -1)));
3187 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_OBJECT_LITERAL
);
3190 /* Parse argument list. Arguments are written to temps starting from
3191 * "next temp". Returns number of arguments parsed. Expects left paren
3192 * to be already eaten, and eats the right paren before returning.
3194 DUK_LOCAL duk_int_t
duk__parse_arguments(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
3195 duk_int_t nargs
= 0;
3198 /* Note: expect that caller has already eaten the left paren */
3200 DUK_DDD(DUK_DDDPRINT("start parsing arguments, prev_token.t=%ld, curr_token.t=%ld",
3201 (long) comp_ctx
->prev_token
.t
, (long) comp_ctx
->curr_token
.t
));
3204 if (comp_ctx
->curr_token
.t
== DUK_TOK_RPAREN
) {
3208 duk__advance_expect(comp_ctx
, DUK_TOK_COMMA
);
3211 /* We want the argument expression value to go to "next temp"
3212 * without additional moves. That should almost always be the
3213 * case, but we double check after expression parsing.
3215 * This is not the cleanest possible approach.
3218 reg_temp
= DUK__ALLOCTEMP(comp_ctx
); /* bump up "allocated" reg count, just in case */
3219 DUK__SETTEMP(comp_ctx
, reg_temp
);
3221 /* binding power must be high enough to NOT allow comma expressions directly */
3222 duk__expr_toforcedreg(comp_ctx
, res
, DUK__BP_COMMA
/*rbp_flags*/, reg_temp
); /* always allow 'in', coerce to 'tr' just in case */
3224 DUK__SETTEMP(comp_ctx
, reg_temp
+ 1);
3227 DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld", (long) nargs
, (long) reg_temp
));
3230 /* eat the right paren */
3231 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
3233 DUK_DDD(DUK_DDDPRINT("end parsing arguments"));
3238 DUK_LOCAL duk_bool_t
duk__expr_is_empty(duk_compiler_ctx
*comp_ctx
) {
3239 /* empty expressions can be detected conveniently with nud/led counts */
3240 return (comp_ctx
->curr_func
.nud_count
== 0) &&
3241 (comp_ctx
->curr_func
.led_count
== 0);
3244 DUK_LOCAL
void duk__expr_nud(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
3245 duk_hthread
*thr
= comp_ctx
->thr
;
3246 duk_context
*ctx
= (duk_context
*) thr
;
3248 duk_reg_t temp_at_entry
;
3249 duk_small_int_t tok
;
3250 duk_uint32_t args
; /* temp variable to pass constants and flags to shared code */
3253 * ctx->prev_token token to process with duk__expr_nud()
3254 * ctx->curr_token updated by caller
3256 * Note: the token in the switch below has already been eaten.
3259 temp_at_entry
= DUK__GETTEMP(comp_ctx
);
3261 comp_ctx
->curr_func
.nud_count
++;
3263 tk
= &comp_ctx
->prev_token
;
3265 res
->t
= DUK_IVAL_NONE
;
3267 DUK_DDD(DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
3268 (long) tk
->t
, (long) comp_ctx
->curr_func
.allow_in
, (long) comp_ctx
->curr_func
.paren_level
));
3272 /* PRIMARY EXPRESSIONS */
3274 case DUK_TOK_THIS
: {
3276 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
3277 duk__emit_extraop_bc(comp_ctx
,
3279 (duk_regconst_t
) reg_temp
);
3280 res
->t
= DUK_IVAL_PLAIN
;
3281 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3282 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
3285 case DUK_TOK_IDENTIFIER
: {
3286 res
->t
= DUK_IVAL_VAR
;
3287 res
->x1
.t
= DUK_ISPEC_VALUE
;
3288 duk_push_hstring(ctx
, tk
->str1
);
3289 duk_replace(ctx
, res
->x1
.valstack_idx
);
3292 case DUK_TOK_NULL
: {
3296 case DUK_TOK_TRUE
: {
3300 case DUK_TOK_FALSE
: {
3301 duk_push_false(ctx
);
3304 case DUK_TOK_NUMBER
: {
3305 duk_push_number(ctx
, tk
->num
);
3308 case DUK_TOK_STRING
: {
3309 DUK_ASSERT(tk
->str1
!= NULL
);
3310 duk_push_hstring(ctx
, tk
->str1
);
3313 case DUK_TOK_REGEXP
: {
3314 #ifdef DUK_USE_REGEXP_SUPPORT
3316 duk_regconst_t rc_re_bytecode
; /* const */
3317 duk_regconst_t rc_re_source
; /* const */
3319 DUK_ASSERT(tk
->str1
!= NULL
);
3320 DUK_ASSERT(tk
->str2
!= NULL
);
3322 DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O",
3323 (duk_heaphdr
*) tk
->str1
,
3324 (duk_heaphdr
*) tk
->str2
));
3326 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
3327 duk_push_hstring(ctx
, tk
->str1
);
3328 duk_push_hstring(ctx
, tk
->str2
);
3330 /* [ ... pattern flags ] */
3332 duk_regexp_compile(thr
);
3334 /* [ ... escaped_source bytecode ] */
3336 rc_re_bytecode
= duk__getconst(comp_ctx
);
3337 rc_re_source
= duk__getconst(comp_ctx
);
3339 duk__emit_a_b_c(comp_ctx
,
3341 (duk_regconst_t
) reg_temp
/*a*/,
3342 rc_re_bytecode
/*b*/,
3343 rc_re_source
/*c*/);
3345 res
->t
= DUK_IVAL_PLAIN
;
3346 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3347 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
3349 #else /* DUK_USE_REGEXP_SUPPORT */
3351 #endif /* DUK_USE_REGEXP_SUPPORT */
3353 case DUK_TOK_LBRACKET
: {
3354 DUK_DDD(DUK_DDDPRINT("parsing array literal"));
3355 duk__nud_array_literal(comp_ctx
, res
);
3358 case DUK_TOK_LCURLY
: {
3359 DUK_DDD(DUK_DDDPRINT("parsing object literal"));
3360 duk__nud_object_literal(comp_ctx
, res
);
3363 case DUK_TOK_LPAREN
: {
3364 duk_bool_t prev_allow_in
;
3366 comp_ctx
->curr_func
.paren_level
++;
3367 prev_allow_in
= comp_ctx
->curr_func
.allow_in
;
3368 comp_ctx
->curr_func
.allow_in
= 1; /* reset 'allow_in' for parenthesized expression */
3370 duk__expr(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/); /* Expression, terminates at a ')' */
3372 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
3373 comp_ctx
->curr_func
.allow_in
= prev_allow_in
;
3374 comp_ctx
->curr_func
.paren_level
--;
3378 /* MEMBER/NEW/CALL EXPRESSIONS */
3382 * Parsing an expression starting with 'new' is tricky because
3383 * there are multiple possible productions deriving from
3384 * LeftHandSideExpression which begin with 'new'.
3386 * We currently resort to one-token lookahead to distinguish the
3387 * cases. Hopefully this is correct. The binding power must be
3388 * such that parsing ends at an LPAREN (CallExpression) but not at
3389 * a PERIOD or LBRACKET (MemberExpression).
3391 * See doc/compiler.rst for discussion on the parsing approach,
3392 * and testcases/test-dev-new.js for a bunch of documented tests.
3395 duk_reg_t reg_target
;
3398 DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
3400 reg_target
= DUK__ALLOCTEMP(comp_ctx
);
3401 duk__expr_toforcedreg(comp_ctx
, res
, DUK__BP_CALL
/*rbp_flags*/, reg_target
/*forced_reg*/);
3402 DUK__SETTEMP(comp_ctx
, reg_target
+ 1);
3404 if (comp_ctx
->curr_token
.t
== DUK_TOK_LPAREN
) {
3405 /* 'new' MemberExpression Arguments */
3406 DUK_DDD(DUK_DDDPRINT("new expression has argument list"));
3407 duk__advance(comp_ctx
);
3408 nargs
= duk__parse_arguments(comp_ctx
, res
); /* parse args starting from "next temp", reg_target + 1 */
3409 /* right paren eaten */
3411 /* 'new' MemberExpression */
3412 DUK_DDD(DUK_DDDPRINT("new expression has no argument list"));
3416 /* Opcode slot C is used in a non-standard way, so shuffling
3419 duk__emit_a_b_c(comp_ctx
,
3420 DUK_OP_NEW
| DUK__EMIT_FLAG_NO_SHUFFLE_A
| DUK__EMIT_FLAG_NO_SHUFFLE_C
,
3422 reg_target
/*target*/,
3423 nargs
/*num_args*/);
3425 DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
3427 res
->t
= DUK_IVAL_PLAIN
;
3428 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3429 res
->x1
.regconst
= (duk_regconst_t
) reg_target
;
3433 /* FUNCTION EXPRESSIONS */
3435 case DUK_TOK_FUNCTION
: {
3436 /* Function expression. Note that any statement beginning with 'function'
3437 * is handled by the statement parser as a function declaration, or a
3438 * non-standard function expression/statement (or a SyntaxError). We only
3439 * handle actual function expressions (occurring inside an expression) here.
3441 * O(depth^2) parse count for inner functions is handled by recording a
3442 * lexer offset on the first compilation pass, so that the function can
3443 * be efficiently skipped on the second pass. This is encapsulated into
3444 * duk__parse_func_like_fnum().
3450 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
3452 /* curr_token follows 'function' */
3453 fnum
= duk__parse_func_like_fnum(comp_ctx
, 0 /*is_decl*/, 0 /*is_setget*/);
3454 DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld", (long) fnum
));
3456 duk__emit_a_bc(comp_ctx
,
3458 (duk_regconst_t
) reg_temp
/*a*/,
3459 (duk_regconst_t
) fnum
/*bc*/);
3461 res
->t
= DUK_IVAL_PLAIN
;
3462 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3463 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
3467 /* UNARY EXPRESSIONS */
3469 case DUK_TOK_DELETE
: {
3470 /* Delete semantics are a bit tricky. The description in E5 specification
3471 * is kind of confusing, because it distinguishes between resolvability of
3472 * a reference (which is only known at runtime) seemingly at compile time
3473 * (= SyntaxError throwing).
3475 duk__expr(comp_ctx
, res
, DUK__BP_MULTIPLICATIVE
/*rbp_flags*/); /* UnaryExpression */
3476 if (res
->t
== DUK_IVAL_VAR
) {
3477 /* not allowed in strict mode, regardless of whether resolves;
3478 * in non-strict mode DELVAR handles both non-resolving and
3479 * resolving cases (the specification description is a bit confusing).
3483 duk_reg_t reg_varbind
;
3484 duk_regconst_t rc_varname
;
3486 if (comp_ctx
->curr_func
.is_strict
) {
3487 DUK_ERROR_SYNTAX(thr
, DUK_STR_CANNOT_DELETE_IDENTIFIER
);
3490 DUK__SETTEMP(comp_ctx
, temp_at_entry
);
3491 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
3493 duk_dup(ctx
, res
->x1
.valstack_idx
);
3494 if (duk__lookup_lhs(comp_ctx
, ®_varbind
, &rc_varname
)) {
3495 /* register bound variables are non-configurable -> always false */
3496 duk__emit_extraop_bc(comp_ctx
,
3497 DUK_EXTRAOP_LDFALSE
,
3498 (duk_regconst_t
) reg_temp
);
3500 duk_dup(ctx
, res
->x1
.valstack_idx
);
3501 rc_varname
= duk__getconst(comp_ctx
);
3502 duk__emit_a_b(comp_ctx
,
3504 (duk_regconst_t
) reg_temp
,
3505 (duk_regconst_t
) rc_varname
);
3507 res
->t
= DUK_IVAL_PLAIN
;
3508 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3509 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
3510 } else if (res
->t
== DUK_IVAL_PROP
) {
3513 duk_regconst_t rc_key
;
3515 DUK__SETTEMP(comp_ctx
, temp_at_entry
);
3516 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
3517 reg_obj
= duk__ispec_toregconst_raw(comp_ctx
, &res
->x1
, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
3518 rc_key
= duk__ispec_toregconst_raw(comp_ctx
, &res
->x2
, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST
/*flags*/);
3519 duk__emit_a_b_c(comp_ctx
,
3521 (duk_regconst_t
) reg_temp
,
3522 (duk_regconst_t
) reg_obj
,
3525 res
->t
= DUK_IVAL_PLAIN
;
3526 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3527 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
3529 /* non-Reference deletion is always 'true', even in strict mode */
3535 case DUK_TOK_VOID
: {
3536 duk__expr_toplain_ignore(comp_ctx
, res
, DUK__BP_MULTIPLICATIVE
/*rbp_flags*/); /* UnaryExpression */
3537 duk_push_undefined(ctx
);
3540 case DUK_TOK_TYPEOF
: {
3541 /* 'typeof' must handle unresolvable references without throwing
3542 * a ReferenceError (E5 Section 11.4.3). Register mapped values
3543 * will never be unresolvable so special handling is only required
3544 * when an identifier is a "slow path" one.
3546 duk__expr(comp_ctx
, res
, DUK__BP_MULTIPLICATIVE
/*rbp_flags*/); /* UnaryExpression */
3548 if (res
->t
== DUK_IVAL_VAR
) {
3549 duk_reg_t reg_varbind
;
3550 duk_regconst_t rc_varname
;
3553 duk_dup(ctx
, res
->x1
.valstack_idx
);
3554 if (!duk__lookup_lhs(comp_ctx
, ®_varbind
, &rc_varname
)) {
3555 DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
3556 "at compile time, need to use special run-time handling"));
3557 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
3558 duk__emit_extraop_b_c(comp_ctx
,
3559 DUK_EXTRAOP_TYPEOFID
| DUK__EMIT_FLAG_B_IS_TARGET
,
3562 res
->t
= DUK_IVAL_PLAIN
;
3563 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3564 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
3569 args
= (DUK_EXTRAOP_TYPEOF
<< 8) + 0;
3572 case DUK_TOK_INCREMENT
: {
3573 args
= (DUK_OP_PREINCR
<< 8) + 0;
3576 case DUK_TOK_DECREMENT
: {
3577 args
= (DUK_OP_PREDECR
<< 8) + 0;
3582 duk__expr(comp_ctx
, res
, DUK__BP_MULTIPLICATIVE
/*rbp_flags*/); /* UnaryExpression */
3583 if (res
->t
== DUK_IVAL_PLAIN
&& res
->x1
.t
== DUK_ISPEC_VALUE
&&
3584 duk_is_number(ctx
, res
->x1
.valstack_idx
)) {
3585 /* unary plus of a number is identity */
3589 args
= (DUK_EXTRAOP_UNP
<< 8) + 0;
3594 duk__expr(comp_ctx
, res
, DUK__BP_MULTIPLICATIVE
/*rbp_flags*/); /* UnaryExpression */
3595 if (res
->t
== DUK_IVAL_PLAIN
&& res
->x1
.t
== DUK_ISPEC_VALUE
&&
3596 duk_is_number(ctx
, res
->x1
.valstack_idx
)) {
3597 /* this optimization is important to handle negative literals
3598 * (which are not directly provided by the lexical grammar)
3601 duk_double_union du
;
3603 tv_num
= DUK_GET_TVAL_POSIDX(ctx
, res
->x1
.valstack_idx
);
3604 DUK_ASSERT(tv_num
!= NULL
);
3605 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num
));
3606 du
.d
= DUK_TVAL_GET_NUMBER(tv_num
);
3608 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du
);
3609 DUK_TVAL_SET_NUMBER(tv_num
, du
.d
);
3612 args
= (DUK_EXTRAOP_UNM
<< 8) + 0;
3615 case DUK_TOK_BNOT
: {
3616 duk__expr(comp_ctx
, res
, DUK__BP_MULTIPLICATIVE
/*rbp_flags*/); /* UnaryExpression */
3617 args
= (DUK_EXTRAOP_BNOT
<< 8) + 0;
3620 case DUK_TOK_LNOT
: {
3621 duk__expr(comp_ctx
, res
, DUK__BP_MULTIPLICATIVE
/*rbp_flags*/); /* UnaryExpression */
3622 if (res
->t
== DUK_IVAL_PLAIN
&& res
->x1
.t
== DUK_ISPEC_VALUE
) {
3623 /* Very minimal inlining to handle common idioms '!0' and '!1',
3624 * and also boolean arguments like '!false' and '!true'.
3628 tv_val
= DUK_GET_TVAL_POSIDX(ctx
, res
->x1
.valstack_idx
);
3629 DUK_ASSERT(tv_val
!= NULL
);
3630 if (DUK_TVAL_IS_NUMBER(tv_val
)) {
3632 d
= DUK_TVAL_GET_NUMBER(tv_val
);
3634 /* Matches both +0 and -0 on purpose. */
3635 DUK_DDD(DUK_DDDPRINT("inlined lnot: !0 -> true"));
3636 DUK_TVAL_SET_BOOLEAN_TRUE(tv_val
);
3638 } else if (d
== 1.0) {
3639 DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false"));
3640 DUK_TVAL_SET_BOOLEAN_FALSE(tv_val
);
3643 } else if (DUK_TVAL_IS_BOOLEAN(tv_val
)) {
3645 v
= DUK_TVAL_GET_BOOLEAN(tv_val
);
3646 DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v
));
3647 DUK_ASSERT(v
== 0 || v
== 1);
3648 DUK_TVAL_SET_BOOLEAN(tv_val
, v
^ 0x01);
3652 args
= (DUK_EXTRAOP_LNOT
<< 8) + 0;
3658 DUK_ERROR_SYNTAX(thr
, DUK_STR_PARSE_ERROR
);
3663 /* Note: must coerce to a (writable) temp register, so that e.g. "!x" where x
3664 * is a reg-mapped variable works correctly (does not mutate the variable register).
3668 reg_temp
= duk__ivalue_toregconst_raw(comp_ctx
, res
, -1 /*forced_reg*/, DUK__IVAL_FLAG_REQUIRE_TEMP
/*flags*/);
3669 duk__emit_extraop_bc(comp_ctx
,
3671 (duk_regconst_t
) reg_temp
);
3672 res
->t
= DUK_IVAL_PLAIN
;
3673 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3674 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
3680 /* preincrement and predecrement */
3682 duk_small_uint_t args_op
= args
>> 8;
3684 /* Specific assumptions for opcode numbering. */
3685 DUK_ASSERT(DUK_OP_PREINCR
+ 4 == DUK_OP_PREINCV
);
3686 DUK_ASSERT(DUK_OP_PREDECR
+ 4 == DUK_OP_PREDECV
);
3687 DUK_ASSERT(DUK_OP_PREINCR
+ 8 == DUK_OP_PREINCP
);
3688 DUK_ASSERT(DUK_OP_PREDECR
+ 8 == DUK_OP_PREDECP
);
3690 reg_res
= DUK__ALLOCTEMP(comp_ctx
);
3692 duk__expr(comp_ctx
, res
, DUK__BP_MULTIPLICATIVE
/*rbp_flags*/); /* UnaryExpression */
3693 if (res
->t
== DUK_IVAL_VAR
) {
3694 duk_hstring
*h_varname
;
3695 duk_reg_t reg_varbind
;
3696 duk_regconst_t rc_varname
;
3698 h_varname
= duk_get_hstring(ctx
, res
->x1
.valstack_idx
);
3699 DUK_ASSERT(h_varname
!= NULL
);
3701 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx
, h_varname
)) {
3705 duk_dup(ctx
, res
->x1
.valstack_idx
);
3706 if (duk__lookup_lhs(comp_ctx
, ®_varbind
, &rc_varname
)) {
3707 duk__emit_a_bc(comp_ctx
,
3708 args_op
, /* e.g. DUK_OP_PREINCR */
3709 (duk_regconst_t
) reg_res
,
3710 (duk_regconst_t
) reg_varbind
);
3712 duk__emit_a_bc(comp_ctx
,
3713 args_op
+ 4, /* e.g. DUK_OP_PREINCV */
3714 (duk_regconst_t
) reg_res
,
3718 DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
3719 (duk_heaphdr
*) h_varname
, (long) reg_varbind
, (long) rc_varname
));
3720 } else if (res
->t
== DUK_IVAL_PROP
) {
3721 duk_reg_t reg_obj
; /* allocate to reg only (not const) */
3722 duk_regconst_t rc_key
;
3723 reg_obj
= duk__ispec_toregconst_raw(comp_ctx
, &res
->x1
, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
3724 rc_key
= duk__ispec_toregconst_raw(comp_ctx
, &res
->x2
, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST
/*flags*/);
3725 duk__emit_a_b_c(comp_ctx
,
3726 args_op
+ 8, /* e.g. DUK_OP_PREINCP */
3727 (duk_regconst_t
) reg_res
,
3728 (duk_regconst_t
) reg_obj
,
3731 /* Technically return value is not needed because INVLHS will
3732 * unconditially throw a ReferenceError. Coercion is necessary
3733 * for proper semantics (consider ToNumber() called for an object).
3734 * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
3737 duk__ivalue_toforcedreg(comp_ctx
, res
, reg_res
);
3738 duk__emit_extraop_bc(comp_ctx
,
3740 reg_res
); /* for side effects, result ignored */
3741 duk__emit_extraop_only(comp_ctx
,
3742 DUK_EXTRAOP_INVLHS
);
3744 res
->t
= DUK_IVAL_PLAIN
;
3745 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3746 res
->x1
.regconst
= (duk_regconst_t
) reg_res
;
3747 DUK__SETTEMP(comp_ctx
, reg_res
+ 1);
3753 /* Stack top contains plain value */
3754 res
->t
= DUK_IVAL_PLAIN
;
3755 res
->x1
.t
= DUK_ISPEC_VALUE
;
3756 duk_replace(ctx
, res
->x1
.valstack_idx
);
3761 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_EXPRESSION
);
3764 /* XXX: add flag to indicate whether caller cares about return value; this
3765 * affects e.g. handling of assignment expressions. This change needs API
3766 * changes elsewhere too.
3768 DUK_LOCAL
void duk__expr_led(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*left
, duk_ivalue
*res
) {
3769 duk_hthread
*thr
= comp_ctx
->thr
;
3770 duk_context
*ctx
= (duk_context
*) thr
;
3772 duk_small_int_t tok
;
3773 duk_uint32_t args
; /* temp variable to pass constants and flags to shared code */
3776 * ctx->prev_token token to process with duk__expr_led()
3777 * ctx->curr_token updated by caller
3780 comp_ctx
->curr_func
.led_count
++;
3782 /* The token in the switch has already been eaten here */
3783 tk
= &comp_ctx
->prev_token
;
3786 DUK_DDD(DUK_DDDPRINT("duk__expr_led(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
3787 (long) tk
->t
, (long) comp_ctx
->curr_func
.allow_in
, (long) comp_ctx
->curr_func
.paren_level
));
3789 /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */
3793 /* PRIMARY EXPRESSIONS */
3795 case DUK_TOK_PERIOD
: {
3796 /* Property access expressions are critical for correct LHS ordering,
3797 * see comments in duk__expr()!
3799 * A conservative approach would be to use duk__ivalue_totempconst()
3800 * for 'left'. However, allowing a reg-bound variable seems safe here
3801 * and is nice because "foo.bar" is a common expression. If the ivalue
3802 * is used in an expression a GETPROP will occur before any changes to
3803 * the base value can occur. If the ivalue is used as an assignment
3804 * LHS, the assignment code will ensure the base value is safe from
3808 /* XXX: This now coerces an identifier into a GETVAR to a temp, which
3809 * causes an extra LDREG in call setup. It's sufficient to coerce to a
3812 duk__ivalue_toplain(comp_ctx
, left
);
3814 /* NB: must accept reserved words as property name */
3815 if (comp_ctx
->curr_token
.t_nores
!= DUK_TOK_IDENTIFIER
) {
3816 DUK_ERROR_SYNTAX(thr
, DUK_STR_EXPECTED_IDENTIFIER
);
3819 res
->t
= DUK_IVAL_PROP
;
3820 duk__copy_ispec(comp_ctx
, &left
->x1
, &res
->x1
); /* left.x1 -> res.x1 */
3821 DUK_ASSERT(comp_ctx
->curr_token
.str1
!= NULL
);
3822 duk_push_hstring(ctx
, comp_ctx
->curr_token
.str1
);
3823 duk_replace(ctx
, res
->x2
.valstack_idx
);
3824 res
->x2
.t
= DUK_ISPEC_VALUE
;
3826 /* special RegExp literal handling after IdentifierName */
3827 comp_ctx
->curr_func
.reject_regexp_in_adv
= 1;
3829 duk__advance(comp_ctx
);
3832 case DUK_TOK_LBRACKET
: {
3833 /* Property access expressions are critical for correct LHS ordering,
3834 * see comments in duk__expr()!
3837 /* XXX: optimize temp reg use */
3838 /* XXX: similar coercion issue as in DUK_TOK_PERIOD */
3839 /* XXX: coerce to regs? it might be better for enumeration use, where the
3840 * same PROP ivalue is used multiple times. Or perhaps coerce PROP further
3843 /* XXX: for simple cases like x['y'] an unnecessary LDREG is
3844 * emitted for the base value; could avoid it if we knew that
3845 * the key expression is safe (e.g. just a single literal).
3848 /* The 'left' value must not be a register bound variable
3849 * because it may be mutated during the rest of the expression
3850 * and E5.1 Section 11.2.1 specifies the order of evaluation
3851 * so that the base value is evaluated first.
3852 * See: test-bug-nested-prop-mutate.js.
3854 duk__ivalue_totempconst(comp_ctx
, left
);
3855 duk__expr_toplain(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/); /* Expression, ']' terminates */
3856 duk__advance_expect(comp_ctx
, DUK_TOK_RBRACKET
);
3858 res
->t
= DUK_IVAL_PROP
;
3859 duk__copy_ispec(comp_ctx
, &res
->x1
, &res
->x2
); /* res.x1 -> res.x2 */
3860 duk__copy_ispec(comp_ctx
, &left
->x1
, &res
->x1
); /* left.x1 -> res.x1 */
3863 case DUK_TOK_LPAREN
: {
3865 duk_reg_t reg_cs
= DUK__ALLOCTEMPS(comp_ctx
, 2);
3867 duk_small_uint_t call_flags
= 0;
3870 * XXX: attempt to get the call result to "next temp" whenever
3871 * possible to avoid unnecessary register shuffles.
3873 * XXX: CSPROP (and CSREG) can overwrite the call target register, and save one temp,
3874 * if the call target is a temporary register and at the top of the temp reg "stack".
3878 * Setup call: target and 'this' binding. Three cases:
3880 * 1. Identifier base (e.g. "foo()")
3881 * 2. Property base (e.g. "foo.bar()")
3882 * 3. Register base (e.g. "foo()()"; i.e. when a return value is a function)
3885 if (left
->t
== DUK_IVAL_VAR
) {
3886 duk_hstring
*h_varname
;
3887 duk_reg_t reg_varbind
;
3888 duk_regconst_t rc_varname
;
3890 DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
3892 h_varname
= duk_get_hstring(ctx
, left
->x1
.valstack_idx
);
3893 DUK_ASSERT(h_varname
!= NULL
);
3894 if (h_varname
== DUK_HTHREAD_STRING_EVAL(thr
)) {
3895 /* Potential direct eval call detected, flag the CALL
3896 * so that a run-time "direct eval" check is made and
3897 * special behavior may be triggered. Note that this
3898 * does not prevent 'eval' from being register bound.
3900 DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' "
3901 "-> enabling EVALCALL flag, marking function "
3902 "as may_direct_eval"));
3903 call_flags
|= DUK_BC_CALL_FLAG_EVALCALL
;
3905 comp_ctx
->curr_func
.may_direct_eval
= 1;
3908 duk_dup(ctx
, left
->x1
.valstack_idx
);
3909 if (duk__lookup_lhs(comp_ctx
, ®_varbind
, &rc_varname
)) {
3910 duk__emit_a_b(comp_ctx
,
3912 (duk_regconst_t
) (reg_cs
+ 0),
3913 (duk_regconst_t
) reg_varbind
);
3915 duk__emit_a_b(comp_ctx
,
3917 (duk_regconst_t
) (reg_cs
+ 0),
3920 } else if (left
->t
== DUK_IVAL_PROP
) {
3921 DUK_DDD(DUK_DDDPRINT("function call with property base"));
3923 duk__ispec_toforcedreg(comp_ctx
, &left
->x1
, reg_cs
+ 0); /* base */
3924 duk__ispec_toforcedreg(comp_ctx
, &left
->x2
, reg_cs
+ 1); /* key */
3925 duk__emit_a_b_c(comp_ctx
,
3927 (duk_regconst_t
) (reg_cs
+ 0),
3928 (duk_regconst_t
) (reg_cs
+ 0),
3929 (duk_regconst_t
) (reg_cs
+ 1)); /* in-place setup */
3931 DUK_DDD(DUK_DDDPRINT("function call with register base"));
3933 duk__ivalue_toforcedreg(comp_ctx
, left
, reg_cs
+ 0);
3934 duk__emit_a_b(comp_ctx
,
3936 (duk_regconst_t
) (reg_cs
+ 0),
3937 (duk_regconst_t
) (reg_cs
+ 0)); /* in-place setup */
3940 DUK__SETTEMP(comp_ctx
, reg_cs
+ 2);
3941 nargs
= duk__parse_arguments(comp_ctx
, res
); /* parse args starting from "next temp" */
3943 /* Tailcalls are handled by back-patching the TAILCALL flag to the
3944 * already emitted instruction later (in return statement parser).
3945 * Since A and C have a special meaning here, they cannot be "shuffled".
3948 duk__emit_a_b_c(comp_ctx
,
3949 DUK_OP_CALL
| DUK__EMIT_FLAG_NO_SHUFFLE_A
| DUK__EMIT_FLAG_NO_SHUFFLE_C
,
3950 (duk_regconst_t
) call_flags
/*flags*/,
3951 (duk_regconst_t
) reg_cs
/*basereg*/,
3952 (duk_regconst_t
) nargs
/*numargs*/);
3953 DUK__SETTEMP(comp_ctx
, reg_cs
+ 1); /* result in csreg */
3955 res
->t
= DUK_IVAL_PLAIN
;
3956 res
->x1
.t
= DUK_ISPEC_REGCONST
;
3957 res
->x1
.regconst
= (duk_regconst_t
) reg_cs
;
3961 /* POSTFIX EXPRESSION */
3963 case DUK_TOK_INCREMENT
: {
3964 args
= (DUK_OP_POSTINCR
<< 8) + 0;
3967 case DUK_TOK_DECREMENT
: {
3968 args
= (DUK_OP_POSTDECR
<< 8) + 0;
3972 /* MULTIPLICATIVE EXPRESSION */
3975 args
= (DUK_OP_MUL
<< 8) + DUK__BP_MULTIPLICATIVE
; /* UnaryExpression */
3979 args
= (DUK_OP_DIV
<< 8) + DUK__BP_MULTIPLICATIVE
; /* UnaryExpression */
3983 args
= (DUK_OP_MOD
<< 8) + DUK__BP_MULTIPLICATIVE
; /* UnaryExpression */
3987 /* ADDITIVE EXPRESSION */
3990 args
= (DUK_OP_ADD
<< 8) + DUK__BP_ADDITIVE
; /* MultiplicativeExpression */
3994 args
= (DUK_OP_SUB
<< 8) + DUK__BP_ADDITIVE
; /* MultiplicativeExpression */
3998 /* SHIFT EXPRESSION */
4000 case DUK_TOK_ALSHIFT
: {
4002 args
= (DUK_OP_BASL
<< 8) + DUK__BP_SHIFT
;
4005 case DUK_TOK_ARSHIFT
: {
4007 args
= (DUK_OP_BASR
<< 8) + DUK__BP_SHIFT
;
4010 case DUK_TOK_RSHIFT
: {
4012 args
= (DUK_OP_BLSR
<< 8) + DUK__BP_SHIFT
;
4016 /* RELATIONAL EXPRESSION */
4020 args
= (DUK_OP_LT
<< 8) + DUK__BP_RELATIONAL
;
4024 args
= (DUK_OP_GT
<< 8) + DUK__BP_RELATIONAL
;
4028 args
= (DUK_OP_LE
<< 8) + DUK__BP_RELATIONAL
;
4032 args
= (DUK_OP_GE
<< 8) + DUK__BP_RELATIONAL
;
4035 case DUK_TOK_INSTANCEOF
: {
4036 args
= (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_INSTOF
<< 8) + DUK__BP_RELATIONAL
;
4040 args
= (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_IN
<< 8) + DUK__BP_RELATIONAL
;
4044 /* EQUALITY EXPRESSION */
4047 args
= (DUK_OP_EQ
<< 8) + DUK__BP_EQUALITY
;
4051 args
= (DUK_OP_NEQ
<< 8) + DUK__BP_EQUALITY
;
4055 args
= (DUK_OP_SEQ
<< 8) + DUK__BP_EQUALITY
;
4058 case DUK_TOK_SNEQ
: {
4059 args
= (DUK_OP_SNEQ
<< 8) + DUK__BP_EQUALITY
;
4063 /* BITWISE EXPRESSIONS */
4065 case DUK_TOK_BAND
: {
4066 args
= (DUK_OP_BAND
<< 8) + DUK__BP_BAND
;
4069 case DUK_TOK_BXOR
: {
4070 args
= (DUK_OP_BXOR
<< 8) + DUK__BP_BXOR
;
4074 args
= (DUK_OP_BOR
<< 8) + DUK__BP_BOR
;
4078 /* LOGICAL EXPRESSIONS */
4080 case DUK_TOK_LAND
: {
4081 /* syntactically left-associative but parsed as right-associative */
4082 args
= (1 << 8) + DUK__BP_LAND
- 1;
4083 goto binary_logical
;
4086 /* syntactically left-associative but parsed as right-associative */
4087 args
= (0 << 8) + DUK__BP_LOR
- 1;
4088 goto binary_logical
;
4091 /* CONDITIONAL EXPRESSION */
4093 case DUK_TOK_QUESTION
: {
4094 /* XXX: common reg allocation need is to reuse a sub-expression's temp reg,
4095 * but only if it really is a temp. Nothing fancy here now.
4101 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
4102 duk__ivalue_toforcedreg(comp_ctx
, left
, reg_temp
);
4103 duk__emit_if_true_skip(comp_ctx
, reg_temp
);
4104 pc_jump1
= duk__emit_jump_empty(comp_ctx
); /* jump to false */
4105 duk__expr_toforcedreg(comp_ctx
, res
, DUK__BP_COMMA
/*rbp_flags*/, reg_temp
/*forced_reg*/); /* AssignmentExpression */
4106 duk__advance_expect(comp_ctx
, DUK_TOK_COLON
);
4107 pc_jump2
= duk__emit_jump_empty(comp_ctx
); /* jump to end */
4108 duk__patch_jump_here(comp_ctx
, pc_jump1
);
4109 duk__expr_toforcedreg(comp_ctx
, res
, DUK__BP_COMMA
/*rbp_flags*/, reg_temp
/*forced_reg*/); /* AssignmentExpression */
4110 duk__patch_jump_here(comp_ctx
, pc_jump2
);
4112 DUK__SETTEMP(comp_ctx
, reg_temp
+ 1);
4113 res
->t
= DUK_IVAL_PLAIN
;
4114 res
->x1
.t
= DUK_ISPEC_REGCONST
;
4115 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
4119 /* ASSIGNMENT EXPRESSION */
4121 case DUK_TOK_EQUALSIGN
: {
4123 * Assignments are right associative, allows e.g.
4125 * a += b = 9; // same as a += (b = 9)
4126 * -> expression value 14, a = 14, b = 9
4128 * Right associativiness is reflected in the BP for recursion,
4129 * "-1" ensures assignment operations are allowed.
4131 * XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)?
4133 args
= (DUK_OP_NONE
<< 8) + DUK__BP_ASSIGNMENT
- 1; /* DUK_OP_NONE marks a 'plain' assignment */
4136 case DUK_TOK_ADD_EQ
: {
4137 /* right associative */
4138 args
= (DUK_OP_ADD
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4141 case DUK_TOK_SUB_EQ
: {
4142 /* right associative */
4143 args
= (DUK_OP_SUB
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4146 case DUK_TOK_MUL_EQ
: {
4147 /* right associative */
4148 args
= (DUK_OP_MUL
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4151 case DUK_TOK_DIV_EQ
: {
4152 /* right associative */
4153 args
= (DUK_OP_DIV
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4156 case DUK_TOK_MOD_EQ
: {
4157 /* right associative */
4158 args
= (DUK_OP_MOD
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4161 case DUK_TOK_ALSHIFT_EQ
: {
4162 /* right associative */
4163 args
= (DUK_OP_BASL
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4166 case DUK_TOK_ARSHIFT_EQ
: {
4167 /* right associative */
4168 args
= (DUK_OP_BASR
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4171 case DUK_TOK_RSHIFT_EQ
: {
4172 /* right associative */
4173 args
= (DUK_OP_BLSR
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4176 case DUK_TOK_BAND_EQ
: {
4177 /* right associative */
4178 args
= (DUK_OP_BAND
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4181 case DUK_TOK_BOR_EQ
: {
4182 /* right associative */
4183 args
= (DUK_OP_BOR
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4186 case DUK_TOK_BXOR_EQ
: {
4187 /* right associative */
4188 args
= (DUK_OP_BXOR
<< 8) + DUK__BP_ASSIGNMENT
- 1;
4194 case DUK_TOK_COMMA
: {
4195 /* right associative */
4197 duk__ivalue_toplain_ignore(comp_ctx
, left
); /* need side effects, not value */
4198 duk__expr_toplain(comp_ctx
, res
, DUK__BP_COMMA
- 1 /*rbp_flags*/);
4200 /* return 'res' (of right part) as our result */
4209 DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok
));
4210 DUK_ERROR_SYNTAX(thr
, DUK_STR_PARSE_ERROR
);
4214 /* XXX: shared handling for 'duk__expr_lhs'? */
4215 if (comp_ctx
->curr_func
.paren_level
== 0 && XXX
) {
4216 comp_ctx
->curr_func
.duk__expr_lhs
= 0;
4222 * Shared handling of binary operations
4224 * args = (is_extraop << 16) + (opcode << 8) + rbp
4227 duk__ivalue_toplain(comp_ctx
, left
);
4228 duk__expr_toplain(comp_ctx
, res
, args
& 0xff /*rbp_flags*/);
4230 /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */
4231 DUK_ASSERT(left
->t
== DUK_IVAL_PLAIN
);
4232 DUK_ASSERT(res
->t
== DUK_IVAL_PLAIN
);
4234 res
->t
= (args
>> 16) ? DUK_IVAL_ARITH_EXTRAOP
: DUK_IVAL_ARITH
;
4235 res
->op
= (args
>> 8) & 0xff;
4237 res
->x2
.t
= res
->x1
.t
;
4238 res
->x2
.regconst
= res
->x1
.regconst
;
4239 duk_copy(ctx
, res
->x1
.valstack_idx
, res
->x2
.valstack_idx
);
4241 res
->x1
.t
= left
->x1
.t
;
4242 res
->x1
.regconst
= left
->x1
.regconst
;
4243 duk_copy(ctx
, left
->x1
.valstack_idx
, res
->x1
.valstack_idx
);
4245 DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx",
4246 (long) res
->t
, (long) res
->x1
.t
, (unsigned long) res
->x1
.regconst
, (long) res
->x2
.t
, (unsigned long) res
->x2
.regconst
));
4252 * Shared handling for logical AND and logical OR.
4254 * args = (truthval << 8) + rbp
4256 * Truthval determines when to skip right-hand-side.
4257 * For logical AND truthval=1, for logical OR truthval=0.
4259 * See doc/compiler.rst for discussion on compiling logical
4260 * AND and OR expressions. The approach here is very simplistic,
4261 * generating extra jumps and multiple evaluations of truth values,
4262 * but generates code on-the-fly with only local back-patching.
4264 * Both logical AND and OR are syntactically left-associated.
4265 * However, logical ANDs are compiled as right associative
4266 * expressions, i.e. "A && B && C" as "A && (B && C)", to allow
4267 * skip jumps to skip over the entire tail. Similarly for logical OR.
4273 duk_small_uint_t args_truthval
= args
>> 8;
4274 duk_small_uint_t args_rbp
= args
& 0xff;
4276 /* XXX: unoptimal use of temps, resetting */
4278 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
4280 duk__ivalue_toforcedreg(comp_ctx
, left
, reg_temp
);
4281 duk__emit_a_b(comp_ctx
,
4282 DUK_OP_IF
| DUK__EMIT_FLAG_NO_SHUFFLE_A
,
4283 (duk_regconst_t
) args_truthval
,
4284 (duk_regconst_t
) reg_temp
); /* skip jump conditionally */
4285 pc_jump
= duk__emit_jump_empty(comp_ctx
);
4286 duk__expr_toforcedreg(comp_ctx
, res
, args_rbp
/*rbp_flags*/, reg_temp
/*forced_reg*/);
4287 duk__patch_jump_here(comp_ctx
, pc_jump
);
4289 res
->t
= DUK_IVAL_PLAIN
;
4290 res
->x1
.t
= DUK_ISPEC_REGCONST
;
4291 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
4297 * Shared assignment expression handling
4299 * args = (opcode << 8) + rbp
4301 * If 'opcode' is DUK_OP_NONE, plain assignment without arithmetic.
4302 * Syntactically valid left-hand-side forms which are not accepted as
4303 * left-hand-side values (e.g. as in "f() = 1") must NOT cause a
4304 * SyntaxError, but rather a run-time ReferenceError.
4306 * When evaluating X <op>= Y, the LHS (X) is conceptually evaluated
4307 * to a temporary first. The RHS is then evaluated. Finally, the
4308 * <op> is applied to the initial value of RHS (not the value after
4309 * RHS evaluation), and written to X. Doing so concretely generates
4310 * inefficient code so we'd like to avoid the temporary when possible.
4311 * See: https://github.com/svaarala/duktape/pull/992.
4313 * The expression value (final LHS value, written to RHS) is
4314 * conceptually copied into a fresh temporary so that it won't
4315 * change even if the LHS/RHS values change in outer expressions.
4316 * For example, it'd be generally incorrect for the expression value
4317 * to be the RHS register binding, unless there's a guarantee that it
4318 * won't change during further expression evaluation. Using the
4319 * temporary concretely produces inefficient bytecode, so we try to
4320 * avoid the extra temporary for some known-to-be-safe cases.
4321 * Currently the only safe case we detect is a "top level assignment",
4322 * for example "x = y + z;", where the assignment expression value is
4324 * See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js.
4328 duk_small_uint_t args_op
= args
>> 8;
4329 duk_small_uint_t args_rbp
= args
& 0xff;
4330 duk_bool_t toplevel_assign
;
4332 /* XXX: here we need to know if 'left' is left-hand-side compatible.
4333 * That information is no longer available from current expr parsing
4334 * state; it would need to be carried into the 'left' ivalue or by
4338 /* A top-level assignment is e.g. "x = y;". For these it's safe
4339 * to use the RHS as-is as the expression value, even if the RHS
4340 * is a reg-bound identifier. The RHS ('res') is right associative
4341 * so it has consumed all other assignment level operations; the
4342 * only relevant lower binding power construct is comma operator
4343 * which will ignore the expression value provided here. Usually
4344 * the top level assignment expression value is ignored, but it
4345 * is relevant for e.g. eval code.
4347 toplevel_assign
= (comp_ctx
->curr_func
.nud_count
== 1 && /* one token before */
4348 comp_ctx
->curr_func
.led_count
== 1); /* one operator (= assign) */
4349 DUK_DDD(DUK_DDDPRINT("assignment: nud_count=%ld, led_count=%ld, toplevel_assign=%ld",
4350 (long) comp_ctx
->curr_func
.nud_count
,
4351 (long) comp_ctx
->curr_func
.led_count
,
4352 (long) toplevel_assign
));
4354 if (left
->t
== DUK_IVAL_VAR
) {
4355 duk_hstring
*h_varname
;
4356 duk_reg_t reg_varbind
;
4357 duk_regconst_t rc_varname
;
4359 DUK_ASSERT(left
->x1
.t
== DUK_ISPEC_VALUE
); /* LHS is already side effect free */
4361 h_varname
= duk_get_hstring(ctx
, left
->x1
.valstack_idx
);
4362 DUK_ASSERT(h_varname
!= NULL
);
4363 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx
, h_varname
)) {
4364 /* E5 Section 11.13.1 (and others for other assignments), step 4. */
4365 goto syntax_error_lvalue
;
4367 duk_dup(ctx
, left
->x1
.valstack_idx
);
4368 (void) duk__lookup_lhs(comp_ctx
, ®_varbind
, &rc_varname
);
4370 if (args_op
== DUK_OP_NONE
) {
4371 duk__expr(comp_ctx
, res
, args_rbp
/*rbp_flags*/);
4372 if (toplevel_assign
) {
4373 /* Any 'res' will do. */
4374 DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is"));
4376 /* 'res' must be a plain ivalue, and not register-bound variable. */
4377 DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier"));
4378 if (res
->t
!= DUK_IVAL_PLAIN
|| (res
->x1
.t
== DUK_ISPEC_REGCONST
&&
4379 (res
->x1
.regconst
& DUK__CONST_MARKER
) == 0 &&
4380 !DUK__ISTEMP(comp_ctx
, res
->x1
.regconst
))) {
4381 duk__ivalue_totempconst(comp_ctx
, res
);
4385 /* For X <op>= Y we need to evaluate the pre-op
4386 * value of X before evaluating the RHS: the RHS
4387 * can change X, but when we do <op> we must use
4392 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
4394 if (reg_varbind
>= 0) {
4397 duk_int_t pc_temp_load
;
4398 duk_int_t pc_before_rhs
;
4399 duk_int_t pc_after_rhs
;
4401 if (toplevel_assign
) {
4402 /* 'reg_varbind' is the operation result and can also
4403 * become the expression value for top level assignments
4404 * such as: "var x; x += y;".
4406 DUK_DD(DUK_DDPRINT("<op>= expression is top level, write directly to reg_varbind"));
4407 reg_res
= reg_varbind
;
4409 /* Not safe to use 'reg_varbind' as assignment expression
4410 * value, so go through a temp.
4412 DUK_DD(DUK_DDPRINT("<op>= expression is not top level, write to reg_temp"));
4413 reg_res
= reg_temp
; /* reg_res should be smallest possible */
4414 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
4417 /* Try to optimize X <op>= Y for reg-bound
4418 * variables. Detect side-effect free RHS
4419 * narrowly by seeing whether it emits code.
4420 * If not, rewind the code emitter and overwrite
4421 * the unnecessary temp reg load.
4424 pc_temp_load
= duk__get_current_pc(comp_ctx
);
4425 duk__emit_a_bc(comp_ctx
,
4427 (duk_regconst_t
) reg_temp
,
4430 pc_before_rhs
= duk__get_current_pc(comp_ctx
);
4431 duk__expr_toregconst(comp_ctx
, res
, args_rbp
/*rbp_flags*/);
4432 DUK_ASSERT(res
->t
== DUK_IVAL_PLAIN
&& res
->x1
.t
== DUK_ISPEC_REGCONST
);
4433 pc_after_rhs
= duk__get_current_pc(comp_ctx
);
4435 DUK_DD(DUK_DDPRINT("pc_temp_load=%ld, pc_before_rhs=%ld, pc_after_rhs=%ld",
4436 (long) pc_temp_load
, (long) pc_before_rhs
,
4437 (long) pc_after_rhs
));
4439 if (pc_after_rhs
== pc_before_rhs
) {
4440 /* Note: if the reg_temp load generated shuffling
4441 * instructions, we may need to rewind more than
4442 * one instruction, so use explicit PC computation.
4444 DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>="));
4445 DUK_BW_ADD_PTR(comp_ctx
->thr
, &comp_ctx
->curr_func
.bw_code
, (pc_temp_load
- pc_before_rhs
) * sizeof(duk_compiler_instr
));
4446 reg_src
= reg_varbind
;
4448 DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
4452 duk__emit_a_b_c(comp_ctx
,
4454 (duk_regconst_t
) reg_res
,
4455 (duk_regconst_t
) reg_src
,
4458 res
->x1
.regconst
= (duk_regconst_t
) reg_res
;
4460 /* Ensure compact use of temps. */
4461 if (DUK__ISTEMP(comp_ctx
, reg_res
)) {
4462 DUK__SETTEMP(comp_ctx
, reg_res
+ 1);
4465 /* When LHS is not register bound, always go through a
4466 * temporary. No optimization for top level assignment.
4469 duk__emit_a_bc(comp_ctx
,
4471 (duk_regconst_t
) reg_temp
,
4474 duk__expr_toregconst(comp_ctx
, res
, args_rbp
/*rbp_flags*/);
4475 DUK_ASSERT(res
->t
== DUK_IVAL_PLAIN
&& res
->x1
.t
== DUK_ISPEC_REGCONST
);
4477 duk__emit_a_b_c(comp_ctx
,
4479 (duk_regconst_t
) reg_temp
,
4480 (duk_regconst_t
) reg_temp
,
4482 res
->x1
.regconst
= (duk_regconst_t
) reg_temp
;
4485 DUK_ASSERT(res
->t
== DUK_IVAL_PLAIN
&& res
->x1
.t
== DUK_ISPEC_REGCONST
);
4488 /* At this point 'res' holds the potential expression value.
4489 * It can be basically any ivalue here, including a reg-bound
4490 * identifier (if code above deems it safe) or a unary/binary
4491 * operation. Operations must be resolved to a side effect free
4492 * plain value, and the side effects must happen exactly once.
4495 if (reg_varbind
>= 0) {
4496 if (res
->t
!= DUK_IVAL_PLAIN
) {
4497 /* Resolve 'res' directly into the LHS binding, and use
4498 * that as the expression value if safe. If not safe,
4499 * resolve to a temp/const and copy to LHS.
4501 if (toplevel_assign
) {
4502 duk__ivalue_toforcedreg(comp_ctx
, res
, (duk_int_t
) reg_varbind
);
4504 duk__ivalue_totempconst(comp_ctx
, res
);
4505 duk__copy_ivalue(comp_ctx
, res
, left
); /* use 'left' as a temp */
4506 duk__ivalue_toforcedreg(comp_ctx
, left
, (duk_int_t
) reg_varbind
);
4509 /* Use 'res' as the expression value (it's side effect
4510 * free and may be a plain value, a register, or a
4511 * constant) and write it to the LHS binding too.
4513 duk__copy_ivalue(comp_ctx
, res
, left
); /* use 'left' as a temp */
4514 duk__ivalue_toforcedreg(comp_ctx
, left
, (duk_int_t
) reg_varbind
);
4517 /* Only a reg fits into 'A' so coerce 'res' into a register
4520 * XXX: here the current A/B/C split is suboptimal: we could
4521 * just use 9 bits for reg_res (and support constants) and 17
4522 * instead of 18 bits for the varname const index.
4525 duk__ivalue_toreg(comp_ctx
, res
);
4526 duk__emit_a_bc(comp_ctx
,
4527 DUK_OP_PUTVAR
| DUK__EMIT_FLAG_A_IS_SOURCE
,
4532 /* 'res' contains expression value */
4533 } else if (left
->t
== DUK_IVAL_PROP
) {
4534 /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
4536 duk_regconst_t rc_key
;
4537 duk_regconst_t rc_res
;
4540 /* Property access expressions ('a[b]') are critical to correct
4541 * LHS evaluation ordering, see test-dev-assign-eval-order*.js.
4542 * We must make sure that the LHS target slot (base object and
4543 * key) don't change during RHS evaluation. The only concrete
4544 * problem is a register reference to a variable-bound register
4545 * (i.e., non-temp). Require temp regs for both key and base.
4547 * Don't allow a constant for the object (even for a number
4548 * etc), as it goes into the 'A' field of the opcode.
4551 reg_obj
= duk__ispec_toregconst_raw(comp_ctx
,
4554 DUK__IVAL_FLAG_REQUIRE_TEMP
/*flags*/);
4556 rc_key
= duk__ispec_toregconst_raw(comp_ctx
,
4559 DUK__IVAL_FLAG_REQUIRE_TEMP
| DUK__IVAL_FLAG_ALLOW_CONST
/*flags*/);
4561 /* Evaluate RHS only when LHS is safe. */
4563 if (args_op
== DUK_OP_NONE
) {
4564 duk__expr_toregconst(comp_ctx
, res
, args_rbp
/*rbp_flags*/);
4565 DUK_ASSERT(res
->t
== DUK_IVAL_PLAIN
&& res
->x1
.t
== DUK_ISPEC_REGCONST
);
4566 rc_res
= res
->x1
.regconst
;
4568 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
4569 duk__emit_a_b_c(comp_ctx
,
4571 (duk_regconst_t
) reg_temp
,
4572 (duk_regconst_t
) reg_obj
,
4575 duk__expr_toregconst(comp_ctx
, res
, args_rbp
/*rbp_flags*/);
4576 DUK_ASSERT(res
->t
== DUK_IVAL_PLAIN
&& res
->x1
.t
== DUK_ISPEC_REGCONST
);
4578 duk__emit_a_b_c(comp_ctx
,
4580 (duk_regconst_t
) reg_temp
,
4581 (duk_regconst_t
) reg_temp
,
4583 rc_res
= (duk_regconst_t
) reg_temp
;
4586 duk__emit_a_b_c(comp_ctx
,
4587 DUK_OP_PUTPROP
| DUK__EMIT_FLAG_A_IS_SOURCE
,
4588 (duk_regconst_t
) reg_obj
,
4592 res
->t
= DUK_IVAL_PLAIN
;
4593 res
->x1
.t
= DUK_ISPEC_REGCONST
;
4594 res
->x1
.regconst
= rc_res
;
4596 /* No support for lvalues returned from new or function call expressions.
4597 * However, these must NOT cause compile-time SyntaxErrors, but run-time
4598 * ReferenceErrors. Both left and right sides of the assignment must be
4599 * evaluated before throwing a ReferenceError. For instance:
4603 * must result in f() being evaluated, then g() being evaluated, and
4604 * finally, a ReferenceError being thrown. See E5 Section 11.13.1.
4607 duk_regconst_t rc_res
;
4609 /* First evaluate LHS fully to ensure all side effects are out. */
4610 duk__ivalue_toplain_ignore(comp_ctx
, left
);
4612 /* Then evaluate RHS fully (its value becomes the expression value too).
4613 * Technically we'd need the side effect safety check here too, but because
4614 * we always throw using INVLHS the result doesn't matter.
4616 rc_res
= duk__expr_toregconst(comp_ctx
, res
, args_rbp
/*rbp_flags*/);
4618 duk__emit_extraop_only(comp_ctx
,
4619 DUK_EXTRAOP_INVLHS
);
4621 res
->t
= DUK_IVAL_PLAIN
;
4622 res
->x1
.t
= DUK_ISPEC_REGCONST
;
4623 res
->x1
.regconst
= rc_res
;
4632 * Post-increment/decrement will return the original value as its
4633 * result value. However, even that value will be coerced using
4634 * ToNumber() which is quite awkward. Specific bytecode opcodes
4635 * are used to handle these semantics.
4637 * Note that post increment/decrement has a "no LineTerminator here"
4638 * restriction. This is handled by duk__expr_lbp(), which forcibly terminates
4639 * the previous expression if a LineTerminator occurs before '++'/'--'.
4643 duk_small_uint_t args_op
= args
>> 8;
4645 /* Specific assumptions for opcode numbering. */
4646 DUK_ASSERT(DUK_OP_POSTINCR
+ 4 == DUK_OP_POSTINCV
);
4647 DUK_ASSERT(DUK_OP_POSTDECR
+ 4 == DUK_OP_POSTDECV
);
4648 DUK_ASSERT(DUK_OP_POSTINCR
+ 8 == DUK_OP_POSTINCP
);
4649 DUK_ASSERT(DUK_OP_POSTDECR
+ 8 == DUK_OP_POSTDECP
);
4651 reg_res
= DUK__ALLOCTEMP(comp_ctx
);
4653 if (left
->t
== DUK_IVAL_VAR
) {
4654 duk_hstring
*h_varname
;
4655 duk_reg_t reg_varbind
;
4656 duk_regconst_t rc_varname
;
4658 h_varname
= duk_get_hstring(ctx
, left
->x1
.valstack_idx
);
4659 DUK_ASSERT(h_varname
!= NULL
);
4661 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx
, h_varname
)) {
4665 duk_dup(ctx
, left
->x1
.valstack_idx
);
4666 if (duk__lookup_lhs(comp_ctx
, ®_varbind
, &rc_varname
)) {
4667 duk__emit_a_bc(comp_ctx
,
4668 args_op
, /* e.g. DUK_OP_POSTINCR */
4669 (duk_regconst_t
) reg_res
,
4670 (duk_regconst_t
) reg_varbind
);
4672 duk__emit_a_bc(comp_ctx
,
4673 args_op
+ 4, /* e.g. DUK_OP_POSTINCV */
4674 (duk_regconst_t
) reg_res
,
4678 DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
4679 (duk_heaphdr
*) h_varname
, (long) reg_varbind
, (long) rc_varname
));
4680 } else if (left
->t
== DUK_IVAL_PROP
) {
4681 duk_reg_t reg_obj
; /* allocate to reg only (not const) */
4682 duk_regconst_t rc_key
;
4684 reg_obj
= duk__ispec_toregconst_raw(comp_ctx
, &left
->x1
, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
4685 rc_key
= duk__ispec_toregconst_raw(comp_ctx
, &left
->x2
, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST
/*flags*/);
4686 duk__emit_a_b_c(comp_ctx
,
4687 args_op
+ 8, /* e.g. DUK_OP_POSTINCP */
4688 (duk_regconst_t
) reg_res
,
4689 (duk_regconst_t
) reg_obj
,
4692 /* Technically return value is not needed because INVLHS will
4693 * unconditially throw a ReferenceError. Coercion is necessary
4694 * for proper semantics (consider ToNumber() called for an object).
4695 * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
4697 duk__ivalue_toforcedreg(comp_ctx
, left
, reg_res
);
4698 duk__emit_extraop_bc(comp_ctx
,
4700 reg_res
); /* for side effects, result ignored */
4701 duk__emit_extraop_only(comp_ctx
,
4702 DUK_EXTRAOP_INVLHS
);
4705 res
->t
= DUK_IVAL_PLAIN
;
4706 res
->x1
.t
= DUK_ISPEC_REGCONST
;
4707 res
->x1
.regconst
= (duk_regconst_t
) reg_res
;
4708 DUK__SETTEMP(comp_ctx
, reg_res
+ 1);
4713 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_EXPRESSION
);
4716 syntax_error_lvalue
:
4717 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_LVALUE
);
4721 DUK_LOCAL duk_small_uint_t
duk__expr_lbp(duk_compiler_ctx
*comp_ctx
) {
4722 duk_small_int_t tok
= comp_ctx
->curr_token
.t
;
4724 DUK_ASSERT(tok
>= DUK_TOK_MINVAL
&& tok
<= DUK_TOK_MAXVAL
);
4725 DUK_ASSERT(sizeof(duk__token_lbp
) == DUK_TOK_MAXVAL
+ 1);
4727 /* XXX: integrate support for this into led() instead?
4728 * Similar issue as post-increment/post-decrement.
4731 /* prevent duk__expr_led() by using a binding power less than anything valid */
4732 if (tok
== DUK_TOK_IN
&& !comp_ctx
->curr_func
.allow_in
) {
4736 if ((tok
== DUK_TOK_DECREMENT
|| tok
== DUK_TOK_INCREMENT
) &&
4737 (comp_ctx
->curr_token
.lineterm
)) {
4738 /* '++' or '--' in a post-increment/decrement position,
4739 * and a LineTerminator occurs between the operator and
4740 * the preceding expression. Force the previous expr
4741 * to terminate, in effect treating e.g. "a,b\n++" as
4742 * "a,b;++" (= SyntaxError).
4747 return DUK__TOKEN_LBP_GET_BP(duk__token_lbp
[tok
]); /* format is bit packed */
4751 * Expression parsing.
4753 * Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the
4754 * first token of the expression. Upon exit, 'curr_tok' will be the first
4755 * token not part of the expression (e.g. semicolon terminating an expression
4759 #define DUK__EXPR_RBP_MASK 0xff
4760 #define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */
4761 #define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */
4762 #define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */
4764 /* main expression parser function */
4765 DUK_LOCAL
void duk__expr(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4766 duk_hthread
*thr
= comp_ctx
->thr
;
4767 duk_context
*ctx
= (duk_context
*) thr
;
4768 duk_ivalue tmp_alloc
; /* 'res' is used for "left", and 'tmp' for "right" */
4769 duk_ivalue
*tmp
= &tmp_alloc
;
4770 duk_small_uint_t rbp
;
4772 DUK__RECURSION_INCREASE(comp_ctx
, thr
);
4774 duk_require_stack(ctx
, DUK__PARSE_EXPR_SLOTS
);
4776 /* filter out flags from exprtop rbp_flags here to save space */
4777 rbp
= rbp_flags
& DUK__EXPR_RBP_MASK
;
4779 DUK_DDD(DUK_DDDPRINT("duk__expr(), rbp_flags=%ld, rbp=%ld, allow_in=%ld, paren_level=%ld",
4780 (long) rbp_flags
, (long) rbp
, (long) comp_ctx
->curr_func
.allow_in
,
4781 (long) comp_ctx
->curr_func
.paren_level
));
4783 DUK_MEMZERO(&tmp_alloc
, sizeof(tmp_alloc
));
4784 tmp
->x1
.valstack_idx
= duk_get_top(ctx
);
4785 tmp
->x2
.valstack_idx
= tmp
->x1
.valstack_idx
+ 1;
4786 duk_push_undefined(ctx
);
4787 duk_push_undefined(ctx
);
4789 /* XXX: where to release temp regs in intermediate expressions?
4790 * e.g. 1+2+3 -> don't inflate temp register count when parsing this.
4791 * that particular expression temp regs can be forced here.
4794 /* XXX: increase ctx->expr_tokens here for every consumed token
4795 * (this would be a nice statistic)?
4798 if (comp_ctx
->curr_token
.t
== DUK_TOK_SEMICOLON
|| comp_ctx
->curr_token
.t
== DUK_TOK_RPAREN
) {
4799 /* XXX: possibly incorrect handling of empty expression */
4800 DUK_DDD(DUK_DDDPRINT("empty expression"));
4801 if (!(rbp_flags
& DUK__EXPR_FLAG_ALLOW_EMPTY
)) {
4802 DUK_ERROR_SYNTAX(thr
, DUK_STR_EMPTY_EXPR_NOT_ALLOWED
);
4804 res
->t
= DUK_IVAL_PLAIN
;
4805 res
->x1
.t
= DUK_ISPEC_VALUE
;
4806 duk_push_undefined(ctx
);
4807 duk_replace(ctx
, res
->x1
.valstack_idx
);
4811 duk__advance(comp_ctx
);
4812 duk__expr_nud(comp_ctx
, res
); /* reuse 'res' as 'left' */
4813 while (rbp
< duk__expr_lbp(comp_ctx
)) {
4814 duk__advance(comp_ctx
);
4815 duk__expr_led(comp_ctx
, res
, tmp
);
4816 duk__copy_ivalue(comp_ctx
, tmp
, res
); /* tmp -> res */
4820 /* final result is already in 'res' */
4824 DUK__RECURSION_DECREASE(comp_ctx
, thr
);
4827 DUK_LOCAL
void duk__exprtop(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4828 duk_hthread
*thr
= comp_ctx
->thr
;
4830 /* Note: these variables must reside in 'curr_func' instead of the global
4831 * context: when parsing function expressions, expression parsing is nested.
4833 comp_ctx
->curr_func
.nud_count
= 0;
4834 comp_ctx
->curr_func
.led_count
= 0;
4835 comp_ctx
->curr_func
.paren_level
= 0;
4836 comp_ctx
->curr_func
.expr_lhs
= 1;
4837 comp_ctx
->curr_func
.allow_in
= (rbp_flags
& DUK__EXPR_FLAG_REJECT_IN
? 0 : 1);
4839 duk__expr(comp_ctx
, res
, rbp_flags
);
4841 if (!(rbp_flags
& DUK__EXPR_FLAG_ALLOW_EMPTY
) && duk__expr_is_empty(comp_ctx
)) {
4842 DUK_ERROR_SYNTAX(thr
, DUK_STR_EMPTY_EXPR_NOT_ALLOWED
);
4846 /* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop()
4847 * and result conversions.
4849 * Each helper needs at least 2-3 calls to make it worth while to wrap.
4853 DUK_LOCAL duk_reg_t
duk__expr_toreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4854 duk__expr(comp_ctx
, res
, rbp_flags
);
4855 return duk__ivalue_toreg(comp_ctx
, res
);
4860 DUK_LOCAL duk_reg_t
duk__expr_totemp(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4861 duk__expr(comp_ctx
, res
, rbp_flags
);
4862 return duk__ivalue_totemp(comp_ctx
, res
);
4866 DUK_LOCAL
void duk__expr_toforcedreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
, duk_reg_t forced_reg
) {
4867 DUK_ASSERT(forced_reg
>= 0);
4868 duk__expr(comp_ctx
, res
, rbp_flags
);
4869 duk__ivalue_toforcedreg(comp_ctx
, res
, forced_reg
);
4872 DUK_LOCAL duk_regconst_t
duk__expr_toregconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4873 duk__expr(comp_ctx
, res
, rbp_flags
);
4874 return duk__ivalue_toregconst(comp_ctx
, res
);
4878 DUK_LOCAL duk_regconst_t
duk__expr_totempconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4879 duk__expr(comp_ctx
, res
, rbp_flags
);
4880 return duk__ivalue_totempconst(comp_ctx
, res
);
4884 DUK_LOCAL
void duk__expr_toplain(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4885 duk__expr(comp_ctx
, res
, rbp_flags
);
4886 duk__ivalue_toplain(comp_ctx
, res
);
4889 DUK_LOCAL
void duk__expr_toplain_ignore(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4890 duk__expr(comp_ctx
, res
, rbp_flags
);
4891 duk__ivalue_toplain_ignore(comp_ctx
, res
);
4894 DUK_LOCAL duk_reg_t
duk__exprtop_toreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4895 duk__exprtop(comp_ctx
, res
, rbp_flags
);
4896 return duk__ivalue_toreg(comp_ctx
, res
);
4900 DUK_LOCAL duk_reg_t
duk__exprtop_totemp(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4901 duk__exprtop(comp_ctx
, res
, rbp_flags
);
4902 return duk__ivalue_totemp(comp_ctx
, res
);
4906 DUK_LOCAL
void duk__exprtop_toforcedreg(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
, duk_reg_t forced_reg
) {
4907 DUK_ASSERT(forced_reg
>= 0);
4908 duk__exprtop(comp_ctx
, res
, rbp_flags
);
4909 duk__ivalue_toforcedreg(comp_ctx
, res
, forced_reg
);
4912 DUK_LOCAL duk_regconst_t
duk__exprtop_toregconst(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t rbp_flags
) {
4913 duk__exprtop(comp_ctx
, res
, rbp_flags
);
4914 return duk__ivalue_toregconst(comp_ctx
, res
);
4918 DUK_LOCAL
void duk__exprtop_toplain_ignore(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, int rbp_flags
) {
4919 duk__exprtop(comp_ctx
, res
, rbp_flags
);
4920 duk__ivalue_toplain_ignore(comp_ctx
, res
);
4925 * Parse an individual source element (top level statement) or a statement.
4927 * Handles labeled statements automatically (peeling away labels before
4928 * parsing an expression that follows the label(s)).
4930 * Upon entry, 'curr_tok' contains the first token of the statement (parsed
4931 * in "allow regexp literal" mode). Upon exit, 'curr_tok' contains the first
4932 * token following the statement (if the statement has a terminator, this is
4933 * the token after the terminator).
4939 #ifdef DUK__HAS_TERM
4940 #undef DUK__HAS_TERM
4942 #ifdef DUK__ALLOW_AUTO_SEMI_ALWAYS
4943 #undef DUK__ALLOW_AUTO_SEMI_ALWAYS
4945 #ifdef DUK__STILL_PROLOGUE
4946 #undef DUK__STILL_PROLOGUE
4948 #ifdef DUK__IS_TERMINAL
4949 #undef DUK__IS_TERMINAL
4952 #define DUK__HAS_VAL (1 << 0) /* stmt has non-empty value */
4953 #define DUK__HAS_TERM (1 << 1) /* stmt has explicit/implicit semicolon terminator */
4954 #define DUK__ALLOW_AUTO_SEMI_ALWAYS (1 << 2) /* allow automatic semicolon even without lineterm (compatibility) */
4955 #define DUK__STILL_PROLOGUE (1 << 3) /* statement does not terminate directive prologue */
4956 #define DUK__IS_TERMINAL (1 << 4) /* statement is guaranteed to be terminal (control doesn't flow to next statement) */
4958 /* Parse a single variable declaration (e.g. "i" or "i=10"). A leading 'var'
4959 * has already been eaten. These is no return value in 'res', it is used only
4962 * When called from 'for-in' statement parser, the initializer expression must
4963 * not allow the 'in' token. The caller supply additional expression parsing
4964 * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'.
4966 * Finally, out_rc_varname and out_reg_varbind are updated to reflect where
4967 * the identifier is bound:
4969 * If register bound: out_reg_varbind >= 0, out_rc_varname == 0 (ignore)
4970 * If not register bound: out_reg_varbind < 0, out_rc_varname >= 0
4972 * These allow the caller to use the variable for further assignment, e.g.
4973 * as is done in 'for-in' parsing.
4976 DUK_LOCAL
void duk__parse_var_decl(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t expr_flags
, duk_reg_t
*out_reg_varbind
, duk_regconst_t
*out_rc_varname
) {
4977 duk_hthread
*thr
= comp_ctx
->thr
;
4978 duk_context
*ctx
= (duk_context
*) thr
;
4979 duk_hstring
*h_varname
;
4980 duk_reg_t reg_varbind
;
4981 duk_regconst_t rc_varname
;
4983 /* assume 'var' has been eaten */
4985 /* Note: Identifier rejects reserved words */
4986 if (comp_ctx
->curr_token
.t
!= DUK_TOK_IDENTIFIER
) {
4989 h_varname
= comp_ctx
->curr_token
.str1
;
4991 DUK_ASSERT(h_varname
!= NULL
);
4993 /* strict mode restrictions (E5 Section 12.2.1) */
4994 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx
, h_varname
)) {
4998 /* register declarations in first pass */
4999 if (comp_ctx
->curr_func
.in_scanning
) {
5001 DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1",
5002 (duk_heaphdr
*) h_varname
));
5003 n
= (duk_uarridx_t
) duk_get_length(ctx
, comp_ctx
->curr_func
.decls_idx
);
5004 duk_push_hstring(ctx
, h_varname
);
5005 duk_put_prop_index(ctx
, comp_ctx
->curr_func
.decls_idx
, n
);
5006 duk_push_int(ctx
, DUK_DECL_TYPE_VAR
+ (0 << 8));
5007 duk_put_prop_index(ctx
, comp_ctx
->curr_func
.decls_idx
, n
+ 1);
5010 duk_push_hstring(ctx
, h_varname
); /* push before advancing to keep reachable */
5012 /* register binding lookup is based on varmap (even in first pass) */
5014 (void) duk__lookup_lhs(comp_ctx
, ®_varbind
, &rc_varname
);
5016 duk__advance(comp_ctx
); /* eat identifier */
5018 if (comp_ctx
->curr_token
.t
== DUK_TOK_EQUALSIGN
) {
5019 duk__advance(comp_ctx
);
5021 DUK_DDD(DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
5022 (duk_heaphdr
*) h_varname
, (long) reg_varbind
, (long) rc_varname
));
5024 duk__exprtop(comp_ctx
, res
, DUK__BP_COMMA
| expr_flags
/*rbp_flags*/); /* AssignmentExpression */
5026 if (reg_varbind
>= 0) {
5027 duk__ivalue_toforcedreg(comp_ctx
, res
, reg_varbind
);
5030 reg_val
= duk__ivalue_toreg(comp_ctx
, res
);
5031 duk__emit_a_bc(comp_ctx
,
5032 DUK_OP_PUTVAR
| DUK__EMIT_FLAG_A_IS_SOURCE
,
5033 (duk_regconst_t
) reg_val
,
5037 if (expr_flags
& DUK__EXPR_FLAG_REQUIRE_INIT
) {
5038 /* Used for minimal 'const': initializer required. */
5043 duk_pop(ctx
); /* pop varname */
5045 *out_rc_varname
= rc_varname
;
5046 *out_reg_varbind
= reg_varbind
;
5051 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_VAR_DECLARATION
);
5054 DUK_LOCAL
void duk__parse_var_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_small_uint_t expr_flags
) {
5055 duk_reg_t reg_varbind
;
5056 duk_regconst_t rc_varname
;
5058 duk__advance(comp_ctx
); /* eat 'var' */
5061 /* rc_varname and reg_varbind are ignored here */
5062 duk__parse_var_decl(comp_ctx
, res
, 0 | expr_flags
, ®_varbind
, &rc_varname
);
5064 if (comp_ctx
->curr_token
.t
!= DUK_TOK_COMMA
) {
5067 duk__advance(comp_ctx
);
5071 DUK_LOCAL
void duk__parse_for_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_int_t pc_label_site
) {
5072 duk_hthread
*thr
= comp_ctx
->thr
;
5073 duk_context
*ctx
= (duk_context
*) thr
;
5074 duk_int_t pc_v34_lhs
; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
5075 duk_reg_t temp_reset
; /* knock back "next temp" to this whenever possible */
5076 duk_reg_t reg_temps
; /* preallocated temporaries (2) for variants 3 and 4 */
5078 DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
5080 /* Two temporaries are preallocated here for variants 3 and 4 which need
5081 * registers which are never clobbered by expressions in the loop
5082 * (concretely: for the enumerator object and the next enumerated value).
5083 * Variants 1 and 2 "release" these temps.
5086 reg_temps
= DUK__ALLOCTEMPS(comp_ctx
, 2);
5088 temp_reset
= DUK__GETTEMP(comp_ctx
);
5091 * For/for-in main variants are:
5093 * 1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement
5094 * 2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement
5095 * 3. for (LeftHandSideExpression in Expression) Statement
5096 * 4. for (var VariableDeclarationNoIn in Expression) Statement
5098 * Parsing these without arbitrary lookahead or backtracking is relatively
5099 * tricky but we manage to do so for now.
5101 * See doc/compiler.rst for a detailed discussion of control flow
5102 * issues, evaluation order issues, etc.
5105 duk__advance(comp_ctx
); /* eat 'for' */
5106 duk__advance_expect(comp_ctx
, DUK_TOK_LPAREN
);
5108 DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld", (long) duk__get_current_pc(comp_ctx
)));
5110 /* a label site has been emitted by duk__parse_stmt() automatically
5111 * (it will also emit the ENDLABEL).
5114 if (comp_ctx
->curr_token
.t
== DUK_TOK_VAR
) {
5119 duk_reg_t reg_varbind
; /* variable binding register if register-bound (otherwise < 0) */
5120 duk_regconst_t rc_varname
; /* variable name reg/const, if variable not register-bound */
5122 duk__advance(comp_ctx
); /* eat 'var' */
5123 duk__parse_var_decl(comp_ctx
, res
, DUK__EXPR_FLAG_REJECT_IN
, ®_varbind
, &rc_varname
);
5124 DUK__SETTEMP(comp_ctx
, temp_reset
);
5126 if (comp_ctx
->curr_token
.t
== DUK_TOK_IN
) {
5131 DUK_DDD(DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement"));
5132 pc_v34_lhs
= duk__get_current_pc(comp_ctx
); /* jump is inserted here */
5133 if (reg_varbind
>= 0) {
5134 duk__emit_a_bc(comp_ctx
,
5136 (duk_regconst_t
) reg_varbind
,
5137 (duk_regconst_t
) (reg_temps
+ 0));
5139 duk__emit_a_bc(comp_ctx
,
5140 DUK_OP_PUTVAR
| DUK__EMIT_FLAG_A_IS_SOURCE
,
5141 (duk_regconst_t
) (reg_temps
+ 0),
5150 DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement"));
5152 /* more initializers */
5153 if (comp_ctx
->curr_token
.t
!= DUK_TOK_COMMA
) {
5156 DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer"));
5158 duk__advance(comp_ctx
); /* eat comma */
5159 duk__parse_var_decl(comp_ctx
, res
, DUK__EXPR_FLAG_REJECT_IN
, ®_varbind
, &rc_varname
);
5168 pc_v34_lhs
= duk__get_current_pc(comp_ctx
); /* jump is inserted here (variant 3) */
5170 /* Note that duk__exprtop() here can clobber any reg above current temp_next,
5171 * so any loop variables (e.g. enumerator) must be "preallocated".
5174 /* don't coerce yet to a plain value (variant 3 needs special handling) */
5175 duk__exprtop(comp_ctx
, res
, DUK__BP_FOR_EXPR
| DUK__EXPR_FLAG_REJECT_IN
| DUK__EXPR_FLAG_ALLOW_EMPTY
/*rbp_flags*/); /* Expression */
5176 if (comp_ctx
->curr_token
.t
== DUK_TOK_IN
) {
5181 /* XXX: need to determine LHS type, and check that it is LHS compatible */
5182 DUK_DDD(DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement"));
5183 if (duk__expr_is_empty(comp_ctx
)) {
5184 goto syntax_error
; /* LeftHandSideExpression does not allow empty expression */
5187 if (res
->t
== DUK_IVAL_VAR
) {
5188 duk_reg_t reg_varbind
;
5189 duk_regconst_t rc_varname
;
5191 duk_dup(ctx
, res
->x1
.valstack_idx
);
5192 if (duk__lookup_lhs(comp_ctx
, ®_varbind
, &rc_varname
)) {
5193 duk__emit_a_bc(comp_ctx
,
5195 (duk_regconst_t
) reg_varbind
,
5196 (duk_regconst_t
) (reg_temps
+ 0));
5198 duk__emit_a_bc(comp_ctx
,
5199 DUK_OP_PUTVAR
| DUK__EMIT_FLAG_A_IS_SOURCE
,
5200 (duk_regconst_t
) (reg_temps
+ 0),
5203 } else if (res
->t
== DUK_IVAL_PROP
) {
5204 /* Don't allow a constant for the object (even for a number etc), as
5205 * it goes into the 'A' field of the opcode.
5208 duk_regconst_t rc_key
;
5209 reg_obj
= duk__ispec_toregconst_raw(comp_ctx
, &res
->x1
, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
5210 rc_key
= duk__ispec_toregconst_raw(comp_ctx
, &res
->x2
, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST
/*flags*/);
5211 duk__emit_a_b_c(comp_ctx
,
5212 DUK_OP_PUTPROP
| DUK__EMIT_FLAG_A_IS_SOURCE
,
5213 (duk_regconst_t
) reg_obj
,
5215 (duk_regconst_t
) (reg_temps
+ 0));
5217 duk__ivalue_toplain_ignore(comp_ctx
, res
); /* just in case */
5218 duk__emit_extraop_only(comp_ctx
,
5219 DUK_EXTRAOP_INVLHS
);
5227 DUK_DDD(DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement"));
5228 duk__ivalue_toplain_ignore(comp_ctx
, res
);
5235 * Parse variant 1 or 2. The first part expression (which differs
5236 * in the variants) has already been parsed and its code emitted.
5238 * reg_temps + 0: unused
5239 * reg_temps + 1: unused
5242 duk_regconst_t rc_cond
;
5243 duk_int_t pc_l1
, pc_l2
, pc_l3
, pc_l4
;
5244 duk_int_t pc_jumpto_l3
, pc_jumpto_l4
;
5245 duk_bool_t expr_c_empty
;
5247 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2"));
5249 /* "release" preallocated temps since we won't need them */
5250 temp_reset
= reg_temps
+ 0;
5251 DUK__SETTEMP(comp_ctx
, temp_reset
);
5253 duk__advance_expect(comp_ctx
, DUK_TOK_SEMICOLON
);
5255 pc_l1
= duk__get_current_pc(comp_ctx
);
5256 duk__exprtop(comp_ctx
, res
, DUK__BP_FOR_EXPR
| DUK__EXPR_FLAG_ALLOW_EMPTY
/*rbp_flags*/); /* Expression_opt */
5257 if (duk__expr_is_empty(comp_ctx
)) {
5258 /* no need to coerce */
5259 pc_jumpto_l3
= duk__emit_jump_empty(comp_ctx
); /* to body */
5260 pc_jumpto_l4
= -1; /* omitted */
5262 rc_cond
= duk__ivalue_toregconst(comp_ctx
, res
);
5263 duk__emit_if_false_skip(comp_ctx
, rc_cond
);
5264 pc_jumpto_l3
= duk__emit_jump_empty(comp_ctx
); /* to body */
5265 pc_jumpto_l4
= duk__emit_jump_empty(comp_ctx
); /* to exit */
5267 DUK__SETTEMP(comp_ctx
, temp_reset
);
5269 duk__advance_expect(comp_ctx
, DUK_TOK_SEMICOLON
);
5271 pc_l2
= duk__get_current_pc(comp_ctx
);
5272 duk__exprtop(comp_ctx
, res
, DUK__BP_FOR_EXPR
| DUK__EXPR_FLAG_ALLOW_EMPTY
/*rbp_flags*/); /* Expression_opt */
5273 if (duk__expr_is_empty(comp_ctx
)) {
5274 /* no need to coerce */
5276 /* JUMP L1 omitted */
5278 duk__ivalue_toplain_ignore(comp_ctx
, res
);
5280 duk__emit_jump(comp_ctx
, pc_l1
);
5282 DUK__SETTEMP(comp_ctx
, temp_reset
);
5284 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
5286 pc_l3
= duk__get_current_pc(comp_ctx
);
5287 duk__parse_stmt(comp_ctx
, res
, 0 /*allow_source_elem*/);
5289 duk__emit_jump(comp_ctx
, pc_l1
);
5291 duk__emit_jump(comp_ctx
, pc_l2
);
5293 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
5295 pc_l4
= duk__get_current_pc(comp_ctx
);
5297 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l3: %ld->%ld, jumpto_l4: %ld->%ld, "
5298 "break: %ld->%ld, continue: %ld->%ld",
5299 (long) pc_jumpto_l3
, (long) pc_l3
, (long) pc_jumpto_l4
, (long) pc_l4
,
5300 (long) (pc_label_site
+ 1), (long) pc_l4
, (long) (pc_label_site
+ 2), (long) pc_l2
));
5302 duk__patch_jump(comp_ctx
, pc_jumpto_l3
, pc_l3
);
5303 duk__patch_jump(comp_ctx
, pc_jumpto_l4
, pc_l4
);
5304 duk__patch_jump(comp_ctx
,
5306 pc_l4
); /* break jump */
5307 duk__patch_jump(comp_ctx
,
5309 expr_c_empty
? pc_l1
: pc_l2
); /* continue jump */
5315 * Parse variant 3 or 4.
5317 * For variant 3 (e.g. "for (A in C) D;") the code for A (except the
5318 * final property/variable write) has already been emitted. The first
5319 * instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted
5320 * there to satisfy control flow needs.
5322 * For variant 4, if the variable declaration had an initializer
5323 * (e.g. "for (var A = B in C) D;") the code for the assignment
5324 * (B) has already been emitted.
5326 * Variables set before entering here:
5328 * pc_v34_lhs: insert a "JUMP L2" here (see doc/compiler.rst example).
5329 * reg_temps + 0: iteration target value (written to LHS)
5330 * reg_temps + 1: enumerator object
5333 duk_int_t pc_l1
, pc_l2
, pc_l3
, pc_l4
, pc_l5
;
5334 duk_int_t pc_jumpto_l2
, pc_jumpto_l3
, pc_jumpto_l4
, pc_jumpto_l5
;
5335 duk_reg_t reg_target
;
5337 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs
));
5339 DUK__SETTEMP(comp_ctx
, temp_reset
);
5341 /* First we need to insert a jump in the middle of previously
5342 * emitted code to get the control flow right. No jumps can
5343 * cross the position where the jump is inserted. See doc/compiler.rst
5344 * for discussion on the intricacies of control flow and side effects
5345 * for variants 3 and 4.
5348 duk__insert_jump_entry(comp_ctx
, pc_v34_lhs
);
5349 pc_jumpto_l2
= pc_v34_lhs
; /* inserted jump */
5350 pc_l1
= pc_v34_lhs
+ 1; /* +1, right after inserted jump */
5352 /* The code for writing reg_temps + 0 to the left hand side has already
5356 pc_jumpto_l3
= duk__emit_jump_empty(comp_ctx
); /* -> loop body */
5358 duk__advance(comp_ctx
); /* eat 'in' */
5360 /* Parse enumeration target and initialize enumerator. For 'null' and 'undefined',
5361 * INITENUM will creates a 'null' enumerator which works like an empty enumerator
5362 * (E5 Section 12.6.4, step 3). Note that INITENUM requires the value to be in a
5363 * register (constant not allowed).
5366 pc_l2
= duk__get_current_pc(comp_ctx
);
5367 reg_target
= duk__exprtop_toreg(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/); /* Expression */
5368 duk__emit_extraop_b_c(comp_ctx
,
5369 DUK_EXTRAOP_INITENUM
| DUK__EMIT_FLAG_B_IS_TARGET
,
5370 (duk_regconst_t
) (reg_temps
+ 1),
5371 (duk_regconst_t
) reg_target
);
5372 pc_jumpto_l4
= duk__emit_jump_empty(comp_ctx
);
5373 DUK__SETTEMP(comp_ctx
, temp_reset
);
5375 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
5377 pc_l3
= duk__get_current_pc(comp_ctx
);
5378 duk__parse_stmt(comp_ctx
, res
, 0 /*allow_source_elem*/);
5379 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
5381 /* NEXTENUM needs a jump slot right after the main opcode.
5382 * We need the code emitter to reserve the slot: if there's
5383 * target shuffling, the target shuffle opcodes must happen
5384 * after the jump slot (for NEXTENUM the shuffle opcodes are
5385 * not needed if the enum is finished).
5387 pc_l4
= duk__get_current_pc(comp_ctx
);
5388 duk__emit_extraop_b_c(comp_ctx
,
5389 DUK_EXTRAOP_NEXTENUM
| DUK__EMIT_FLAG_B_IS_TARGET
| DUK__EMIT_FLAG_RESERVE_JUMPSLOT
,
5390 (duk_regconst_t
) (reg_temps
+ 0),
5391 (duk_regconst_t
) (reg_temps
+ 1));
5392 pc_jumpto_l5
= comp_ctx
->emit_jumpslot_pc
; /* NEXTENUM jump slot: executed when enum finished */
5393 duk__emit_jump(comp_ctx
, pc_l1
); /* jump to next loop, using reg_v34_iter as iterated value */
5395 pc_l5
= duk__get_current_pc(comp_ctx
);
5397 /* XXX: since the enumerator may be a memory expensive object,
5398 * perhaps clear it explicitly here? If so, break jump must
5399 * go through this clearing operation.
5402 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l2: %ld->%ld, jumpto_l3: %ld->%ld, "
5403 "jumpto_l4: %ld->%ld, jumpto_l5: %ld->%ld, "
5404 "break: %ld->%ld, continue: %ld->%ld",
5405 (long) pc_jumpto_l2
, (long) pc_l2
, (long) pc_jumpto_l3
, (long) pc_l3
,
5406 (long) pc_jumpto_l4
, (long) pc_l4
, (long) pc_jumpto_l5
, (long) pc_l5
,
5407 (long) (pc_label_site
+ 1), (long) pc_l5
, (long) (pc_label_site
+ 2), (long) pc_l4
));
5409 duk__patch_jump(comp_ctx
, pc_jumpto_l2
, pc_l2
);
5410 duk__patch_jump(comp_ctx
, pc_jumpto_l3
, pc_l3
);
5411 duk__patch_jump(comp_ctx
, pc_jumpto_l4
, pc_l4
);
5412 duk__patch_jump(comp_ctx
, pc_jumpto_l5
, pc_l5
);
5413 duk__patch_jump(comp_ctx
, pc_label_site
+ 1, pc_l5
); /* break jump */
5414 duk__patch_jump(comp_ctx
, pc_label_site
+ 2, pc_l4
); /* continue jump */
5419 DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement"));
5423 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_FOR
);
5426 DUK_LOCAL
void duk__parse_switch_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_int_t pc_label_site
) {
5427 duk_hthread
*thr
= comp_ctx
->thr
;
5428 duk_reg_t temp_at_loop
;
5429 duk_regconst_t rc_switch
; /* reg/const for switch value */
5430 duk_regconst_t rc_case
; /* reg/const for case value */
5431 duk_reg_t reg_temp
; /* general temp register */
5432 duk_int_t pc_prevcase
= -1;
5433 duk_int_t pc_prevstmt
= -1;
5434 duk_int_t pc_default
= -1; /* -1 == not set, -2 == pending (next statement list) */
5436 /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */
5439 * Switch is pretty complicated because of several conflicting concerns:
5441 * - Want to generate code without an intermediate representation,
5444 * - Case selectors are expressions, not values, and may thus e.g. throw
5445 * exceptions (which causes evaluation order concerns)
5447 * - Evaluation semantics of case selectors and default clause need to be
5448 * carefully implemented to provide correct behavior even with case value
5451 * - Fall through case and default clauses; avoiding dead JUMPs if case
5452 * ends with an unconditional jump (a break or a continue)
5454 * - The same case value may occur multiple times, but evaluation rules
5455 * only process the first match before switching to a "propagation" mode
5456 * where case values are no longer evaluated
5458 * See E5 Section 12.11. Also see doc/compiler.rst for compilation
5462 duk__advance(comp_ctx
);
5463 duk__advance_expect(comp_ctx
, DUK_TOK_LPAREN
);
5464 rc_switch
= duk__exprtop_toregconst(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/);
5465 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
5466 duk__advance_expect(comp_ctx
, DUK_TOK_LCURLY
);
5468 DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch
));
5470 temp_at_loop
= DUK__GETTEMP(comp_ctx
);
5473 duk_int_t num_stmts
;
5474 duk_small_int_t tok
;
5476 /* sufficient for keeping temp reg numbers in check */
5477 DUK__SETTEMP(comp_ctx
, temp_at_loop
);
5479 if (comp_ctx
->curr_token
.t
== DUK_TOK_RCURLY
) {
5484 * Parse a case or default clause.
5487 if (comp_ctx
->curr_token
.t
== DUK_TOK_CASE
) {
5491 * Note: cannot use reg_case as a temp register (for SEQ target)
5492 * because it may be a constant.
5495 duk__patch_jump_here(comp_ctx
, pc_prevcase
); /* chain jumps for case
5496 * evaluation and checking
5499 duk__advance(comp_ctx
);
5500 rc_case
= duk__exprtop_toregconst(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/);
5501 duk__advance_expect(comp_ctx
, DUK_TOK_COLON
);
5503 reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
5504 duk__emit_a_b_c(comp_ctx
,
5506 (duk_regconst_t
) reg_temp
,
5509 duk__emit_if_true_skip(comp_ctx
, (duk_regconst_t
) reg_temp
);
5511 /* jump to next case clause */
5512 pc_prevcase
= duk__emit_jump_empty(comp_ctx
); /* no match, next case */
5514 /* statements go here (if any) on next loop */
5515 } else if (comp_ctx
->curr_token
.t
== DUK_TOK_DEFAULT
) {
5520 if (pc_default
>= 0) {
5523 duk__advance(comp_ctx
);
5524 duk__advance_expect(comp_ctx
, DUK_TOK_COLON
);
5526 /* Fix for https://github.com/svaarala/duktape/issues/155:
5527 * If 'default' is first clause (detected by pc_prevcase < 0)
5528 * we need to ensure we stay in the matching chain.
5530 if (pc_prevcase
< 0) {
5531 DUK_DD(DUK_DDPRINT("default clause is first, emit prevcase jump"));
5532 pc_prevcase
= duk__emit_jump_empty(comp_ctx
);
5535 /* default clause matches next statement list (if any) */
5538 /* Code is not accepted before the first case/default clause */
5543 * Parse code after the clause. Possible terminators are
5544 * 'case', 'default', and '}'.
5546 * Note that there may be no code at all, not even an empty statement,
5547 * between case clauses. This must be handled just like an empty statement
5548 * (omitting seemingly pointless JUMPs), to avoid situations like
5549 * test-bug-case-fallthrough.js.
5553 if (pc_default
== -2) {
5554 pc_default
= duk__get_current_pc(comp_ctx
);
5557 /* Note: this is correct even for default clause statements:
5558 * they participate in 'fall-through' behavior even if the
5559 * default clause is in the middle.
5561 duk__patch_jump_here(comp_ctx
, pc_prevstmt
); /* chain jumps for 'fall-through'
5562 * after a case matches.
5566 tok
= comp_ctx
->curr_token
.t
;
5567 if (tok
== DUK_TOK_CASE
|| tok
== DUK_TOK_DEFAULT
||
5568 tok
== DUK_TOK_RCURLY
) {
5572 duk__parse_stmt(comp_ctx
, res
, 0 /*allow_source_elem*/);
5575 /* fall-through jump to next code of next case (backpatched) */
5576 pc_prevstmt
= duk__emit_jump_empty(comp_ctx
);
5578 /* XXX: would be nice to omit this jump when the jump is not
5579 * reachable, at least in the obvious cases (such as the case
5580 * ending with a 'break'.
5582 * Perhaps duk__parse_stmt() could provide some info on whether
5583 * the statement is a "dead end"?
5585 * If implemented, just set pc_prevstmt to -1 when not needed.
5589 DUK_ASSERT(comp_ctx
->curr_token
.t
== DUK_TOK_RCURLY
);
5590 duk__advance(comp_ctx
);
5592 /* default case control flow patchup; note that if pc_prevcase < 0
5593 * (i.e. no case clauses), control enters default case automatically.
5595 if (pc_default
>= 0) {
5596 /* default case exists: go there if no case matches */
5597 duk__patch_jump(comp_ctx
, pc_prevcase
, pc_default
);
5599 /* default case does not exist, or no statements present
5600 * after default case: finish case evaluation
5602 duk__patch_jump_here(comp_ctx
, pc_prevcase
);
5605 /* fall-through control flow patchup; note that pc_prevstmt may be
5606 * < 0 (i.e. no case clauses), in which case this is a no-op.
5608 duk__patch_jump_here(comp_ctx
, pc_prevstmt
);
5610 /* continue jump not patched, an INVALID opcode remains there */
5611 duk__patch_jump_here(comp_ctx
, pc_label_site
+ 1); /* break jump */
5613 /* Note: 'fast' breaks will jump to pc_label_site + 1, which will
5614 * then jump here. The double jump will be eliminated by a
5615 * peephole pass, resulting in an optimal jump here. The label
5616 * site jumps will remain in bytecode and will waste code size.
5622 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_SWITCH
);
5625 DUK_LOCAL
void duk__parse_if_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
5626 duk_reg_t temp_reset
;
5627 duk_regconst_t rc_cond
;
5628 duk_int_t pc_jump_false
;
5630 DUK_DDD(DUK_DDDPRINT("begin parsing if statement"));
5632 temp_reset
= DUK__GETTEMP(comp_ctx
);
5634 duk__advance(comp_ctx
); /* eat 'if' */
5635 duk__advance_expect(comp_ctx
, DUK_TOK_LPAREN
);
5637 rc_cond
= duk__exprtop_toregconst(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/);
5638 duk__emit_if_true_skip(comp_ctx
, rc_cond
);
5639 pc_jump_false
= duk__emit_jump_empty(comp_ctx
); /* jump to end or else part */
5640 DUK__SETTEMP(comp_ctx
, temp_reset
);
5642 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
5644 duk__parse_stmt(comp_ctx
, res
, 0 /*allow_source_elem*/);
5646 /* The 'else' ambiguity is resolved by 'else' binding to the innermost
5647 * construct, so greedy matching is correct here.
5650 if (comp_ctx
->curr_token
.t
== DUK_TOK_ELSE
) {
5651 duk_int_t pc_jump_end
;
5653 DUK_DDD(DUK_DDDPRINT("if has else part"));
5655 duk__advance(comp_ctx
);
5657 pc_jump_end
= duk__emit_jump_empty(comp_ctx
); /* jump from true part to end */
5658 duk__patch_jump_here(comp_ctx
, pc_jump_false
);
5660 duk__parse_stmt(comp_ctx
, res
, 0 /*allow_source_elem*/);
5662 duk__patch_jump_here(comp_ctx
, pc_jump_end
);
5664 DUK_DDD(DUK_DDDPRINT("if does not have else part"));
5666 duk__patch_jump_here(comp_ctx
, pc_jump_false
);
5669 DUK_DDD(DUK_DDDPRINT("end parsing if statement"));
5672 DUK_LOCAL
void duk__parse_do_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_int_t pc_label_site
) {
5673 duk_regconst_t rc_cond
;
5676 DUK_DDD(DUK_DDDPRINT("begin parsing do statement"));
5678 duk__advance(comp_ctx
); /* eat 'do' */
5680 pc_start
= duk__get_current_pc(comp_ctx
);
5681 duk__parse_stmt(comp_ctx
, res
, 0 /*allow_source_elem*/);
5682 duk__patch_jump_here(comp_ctx
, pc_label_site
+ 2); /* continue jump */
5684 duk__advance_expect(comp_ctx
, DUK_TOK_WHILE
);
5685 duk__advance_expect(comp_ctx
, DUK_TOK_LPAREN
);
5687 rc_cond
= duk__exprtop_toregconst(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/);
5688 duk__emit_if_false_skip(comp_ctx
, rc_cond
);
5689 duk__emit_jump(comp_ctx
, pc_start
);
5690 /* no need to reset temps, as we're finished emitting code */
5692 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
5694 duk__patch_jump_here(comp_ctx
, pc_label_site
+ 1); /* break jump */
5696 DUK_DDD(DUK_DDDPRINT("end parsing do statement"));
5699 DUK_LOCAL
void duk__parse_while_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_int_t pc_label_site
) {
5700 duk_reg_t temp_reset
;
5701 duk_regconst_t rc_cond
;
5703 duk_int_t pc_jump_false
;
5705 DUK_DDD(DUK_DDDPRINT("begin parsing while statement"));
5707 temp_reset
= DUK__GETTEMP(comp_ctx
);
5709 duk__advance(comp_ctx
); /* eat 'while' */
5711 duk__advance_expect(comp_ctx
, DUK_TOK_LPAREN
);
5713 pc_start
= duk__get_current_pc(comp_ctx
);
5714 duk__patch_jump_here(comp_ctx
, pc_label_site
+ 2); /* continue jump */
5716 rc_cond
= duk__exprtop_toregconst(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/);
5717 duk__emit_if_true_skip(comp_ctx
, rc_cond
);
5718 pc_jump_false
= duk__emit_jump_empty(comp_ctx
);
5719 DUK__SETTEMP(comp_ctx
, temp_reset
);
5721 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
5723 duk__parse_stmt(comp_ctx
, res
, 0 /*allow_source_elem*/);
5724 duk__emit_jump(comp_ctx
, pc_start
);
5726 duk__patch_jump_here(comp_ctx
, pc_jump_false
);
5727 duk__patch_jump_here(comp_ctx
, pc_label_site
+ 1); /* break jump */
5729 DUK_DDD(DUK_DDDPRINT("end parsing while statement"));
5732 DUK_LOCAL
void duk__parse_break_or_continue_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
5733 duk_hthread
*thr
= comp_ctx
->thr
;
5734 duk_bool_t is_break
= (comp_ctx
->curr_token
.t
== DUK_TOK_BREAK
);
5736 duk_int_t label_catch_depth
;
5737 duk_int_t label_pc
; /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */
5738 duk_bool_t label_is_closest
;
5742 duk__advance(comp_ctx
); /* eat 'break' or 'continue' */
5744 if (comp_ctx
->curr_token
.t
== DUK_TOK_SEMICOLON
|| /* explicit semi follows */
5745 comp_ctx
->curr_token
.lineterm
|| /* automatic semi will be inserted */
5746 comp_ctx
->curr_token
.allow_auto_semi
) { /* automatic semi will be inserted */
5747 /* break/continue without label */
5749 duk__lookup_active_label(comp_ctx
, DUK_HTHREAD_STRING_EMPTY_STRING(thr
), is_break
, &label_id
, &label_catch_depth
, &label_pc
, &label_is_closest
);
5750 } else if (comp_ctx
->curr_token
.t
== DUK_TOK_IDENTIFIER
) {
5751 /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */
5752 DUK_ASSERT(comp_ctx
->curr_token
.str1
!= NULL
);
5753 duk__lookup_active_label(comp_ctx
, comp_ctx
->curr_token
.str1
, is_break
, &label_id
, &label_catch_depth
, &label_pc
, &label_is_closest
);
5754 duk__advance(comp_ctx
);
5756 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_BREAK_CONT_LABEL
);
5759 /* Use a fast break/continue when possible. A fast break/continue is
5760 * just a jump to the LABEL break/continue jump slot, which then jumps
5761 * to an appropriate place (for break, going through ENDLABEL correctly).
5762 * The peephole optimizer will optimize the jump to a direct one.
5765 if (label_catch_depth
== comp_ctx
->curr_func
.catch_depth
&&
5767 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
5768 "label_catch_depth=%ld, catch_depth=%ld "
5769 "-> use fast variant (direct jump)",
5770 (long) is_break
, (long) label_id
, (long) label_is_closest
,
5771 (long) label_catch_depth
, (long) comp_ctx
->curr_func
.catch_depth
));
5773 duk__emit_jump(comp_ctx
, label_pc
+ (is_break
? 1 : 2));
5775 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
5776 "label_catch_depth=%ld, catch_depth=%ld "
5777 "-> use slow variant (longjmp)",
5778 (long) is_break
, (long) label_id
, (long) label_is_closest
,
5779 (long) label_catch_depth
, (long) comp_ctx
->curr_func
.catch_depth
));
5781 duk__emit_extraop_bc(comp_ctx
,
5782 is_break
? DUK_EXTRAOP_BREAK
: DUK_EXTRAOP_CONTINUE
,
5783 (duk_regconst_t
) label_id
);
5787 DUK_LOCAL
void duk__parse_return_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
5788 duk_hthread
*thr
= comp_ctx
->thr
;
5789 duk_regconst_t rc_val
;
5790 duk_small_uint_t ret_flags
;
5792 duk__advance(comp_ctx
); /* eat 'return' */
5794 /* A 'return' statement is only allowed inside an actual function body,
5795 * not as part of eval or global code.
5797 if (!comp_ctx
->curr_func
.is_function
) {
5798 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_RETURN
);
5803 if (comp_ctx
->curr_token
.t
== DUK_TOK_SEMICOLON
|| /* explicit semi follows */
5804 comp_ctx
->curr_token
.lineterm
|| /* automatic semi will be inserted */
5805 comp_ctx
->curr_token
.allow_auto_semi
) { /* automatic semi will be inserted */
5806 DUK_DDD(DUK_DDDPRINT("empty return value -> undefined"));
5809 duk_int_t pc_before_expr
;
5810 duk_int_t pc_after_expr
;
5812 DUK_DDD(DUK_DDDPRINT("return with a value"));
5814 DUK_UNREF(pc_before_expr
);
5815 DUK_UNREF(pc_after_expr
);
5817 pc_before_expr
= duk__get_current_pc(comp_ctx
);
5818 rc_val
= duk__exprtop_toregconst(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/);
5819 pc_after_expr
= duk__get_current_pc(comp_ctx
);
5821 /* Tail call check: if last opcode emitted was CALL(I), and
5822 * the context allows it, change the CALL(I) to a tail call.
5823 * This doesn't guarantee that a tail call will be allowed at
5824 * runtime, so the RETURN must still be emitted. (Duktape
5825 * 0.10.0 avoided this and simulated a RETURN if a tail call
5826 * couldn't be used at runtime; but this didn't work
5827 * correctly with a thread yield/resume, see
5828 * test-bug-tailcall-thread-yield-resume.js for discussion.)
5830 * In addition to the last opcode being CALL, we also need to
5831 * be sure that 'rc_val' is the result register of the CALL(I).
5832 * For instance, for the expression 'return 0, (function ()
5833 * { return 1; }), 2' the last opcode emitted is CALL (no
5834 * bytecode is emitted for '2') but 'rc_val' indicates
5835 * constant '2'. Similarly if '2' is replaced by a register
5836 * bound variable, no opcodes are emitted but tail call would
5839 * This is tricky and easy to get wrong. It would be best to
5840 * track enough expression metadata to check that 'rc_val' came
5841 * from that last CALL instruction. We don't have that metadata
5842 * now, so we check that 'rc_val' is a temporary register result
5843 * (not a constant or a register bound variable). There should
5844 * be no way currently for 'rc_val' to be a temporary for an
5845 * expression following the CALL instruction without emitting
5846 * some opcodes following the CALL. This proxy check is used
5849 * See: test-bug-comma-expr-gh131.js.
5851 * The non-standard 'caller' property disables tail calls
5852 * because they pose some special cases which haven't been
5856 #if defined(DUK_USE_TAILCALL)
5857 if (comp_ctx
->curr_func
.catch_depth
== 0 && /* no catchers */
5858 pc_after_expr
> pc_before_expr
) { /* at least one opcode emitted */
5859 duk_compiler_instr
*instr
;
5860 duk_small_uint_t op
;
5862 instr
= duk__get_instr_ptr(comp_ctx
, pc_after_expr
- 1);
5863 DUK_ASSERT(instr
!= NULL
);
5865 op
= (duk_small_uint_t
) DUK_DEC_OP(instr
->ins
);
5866 if ((op
== DUK_OP_CALL
|| op
== DUK_OP_CALLI
) &&
5867 DUK__ISTEMP(comp_ctx
, rc_val
) /* see above */) {
5868 DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: "
5869 "catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
5870 "and last instruction is a CALL "
5871 "-> set TAILCALL flag"));
5872 /* Just flip the single bit. */
5873 instr
->ins
|= DUK_ENC_OP_A_B_C(0, DUK_BC_CALL_FLAG_TAILCALL
, 0, 0);
5876 #endif /* DUK_USE_TAILCALL */
5878 ret_flags
= DUK_BC_RETURN_FLAG_HAVE_RETVAL
;
5881 duk__emit_a_b(comp_ctx
,
5882 DUK_OP_RETURN
| DUK__EMIT_FLAG_NO_SHUFFLE_A
,
5883 (duk_regconst_t
) ret_flags
/*flags*/,
5887 DUK_LOCAL
void duk__parse_throw_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
5890 duk__advance(comp_ctx
); /* eat 'throw' */
5892 /* Unlike break/continue, throw statement does not allow an empty value. */
5894 if (comp_ctx
->curr_token
.lineterm
) {
5895 DUK_ERROR_SYNTAX(comp_ctx
->thr
, DUK_STR_INVALID_THROW
);
5898 reg_val
= duk__exprtop_toreg(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/);
5899 duk__emit_extraop_bc(comp_ctx
,
5901 (duk_regconst_t
) reg_val
);
5904 DUK_LOCAL
void duk__parse_try_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
5905 duk_hthread
*thr
= comp_ctx
->thr
;
5906 duk_context
*ctx
= (duk_context
*) thr
;
5907 duk_reg_t reg_catch
; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
5908 duk_regconst_t rc_varname
= 0;
5909 duk_small_uint_t trycatch_flags
= 0;
5910 duk_int_t pc_ldconst
= -1;
5911 duk_int_t pc_trycatch
= -1;
5912 duk_int_t pc_catch
= -1;
5913 duk_int_t pc_finally
= -1;
5918 * See the following documentation for discussion:
5920 * doc/execution.rst: control flow details
5922 * Try, catch, and finally "parts" are Blocks, not Statements, so
5923 * they must always be delimited by curly braces. This is unlike e.g.
5924 * the if statement, which accepts any Statement. This eliminates any
5925 * questions of matching parts of nested try statements. The Block
5926 * parsing is implemented inline here (instead of calling out).
5928 * Finally part has a 'let scoped' variable, which requires a few kinks
5932 comp_ctx
->curr_func
.catch_depth
++;
5934 duk__advance(comp_ctx
); /* eat 'try' */
5936 reg_catch
= DUK__ALLOCTEMPS(comp_ctx
, 2);
5938 /* The target for this LDCONST may need output shuffling, but we assume
5939 * that 'pc_ldconst' will be the LDCONST that we can patch later. This
5940 * should be the case because there's no input shuffling. (If there's
5941 * no catch clause, this LDCONST will be replaced with a NOP.)
5943 pc_ldconst
= duk__get_current_pc(comp_ctx
);
5944 duk__emit_a_bc(comp_ctx
, DUK_OP_LDCONST
, reg_catch
, 0 /*patched later*/);
5946 pc_trycatch
= duk__get_current_pc(comp_ctx
);
5947 duk__emit_invalid(comp_ctx
); /* TRYCATCH, cannot emit now (not enough info) */
5948 duk__emit_invalid(comp_ctx
); /* jump for 'catch' case */
5949 duk__emit_invalid(comp_ctx
); /* jump for 'finally' case or end (if no finally) */
5952 duk__advance_expect(comp_ctx
, DUK_TOK_LCURLY
);
5953 duk__parse_stmts(comp_ctx
, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
5954 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
5955 duk__emit_extraop_only(comp_ctx
,
5956 DUK_EXTRAOP_ENDTRY
);
5958 if (comp_ctx
->curr_token
.t
== DUK_TOK_CATCH
) {
5960 * The catch variable must be updated to reflect the new allocated
5961 * register for the duration of the catch clause. We need to store
5962 * and restore the original value for the varmap entry (if any).
5966 * Note: currently register bindings must be fixed for the entire
5967 * function. So, even though the catch variable is in a register
5968 * we know, we must use an explicit environment record and slow path
5969 * accesses to read/write the catch binding to make closures created
5970 * within the catch clause work correctly. This restriction should
5971 * be fixable (at least in common cases) later.
5973 * See: test-bug-catch-binding-2.js.
5975 * XXX: improve to get fast path access to most catch clauses.
5979 duk_int_t varmap_value
; /* for storing/restoring the varmap binding for catch variable */
5981 DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(ctx
)));
5983 trycatch_flags
|= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH
;
5985 pc_catch
= duk__get_current_pc(comp_ctx
);
5987 duk__advance(comp_ctx
);
5988 duk__advance_expect(comp_ctx
, DUK_TOK_LPAREN
);
5990 if (comp_ctx
->curr_token
.t
!= DUK_TOK_IDENTIFIER
) {
5991 /* Identifier, i.e. don't allow reserved words */
5994 h_var
= comp_ctx
->curr_token
.str1
;
5995 DUK_ASSERT(h_var
!= NULL
);
5997 duk_push_hstring(ctx
, h_var
); /* keep in on valstack, use borrowed ref below */
5999 if (comp_ctx
->curr_func
.is_strict
&&
6000 ((h_var
== DUK_HTHREAD_STRING_EVAL(thr
)) ||
6001 (h_var
== DUK_HTHREAD_STRING_LC_ARGUMENTS(thr
)))) {
6002 DUK_DDD(DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError"));
6007 rc_varname
= duk__getconst(comp_ctx
);
6008 DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)",
6009 (unsigned long) rc_varname
, (long) rc_varname
));
6011 duk__advance(comp_ctx
);
6012 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
6014 duk__advance_expect(comp_ctx
, DUK_TOK_LCURLY
);
6016 DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT",
6017 (duk_tval
*) duk_get_tval(ctx
, comp_ctx
->curr_func
.varmap_idx
)));
6020 duk_get_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
);
6021 if (duk_is_undefined(ctx
, -1)) {
6023 } else if (duk_is_null(ctx
, -1)) {
6026 DUK_ASSERT(duk_is_number(ctx
, -1));
6027 varmap_value
= duk_get_int(ctx
, -1);
6028 DUK_ASSERT(varmap_value
>= 0);
6033 /* It'd be nice to do something like this - but it doesn't
6034 * work for closures created inside the catch clause.
6037 duk_push_int(ctx
, (duk_int_t
) (reg_catch
+ 0));
6038 duk_put_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
);
6042 duk_put_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
);
6044 duk__emit_a_bc(comp_ctx
,
6045 DUK_OP_PUTVAR
| DUK__EMIT_FLAG_A_IS_SOURCE
,
6046 (duk_regconst_t
) (reg_catch
+ 0) /*value*/,
6047 rc_varname
/*varname*/);
6049 DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
6050 (duk_tval
*) duk_get_tval(ctx
, comp_ctx
->curr_func
.varmap_idx
)));
6052 duk__parse_stmts(comp_ctx
, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
6053 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
6055 if (varmap_value
== -2) {
6057 duk_del_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
);
6059 if (varmap_value
== -1) {
6062 DUK_ASSERT(varmap_value
>= 0);
6063 duk_push_int(ctx
, varmap_value
);
6065 duk_put_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
);
6067 /* varname is popped by above code */
6069 DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
6070 (duk_tval
*) duk_get_tval(ctx
, comp_ctx
->curr_func
.varmap_idx
)));
6072 duk__emit_extraop_only(comp_ctx
,
6073 DUK_EXTRAOP_ENDCATCH
);
6076 * XXX: for now, indicate that an expensive catch binding
6077 * declarative environment is always needed. If we don't
6078 * need it, we don't need the const_varname either.
6081 trycatch_flags
|= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING
;
6083 DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(ctx
)));
6086 if (comp_ctx
->curr_token
.t
== DUK_TOK_FINALLY
) {
6087 trycatch_flags
|= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY
;
6089 pc_finally
= duk__get_current_pc(comp_ctx
);
6091 duk__advance(comp_ctx
);
6093 duk__advance_expect(comp_ctx
, DUK_TOK_LCURLY
);
6094 duk__parse_stmts(comp_ctx
, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
6095 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
6096 duk__emit_extraop_b(comp_ctx
,
6098 reg_catch
); /* rethrow */
6101 if (!(trycatch_flags
& DUK_BC_TRYCATCH_FLAG_HAVE_CATCH
) &&
6102 !(trycatch_flags
& DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY
)) {
6103 /* must have catch and/or finally */
6107 /* If there's no catch block, rc_varname will be 0 and duk__patch_trycatch()
6108 * will replace the LDCONST with a NOP. For any actual constant (including
6109 * constant 0) the DUK__CONST_MARKER flag will be set in rc_varname.
6112 duk__patch_trycatch(comp_ctx
,
6119 if (trycatch_flags
& DUK_BC_TRYCATCH_FLAG_HAVE_CATCH
) {
6120 DUK_ASSERT(pc_catch
>= 0);
6121 duk__patch_jump(comp_ctx
, pc_trycatch
+ 1, pc_catch
);
6124 if (trycatch_flags
& DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY
) {
6125 DUK_ASSERT(pc_finally
>= 0);
6126 duk__patch_jump(comp_ctx
, pc_trycatch
+ 2, pc_finally
);
6128 /* without finally, the second jump slot is used to jump to end of stmt */
6129 duk__patch_jump_here(comp_ctx
, pc_trycatch
+ 2);
6132 comp_ctx
->curr_func
.catch_depth
--;
6136 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_TRY
);
6139 DUK_LOCAL
void duk__parse_with_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
) {
6140 duk_int_t pc_trycatch
;
6141 duk_int_t pc_finished
;
6142 duk_reg_t reg_catch
;
6143 duk_small_uint_t trycatch_flags
;
6145 if (comp_ctx
->curr_func
.is_strict
) {
6146 DUK_ERROR_SYNTAX(comp_ctx
->thr
, DUK_STR_WITH_IN_STRICT_MODE
);
6149 comp_ctx
->curr_func
.catch_depth
++;
6151 duk__advance(comp_ctx
); /* eat 'with' */
6153 reg_catch
= DUK__ALLOCTEMPS(comp_ctx
, 2);
6155 duk__advance_expect(comp_ctx
, DUK_TOK_LPAREN
);
6156 duk__exprtop_toforcedreg(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/, reg_catch
);
6157 duk__advance_expect(comp_ctx
, DUK_TOK_RPAREN
);
6159 pc_trycatch
= duk__get_current_pc(comp_ctx
);
6160 trycatch_flags
= DUK_BC_TRYCATCH_FLAG_WITH_BINDING
;
6161 duk__emit_a_bc(comp_ctx
,
6162 DUK_OP_TRYCATCH
| DUK__EMIT_FLAG_NO_SHUFFLE_A
,
6163 (duk_regconst_t
) trycatch_flags
/*a*/,
6164 (duk_regconst_t
) reg_catch
/*bc*/);
6165 duk__emit_invalid(comp_ctx
); /* catch jump */
6166 duk__emit_invalid(comp_ctx
); /* finished jump */
6168 duk__parse_stmt(comp_ctx
, res
, 0 /*allow_source_elem*/);
6169 duk__emit_extraop_only(comp_ctx
,
6170 DUK_EXTRAOP_ENDTRY
);
6172 pc_finished
= duk__get_current_pc(comp_ctx
);
6174 duk__patch_jump(comp_ctx
, pc_trycatch
+ 2, pc_finished
);
6176 comp_ctx
->curr_func
.catch_depth
--;
6179 DUK_LOCAL duk_int_t
duk__stmt_label_site(duk_compiler_ctx
*comp_ctx
, duk_int_t label_id
) {
6180 /* if a site already exists, nop: max one label site per statement */
6181 if (label_id
>= 0) {
6185 label_id
= comp_ctx
->curr_func
.label_next
++;
6186 DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld", (long) label_id
));
6188 duk__emit_extraop_bc(comp_ctx
,
6190 (duk_regconst_t
) label_id
);
6191 duk__emit_invalid(comp_ctx
);
6192 duk__emit_invalid(comp_ctx
);
6197 /* Parse a single statement.
6199 * Creates a label site (with an empty label) automatically for iteration
6200 * statements. Also "peels off" any label statements for explicit labels.
6202 DUK_LOCAL
void duk__parse_stmt(duk_compiler_ctx
*comp_ctx
, duk_ivalue
*res
, duk_bool_t allow_source_elem
) {
6203 duk_hthread
*thr
= comp_ctx
->thr
;
6204 duk_context
*ctx
= (duk_context
*) thr
;
6205 duk_bool_t dir_prol_at_entry
; /* directive prologue status at entry */
6206 duk_reg_t temp_at_entry
;
6207 duk_uarridx_t labels_len_at_entry
;
6208 duk_int_t pc_at_entry
; /* assumed to also be PC of "LABEL" */
6210 duk_small_uint_t stmt_flags
= 0;
6211 duk_int_t label_id
= -1;
6212 duk_small_uint_t tok
;
6214 DUK__RECURSION_INCREASE(comp_ctx
, thr
);
6216 temp_at_entry
= DUK__GETTEMP(comp_ctx
);
6217 pc_at_entry
= duk__get_current_pc(comp_ctx
);
6218 labels_len_at_entry
= (duk_uarridx_t
) duk_get_length(ctx
, comp_ctx
->curr_func
.labelnames_idx
);
6219 stmt_id
= comp_ctx
->curr_func
.stmt_next
++;
6220 dir_prol_at_entry
= comp_ctx
->curr_func
.in_directive_prologue
;
6224 DUK_DDD(DUK_DDDPRINT("parsing a statement, stmt_id=%ld, temp_at_entry=%ld, labels_len_at_entry=%ld, "
6225 "is_strict=%ld, in_directive_prologue=%ld, catch_depth=%ld",
6226 (long) stmt_id
, (long) temp_at_entry
, (long) labels_len_at_entry
,
6227 (long) comp_ctx
->curr_func
.is_strict
, (long) comp_ctx
->curr_func
.in_directive_prologue
,
6228 (long) comp_ctx
->curr_func
.catch_depth
));
6230 /* The directive prologue flag is cleared by default so that it is
6231 * unset for any recursive statement parsing. It is only "revived"
6232 * if a directive is detected. (We could also make directives only
6233 * allowed if 'allow_source_elem' was true.)
6235 comp_ctx
->curr_func
.in_directive_prologue
= 0;
6239 DUK_DDD(DUK_DDDPRINT("try stmt parse, stmt_id=%ld, label_id=%ld, allow_source_elem=%ld, catch_depth=%ld",
6240 (long) stmt_id
, (long) label_id
, (long) allow_source_elem
,
6241 (long) comp_ctx
->curr_func
.catch_depth
));
6244 * Detect iteration statements; if encountered, establish an
6248 tok
= comp_ctx
->curr_token
.t
;
6249 if (tok
== DUK_TOK_FOR
|| tok
== DUK_TOK_DO
|| tok
== DUK_TOK_WHILE
||
6250 tok
== DUK_TOK_SWITCH
) {
6251 DUK_DDD(DUK_DDDPRINT("iteration/switch statement -> add empty label"));
6253 label_id
= duk__stmt_label_site(comp_ctx
, label_id
);
6254 duk__add_label(comp_ctx
,
6255 DUK_HTHREAD_STRING_EMPTY_STRING(thr
),
6256 pc_at_entry
/*pc_label*/,
6261 * Main switch for statement / source element type.
6264 switch (comp_ctx
->curr_token
.t
) {
6265 case DUK_TOK_FUNCTION
: {
6267 * Function declaration, function expression, or (non-standard)
6268 * function statement.
6270 * The E5 specification only allows function declarations at
6271 * the top level (in "source elements"). An ExpressionStatement
6272 * is explicitly not allowed to begin with a "function" keyword
6273 * (E5 Section 12.4). Hence any non-error semantics for such
6274 * non-top-level statements are non-standard. Duktape semantics
6275 * for function statements are modelled after V8, see
6276 * test-dev-func-decl-outside-top.js.
6279 #if defined(DUK_USE_NONSTD_FUNC_STMT)
6280 /* Lenient: allow function declarations outside top level in
6281 * non-strict mode but reject them in strict mode.
6283 if (allow_source_elem
|| !comp_ctx
->curr_func
.is_strict
)
6284 #else /* DUK_USE_NONSTD_FUNC_STMT */
6285 /* Strict: never allow function declarations outside top level. */
6286 if (allow_source_elem
)
6287 #endif /* DUK_USE_NONSTD_FUNC_STMT */
6289 /* FunctionDeclaration: not strictly a statement but handled as such.
6291 * O(depth^2) parse count for inner functions is handled by recording a
6292 * lexer offset on the first compilation pass, so that the function can
6293 * be efficiently skipped on the second pass. This is encapsulated into
6294 * duk__parse_func_like_fnum().
6299 DUK_DDD(DUK_DDDPRINT("function declaration statement"));
6301 duk__advance(comp_ctx
); /* eat 'function' */
6302 fnum
= duk__parse_func_like_fnum(comp_ctx
, 1 /*is_decl*/, 0 /*is_setget*/);
6304 if (comp_ctx
->curr_func
.in_scanning
) {
6306 duk_hstring
*h_funcname
;
6308 duk_get_prop_index(ctx
, comp_ctx
->curr_func
.funcs_idx
, fnum
* 3);
6309 duk_get_prop_stridx(ctx
, -1, DUK_STRIDX_NAME
); /* -> [ ... func name ] */
6310 h_funcname
= duk_get_hstring(ctx
, -1);
6311 DUK_ASSERT(h_funcname
!= NULL
);
6313 DUK_DDD(DUK_DDDPRINT("register function declaration %!O in pass 1, fnum %ld",
6314 (duk_heaphdr
*) h_funcname
, (long) fnum
));
6315 n
= (duk_uarridx_t
) duk_get_length(ctx
, comp_ctx
->curr_func
.decls_idx
);
6316 duk_push_hstring(ctx
, h_funcname
);
6317 duk_put_prop_index(ctx
, comp_ctx
->curr_func
.decls_idx
, n
);
6318 duk_push_int(ctx
, (duk_int_t
) (DUK_DECL_TYPE_FUNC
+ (fnum
<< 8)));
6319 duk_put_prop_index(ctx
, comp_ctx
->curr_func
.decls_idx
, n
+ 1);
6324 /* no statement value (unlike function expression) */
6328 DUK_ERROR_SYNTAX(thr
, DUK_STR_FUNC_STMT_NOT_ALLOWED
);
6332 case DUK_TOK_LCURLY
: {
6333 DUK_DDD(DUK_DDDPRINT("block statement"));
6334 duk__advance(comp_ctx
);
6335 duk__parse_stmts(comp_ctx
, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
6336 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
6337 if (label_id
>= 0) {
6338 duk__patch_jump_here(comp_ctx
, pc_at_entry
+ 1); /* break jump */
6343 case DUK_TOK_CONST
: {
6344 DUK_DDD(DUK_DDDPRINT("constant declaration statement"));
6345 duk__parse_var_stmt(comp_ctx
, res
, DUK__EXPR_FLAG_REQUIRE_INIT
/*expr_flags*/);
6346 stmt_flags
= DUK__HAS_TERM
;
6350 DUK_DDD(DUK_DDDPRINT("variable declaration statement"));
6351 duk__parse_var_stmt(comp_ctx
, res
, 0 /*expr_flags*/);
6352 stmt_flags
= DUK__HAS_TERM
;
6355 case DUK_TOK_SEMICOLON
: {
6356 /* empty statement with an explicit semicolon */
6357 DUK_DDD(DUK_DDDPRINT("empty statement"));
6358 stmt_flags
= DUK__HAS_TERM
;
6362 DUK_DDD(DUK_DDDPRINT("if statement"));
6363 duk__parse_if_stmt(comp_ctx
, res
);
6364 if (label_id
>= 0) {
6365 duk__patch_jump_here(comp_ctx
, pc_at_entry
+ 1); /* break jump */
6372 * Do-while statement is mostly trivial, but there is special
6373 * handling for automatic semicolon handling (triggered by the
6374 * DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at:
6376 * https://bugs.ecmascript.org/show_bug.cgi?id=8
6378 * See doc/compiler.rst for details.
6380 DUK_DDD(DUK_DDDPRINT("do statement"));
6381 DUK_ASSERT(label_id
>= 0);
6382 duk__update_label_flags(comp_ctx
,
6384 DUK_LABEL_FLAG_ALLOW_BREAK
| DUK_LABEL_FLAG_ALLOW_CONTINUE
);
6385 duk__parse_do_stmt(comp_ctx
, res
, pc_at_entry
);
6386 stmt_flags
= DUK__HAS_TERM
| DUK__ALLOW_AUTO_SEMI_ALWAYS
; /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */
6389 case DUK_TOK_WHILE
: {
6390 DUK_DDD(DUK_DDDPRINT("while statement"));
6391 DUK_ASSERT(label_id
>= 0);
6392 duk__update_label_flags(comp_ctx
,
6394 DUK_LABEL_FLAG_ALLOW_BREAK
| DUK_LABEL_FLAG_ALLOW_CONTINUE
);
6395 duk__parse_while_stmt(comp_ctx
, res
, pc_at_entry
);
6401 * For/for-in statement is complicated to parse because
6402 * determining the statement type (three-part for vs. a
6403 * for-in) requires potential backtracking.
6405 * See the helper for the messy stuff.
6407 DUK_DDD(DUK_DDDPRINT("for/for-in statement"));
6408 DUK_ASSERT(label_id
>= 0);
6409 duk__update_label_flags(comp_ctx
,
6411 DUK_LABEL_FLAG_ALLOW_BREAK
| DUK_LABEL_FLAG_ALLOW_CONTINUE
);
6412 duk__parse_for_stmt(comp_ctx
, res
, pc_at_entry
);
6416 case DUK_TOK_CONTINUE
:
6417 case DUK_TOK_BREAK
: {
6418 DUK_DDD(DUK_DDDPRINT("break/continue statement"));
6419 duk__parse_break_or_continue_stmt(comp_ctx
, res
);
6420 stmt_flags
= DUK__HAS_TERM
| DUK__IS_TERMINAL
;
6423 case DUK_TOK_RETURN
: {
6424 DUK_DDD(DUK_DDDPRINT("return statement"));
6425 duk__parse_return_stmt(comp_ctx
, res
);
6426 stmt_flags
= DUK__HAS_TERM
| DUK__IS_TERMINAL
;
6429 case DUK_TOK_WITH
: {
6430 DUK_DDD(DUK_DDDPRINT("with statement"));
6431 comp_ctx
->curr_func
.with_depth
++;
6432 duk__parse_with_stmt(comp_ctx
, res
);
6433 if (label_id
>= 0) {
6434 duk__patch_jump_here(comp_ctx
, pc_at_entry
+ 1); /* break jump */
6436 comp_ctx
->curr_func
.with_depth
--;
6440 case DUK_TOK_SWITCH
: {
6442 * The switch statement is pretty messy to compile.
6443 * See the helper for details.
6445 DUK_DDD(DUK_DDDPRINT("switch statement"));
6446 DUK_ASSERT(label_id
>= 0);
6447 duk__update_label_flags(comp_ctx
,
6449 DUK_LABEL_FLAG_ALLOW_BREAK
); /* don't allow continue */
6450 duk__parse_switch_stmt(comp_ctx
, res
, pc_at_entry
);
6454 case DUK_TOK_THROW
: {
6455 DUK_DDD(DUK_DDDPRINT("throw statement"));
6456 duk__parse_throw_stmt(comp_ctx
, res
);
6457 stmt_flags
= DUK__HAS_TERM
| DUK__IS_TERMINAL
;
6461 DUK_DDD(DUK_DDDPRINT("try statement"));
6462 duk__parse_try_stmt(comp_ctx
, res
);
6466 case DUK_TOK_DEBUGGER
: {
6467 duk__advance(comp_ctx
);
6468 #if defined(DUK_USE_DEBUGGER_SUPPORT)
6469 DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode"));
6470 duk__emit_extraop_only(comp_ctx
, DUK_EXTRAOP_DEBUGGER
);
6472 DUK_DDD(DUK_DDDPRINT("debugger statement: ignored"));
6474 stmt_flags
= DUK__HAS_TERM
;
6479 * Else, must be one of:
6480 * - ExpressionStatement, possibly a directive (String)
6481 * - LabelledStatement (Identifier followed by ':')
6483 * Expressions beginning with 'function' keyword are covered by a case
6484 * above (such expressions are not allowed in standard E5 anyway).
6485 * Also expressions starting with '{' are interpreted as block
6486 * statements. See E5 Section 12.4.
6488 * Directive detection is tricky; see E5 Section 14.1 on directive
6489 * prologue. A directive is an expression statement with a single
6490 * string literal and an explicit or automatic semicolon. Escape
6491 * characters are significant and no parens etc are allowed:
6493 * 'use strict'; // valid 'use strict' directive
6494 * 'use\u0020strict'; // valid directive, not a 'use strict' directive
6495 * ('use strict'); // not a valid directive
6497 * The expression is determined to consist of a single string literal
6498 * based on duk__expr_nud() and duk__expr_led() call counts. The string literal
6499 * of a 'use strict' directive is determined to lack any escapes based
6500 * num_escapes count from the lexer. Note that other directives may be
6501 * allowed to contain escapes, so a directive with escapes does not
6502 * terminate a directive prologue.
6504 * We rely on the fact that the expression parser will not emit any
6505 * code for a single token expression. However, it will generate an
6506 * intermediate value which we will then successfully ignore.
6508 * A similar approach is used for labels.
6511 duk_bool_t single_token
;
6513 DUK_DDD(DUK_DDDPRINT("expression statement"));
6514 duk__exprtop(comp_ctx
, res
, DUK__BP_FOR_EXPR
/*rbp_flags*/);
6516 single_token
= (comp_ctx
->curr_func
.nud_count
== 1 && /* one token */
6517 comp_ctx
->curr_func
.led_count
== 0); /* no operators */
6520 comp_ctx
->prev_token
.t
== DUK_TOK_IDENTIFIER
&&
6521 comp_ctx
->curr_token
.t
== DUK_TOK_COLON
) {
6529 DUK_ASSERT(res
->t
== DUK_IVAL_VAR
);
6530 DUK_ASSERT(res
->x1
.t
== DUK_ISPEC_VALUE
);
6531 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx
, res
->x1
.valstack_idx
)));
6532 h_lab
= comp_ctx
->prev_token
.str1
;
6533 DUK_ASSERT(h_lab
!= NULL
);
6535 DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'",
6536 (duk_heaphdr
*) h_lab
));
6538 duk__advance(comp_ctx
); /* eat colon */
6540 label_id
= duk__stmt_label_site(comp_ctx
, label_id
);
6542 duk__add_label(comp_ctx
,
6544 pc_at_entry
/*pc_label*/,
6547 /* a statement following a label cannot be a source element
6548 * (a function declaration).
6550 allow_source_elem
= 0;
6552 DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing"));
6558 if (dir_prol_at_entry
&& /* still in prologue */
6559 single_token
&& /* single string token */
6560 comp_ctx
->prev_token
.t
== DUK_TOK_STRING
) {
6562 * Detected a directive
6567 DUK_ASSERT(res
->t
== DUK_IVAL_PLAIN
);
6568 DUK_ASSERT(res
->x1
.t
== DUK_ISPEC_VALUE
);
6569 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx
, res
->x1
.valstack_idx
)));
6570 h_dir
= comp_ctx
->prev_token
.str1
;
6571 DUK_ASSERT(h_dir
!= NULL
);
6573 DUK_DDD(DUK_DDDPRINT("potential directive: %!O", h_dir
));
6575 stmt_flags
|= DUK__STILL_PROLOGUE
;
6577 /* Note: escaped characters differentiate directives */
6579 if (comp_ctx
->prev_token
.num_escapes
> 0) {
6580 DUK_DDD(DUK_DDDPRINT("directive contains escapes: valid directive "
6581 "but we ignore such directives"));
6584 * The length comparisons are present to handle
6585 * strings like "use strict\u0000foo" as required.
6588 if (DUK_HSTRING_GET_BYTELEN(h_dir
) == 10 &&
6589 DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir
), "use strict", 10) == 0) {
6590 #if defined(DUK_USE_STRICT_DECL)
6591 DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld",
6592 (long) comp_ctx
->curr_func
.is_strict
, (long) 1));
6593 comp_ctx
->curr_func
.is_strict
= 1;
6595 DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring"));
6597 } else if (DUK_HSTRING_GET_BYTELEN(h_dir
) == 14 &&
6598 DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir
), "use duk notail", 14) == 0) {
6599 DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld",
6600 (long) comp_ctx
->curr_func
.is_notail
, (long) 1));
6601 comp_ctx
->curr_func
.is_notail
= 1;
6603 DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
6604 "directive prologue", (duk_hobject
*) h_dir
));
6608 DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; "
6609 "prologue terminated if still active"));
6612 stmt_flags
|= DUK__HAS_VAL
| DUK__HAS_TERM
;
6614 } /* end switch (tok) */
6617 * Statement value handling.
6619 * Global code and eval code has an implicit return value
6620 * which comes from the last statement with a value
6621 * (technically a non-"empty" continuation, which is
6622 * different from an empty statement).
6624 * Since we don't know whether a later statement will
6625 * override the value of the current statement, we need
6626 * to coerce the statement value to a register allocated
6627 * for implicit return values. In other cases we need
6628 * to coerce the statement value to a plain value to get
6629 * any side effects out (consider e.g. "foo.bar;").
6632 /* XXX: what about statements which leave a half-cooked value in 'res'
6633 * but have no stmt value? Any such statements?
6636 if (stmt_flags
& DUK__HAS_VAL
) {
6637 duk_reg_t reg_stmt_value
= comp_ctx
->curr_func
.reg_stmt_value
;
6638 if (reg_stmt_value
>= 0) {
6639 duk__ivalue_toforcedreg(comp_ctx
, res
, reg_stmt_value
);
6641 duk__ivalue_toplain_ignore(comp_ctx
, res
);
6648 * Statement terminator check, including automatic semicolon
6649 * handling. After this step, 'curr_tok' should be the first
6650 * token after a possible statement terminator.
6653 if (stmt_flags
& DUK__HAS_TERM
) {
6654 if (comp_ctx
->curr_token
.t
== DUK_TOK_SEMICOLON
) {
6655 DUK_DDD(DUK_DDDPRINT("explicit semicolon terminates statement"));
6656 duk__advance(comp_ctx
);
6658 if (comp_ctx
->curr_token
.allow_auto_semi
) {
6659 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement"));
6660 } else if (stmt_flags
& DUK__ALLOW_AUTO_SEMI_ALWAYS
) {
6661 /* XXX: make this lenience dependent on flags or strictness? */
6662 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility "
6663 "even though no lineterm present before next token)"));
6665 DUK_ERROR_SYNTAX(thr
, DUK_STR_UNTERMINATED_STMT
);
6669 DUK_DDD(DUK_DDDPRINT("statement has no terminator"));
6673 * Directive prologue tracking.
6676 if (stmt_flags
& DUK__STILL_PROLOGUE
) {
6677 DUK_DDD(DUK_DDDPRINT("setting in_directive_prologue"));
6678 comp_ctx
->curr_func
.in_directive_prologue
= 1;
6682 * Cleanups (all statement parsing flows through here).
6684 * Pop label site and reset labels. Reset 'next temp' to value at
6685 * entry to reuse temps.
6688 if (label_id
>= 0) {
6689 duk__emit_extraop_bc(comp_ctx
,
6690 DUK_EXTRAOP_ENDLABEL
,
6691 (duk_regconst_t
) label_id
);
6694 DUK__SETTEMP(comp_ctx
, temp_at_entry
);
6696 duk__reset_labels_to_length(comp_ctx
, labels_len_at_entry
);
6698 /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */
6700 DUK__RECURSION_DECREASE(comp_ctx
, thr
);
6704 #undef DUK__HAS_TERM
6705 #undef DUK__ALLOW_AUTO_SEMI_ALWAYS
6708 * Parse a statement list.
6710 * Handles automatic semicolon insertion and implicit return value.
6712 * Upon entry, 'curr_tok' should contain the first token of the first
6713 * statement (parsed in the "allow regexp literal" mode). Upon exit,
6714 * 'curr_tok' contains the token following the statement list terminator
6715 * (EOF or closing brace).
6718 DUK_LOCAL
void duk__parse_stmts(duk_compiler_ctx
*comp_ctx
, duk_bool_t allow_source_elem
, duk_bool_t expect_eof
) {
6719 duk_hthread
*thr
= comp_ctx
->thr
;
6720 duk_context
*ctx
= (duk_context
*) thr
;
6721 duk_ivalue res_alloc
;
6722 duk_ivalue
*res
= &res_alloc
;
6724 /* Setup state. Initial ivalue is 'undefined'. */
6726 duk_require_stack(ctx
, DUK__PARSE_STATEMENTS_SLOTS
);
6728 /* XXX: 'res' setup can be moved to function body level; in fact, two 'res'
6729 * intermediate values suffice for parsing of each function. Nesting is needed
6730 * for nested functions (which may occur inside expressions).
6733 DUK_MEMZERO(&res_alloc
, sizeof(res_alloc
));
6734 res
->t
= DUK_IVAL_PLAIN
;
6735 res
->x1
.t
= DUK_ISPEC_VALUE
;
6736 res
->x1
.valstack_idx
= duk_get_top(ctx
);
6737 res
->x2
.valstack_idx
= res
->x1
.valstack_idx
+ 1;
6738 duk_push_undefined(ctx
);
6739 duk_push_undefined(ctx
);
6741 /* Parse statements until a closing token (EOF or '}') is found. */
6744 /* Check whether statement list ends. */
6747 if (comp_ctx
->curr_token
.t
== DUK_TOK_EOF
) {
6751 if (comp_ctx
->curr_token
.t
== DUK_TOK_RCURLY
) {
6756 /* Check statement type based on the first token type.
6758 * Note: expression parsing helpers expect 'curr_tok' to
6759 * contain the first token of the expression upon entry.
6762 DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)", (long) comp_ctx
->curr_token
.t
));
6764 duk__parse_stmt(comp_ctx
, res
, allow_source_elem
);
6767 duk__advance(comp_ctx
);
6769 /* Tear down state. */
6775 * Declaration binding instantiation conceptually happens when calling a
6776 * function; for us it essentially means that function prologue. The
6777 * conceptual process is described in E5 Section 10.5.
6779 * We need to keep track of all encountered identifiers to (1) create an
6780 * identifier-to-register map ("varmap"); and (2) detect duplicate
6781 * declarations. Identifiers which are not bound to registers still need
6782 * to be tracked for detecting duplicates. Currently such identifiers
6783 * are put into the varmap with a 'null' value, which is later cleaned up.
6785 * To support functions with a large number of variable and function
6786 * declarations, registers are not allocated beyond a certain limit;
6787 * after that limit, variables and functions need slow path access.
6788 * Arguments are currently always register bound, which imposes a hard
6789 * (and relatively small) argument count limit.
6791 * Some bindings in E5 are not configurable (= deletable) and almost all
6792 * are mutable (writable). Exceptions are:
6794 * - The 'arguments' binding, established only if no shadowing argument
6795 * or function declaration exists. We handle 'arguments' creation
6796 * and binding through an explicit slow path environment record.
6798 * - The "name" binding for a named function expression. This is also
6799 * handled through an explicit slow path environment record.
6802 /* XXX: add support for variables to not be register bound always, to
6803 * handle cases with a very large number of variables?
6806 DUK_LOCAL
void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx
*comp_ctx
, duk_reg_t
*out_stmt_value_reg
) {
6807 duk_hthread
*thr
= comp_ctx
->thr
;
6808 duk_context
*ctx
= (duk_context
*) thr
;
6809 duk_hstring
*h_name
;
6810 duk_bool_t configurable_bindings
;
6811 duk_uarridx_t num_args
;
6812 duk_uarridx_t num_decls
;
6813 duk_regconst_t rc_name
;
6814 duk_small_uint_t declvar_flags
;
6816 #ifdef DUK_USE_ASSERTIONS
6817 duk_idx_t entry_top
;
6820 #ifdef DUK_USE_ASSERTIONS
6821 entry_top
= duk_get_top(ctx
);
6828 configurable_bindings
= comp_ctx
->curr_func
.is_eval
;
6829 DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld", (long) configurable_bindings
));
6831 /* varmap is already in comp_ctx->curr_func.varmap_idx */
6834 * Function formal arguments, always bound to registers
6835 * (there's no support for shuffling them now).
6838 num_args
= (duk_uarridx_t
) duk_get_length(ctx
, comp_ctx
->curr_func
.argnames_idx
);
6839 DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args
));
6840 /* XXX: check num_args */
6842 for (i
= 0; i
< num_args
; i
++) {
6843 duk_get_prop_index(ctx
, comp_ctx
->curr_func
.argnames_idx
, i
);
6844 h_name
= duk_get_hstring(ctx
, -1);
6845 DUK_ASSERT(h_name
!= NULL
);
6847 if (comp_ctx
->curr_func
.is_strict
) {
6848 if (duk__hstring_is_eval_or_arguments(comp_ctx
, h_name
)) {
6849 DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError"));
6853 if (duk_has_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
)) {
6854 DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
6858 /* Ensure argument name is not a reserved word in current
6859 * (final) strictness. Formal argument parsing may not
6860 * catch reserved names if strictness changes during
6863 * We only need to do this in strict mode because non-strict
6864 * keyword are always detected in formal argument parsing.
6867 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name
)) {
6872 /* overwrite any previous binding of the same name; the effect is
6873 * that last argument of a certain name wins.
6876 /* only functions can have arguments */
6877 DUK_ASSERT(comp_ctx
->curr_func
.is_function
);
6878 duk_push_uarridx(ctx
, i
); /* -> [ ... name index ] */
6879 duk_put_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
); /* -> [ ... ] */
6881 /* no code needs to be emitted, the regs already have values */
6884 /* use temp_next for tracking register allocations */
6885 DUK__SETTEMP_CHECKMAX(comp_ctx
, (duk_reg_t
) num_args
);
6888 * After arguments, allocate special registers (like shuffling temps)
6891 if (out_stmt_value_reg
) {
6892 *out_stmt_value_reg
= DUK__ALLOCTEMP(comp_ctx
);
6894 if (comp_ctx
->curr_func
.needs_shuffle
) {
6895 duk_reg_t shuffle_base
= DUK__ALLOCTEMPS(comp_ctx
, 3);
6896 comp_ctx
->curr_func
.shuffle1
= shuffle_base
;
6897 comp_ctx
->curr_func
.shuffle2
= shuffle_base
+ 1;
6898 comp_ctx
->curr_func
.shuffle3
= shuffle_base
+ 2;
6899 DUK_D(DUK_DPRINT("shuffle registers needed by function, allocated: %ld %ld %ld",
6900 (long) comp_ctx
->curr_func
.shuffle1
,
6901 (long) comp_ctx
->curr_func
.shuffle2
,
6902 (long) comp_ctx
->curr_func
.shuffle3
));
6904 if (comp_ctx
->curr_func
.temp_next
> 0x100) {
6905 DUK_D(DUK_DPRINT("not enough 8-bit regs: temp_next=%ld", (long) comp_ctx
->curr_func
.temp_next
));
6906 goto error_outofregs
;
6910 * Function declarations
6913 num_decls
= (duk_uarridx_t
) duk_get_length(ctx
, comp_ctx
->curr_func
.decls_idx
);
6914 DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T",
6916 (duk_tval
*) duk_get_tval(ctx
, comp_ctx
->curr_func
.decls_idx
)));
6917 for (i
= 0; i
< num_decls
; i
+= 2) {
6918 duk_int_t decl_type
;
6921 duk_get_prop_index(ctx
, comp_ctx
->curr_func
.decls_idx
, i
+ 1); /* decl type */
6922 decl_type
= duk_to_int(ctx
, -1);
6923 fnum
= decl_type
>> 8; /* XXX: macros */
6924 decl_type
= decl_type
& 0xff;
6927 if (decl_type
!= DUK_DECL_TYPE_FUNC
) {
6931 duk_get_prop_index(ctx
, comp_ctx
->curr_func
.decls_idx
, i
); /* decl name */
6934 if (comp_ctx
->curr_func
.is_function
) {
6937 if (duk_has_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
)) {
6938 /* shadowed; update value */
6940 duk_get_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
);
6941 reg_bind
= duk_to_int(ctx
, -1); /* [ ... name reg_bind ] */
6942 duk__emit_a_bc(comp_ctx
,
6944 (duk_regconst_t
) reg_bind
,
6945 (duk_regconst_t
) fnum
);
6947 /* function: always register bound */
6948 reg_bind
= DUK__ALLOCTEMP(comp_ctx
);
6949 duk__emit_a_bc(comp_ctx
,
6951 (duk_regconst_t
) reg_bind
,
6952 (duk_regconst_t
) fnum
);
6953 duk_push_int(ctx
, (duk_int_t
) reg_bind
);
6956 /* Function declaration for global/eval code is emitted even
6957 * for duplicates, because of E5 Section 10.5, step 5.e of
6958 * E5.1 (special behavior for variable bound to global object).
6960 * DECLVAR will not re-declare a variable as such, but will
6961 * update the binding value.
6964 duk_reg_t reg_temp
= DUK__ALLOCTEMP(comp_ctx
);
6966 rc_name
= duk__getconst(comp_ctx
);
6969 duk__emit_a_bc(comp_ctx
,
6971 (duk_regconst_t
) reg_temp
,
6972 (duk_regconst_t
) fnum
);
6974 declvar_flags
= DUK_PROPDESC_FLAG_WRITABLE
|
6975 DUK_PROPDESC_FLAG_ENUMERABLE
|
6976 DUK_BC_DECLVAR_FLAG_FUNC_DECL
;
6978 if (configurable_bindings
) {
6979 declvar_flags
|= DUK_PROPDESC_FLAG_CONFIGURABLE
;
6982 duk__emit_a_b_c(comp_ctx
,
6983 DUK_OP_DECLVAR
| DUK__EMIT_FLAG_NO_SHUFFLE_A
,
6984 (duk_regconst_t
) declvar_flags
/*flags*/,
6986 (duk_regconst_t
) reg_temp
/*value*/);
6988 DUK__SETTEMP(comp_ctx
, reg_temp
); /* forget temp */
6991 DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T",
6992 (duk_tval
*) duk_get_tval(ctx
, -2),
6993 (duk_tval
*) duk_get_tval(ctx
, -1)));
6995 duk_put_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
); /* [ ... name reg/null ] -> [ ... ] */
6999 * 'arguments' binding is special; if a shadowing argument or
7000 * function declaration exists, an arguments object will
7001 * definitely not be needed, regardless of whether the identifier
7002 * 'arguments' is referenced inside the function body.
7005 if (duk_has_prop_stridx(ctx
, comp_ctx
->curr_func
.varmap_idx
, DUK_STRIDX_LC_ARGUMENTS
)) {
7006 DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
7007 "-> arguments object creation can be skipped"));
7008 comp_ctx
->curr_func
.is_arguments_shadowed
= 1;
7012 * Variable declarations.
7014 * Unlike function declarations, variable declaration values don't get
7015 * assigned on entry. If a binding of the same name already exists, just
7016 * ignore it silently.
7019 for (i
= 0; i
< num_decls
; i
+= 2) {
7020 duk_int_t decl_type
;
7022 duk_get_prop_index(ctx
, comp_ctx
->curr_func
.decls_idx
, i
+ 1); /* decl type */
7023 decl_type
= duk_to_int(ctx
, -1);
7024 decl_type
= decl_type
& 0xff;
7027 if (decl_type
!= DUK_DECL_TYPE_VAR
) {
7031 duk_get_prop_index(ctx
, comp_ctx
->curr_func
.decls_idx
, i
); /* decl name */
7033 if (duk_has_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
)) {
7034 /* shadowed, ignore */
7036 duk_get_prop_index(ctx
, comp_ctx
->curr_func
.decls_idx
, i
); /* decl name */
7037 h_name
= duk_get_hstring(ctx
, -1);
7038 DUK_ASSERT(h_name
!= NULL
);
7040 if (h_name
== DUK_HTHREAD_STRING_LC_ARGUMENTS(thr
) &&
7041 !comp_ctx
->curr_func
.is_arguments_shadowed
) {
7042 /* E5 Section steps 7-8 */
7043 DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
7044 "but appears as a variable declaration -> treat as "
7045 "a no-op for variable declaration purposes"));
7051 if (comp_ctx
->curr_func
.is_function
) {
7052 duk_reg_t reg_bind
= DUK__ALLOCTEMP(comp_ctx
);
7053 /* no need to init reg, it will be undefined on entry */
7054 duk_push_int(ctx
, (duk_int_t
) reg_bind
);
7057 rc_name
= duk__getconst(comp_ctx
);
7060 declvar_flags
= DUK_PROPDESC_FLAG_WRITABLE
|
7061 DUK_PROPDESC_FLAG_ENUMERABLE
|
7062 DUK_BC_DECLVAR_FLAG_UNDEF_VALUE
;
7063 if (configurable_bindings
) {
7064 declvar_flags
|= DUK_PROPDESC_FLAG_CONFIGURABLE
;
7067 duk__emit_a_b_c(comp_ctx
,
7068 DUK_OP_DECLVAR
| DUK__EMIT_FLAG_NO_SHUFFLE_A
,
7069 (duk_regconst_t
) declvar_flags
/*flags*/,
7071 (duk_regconst_t
) 0 /*value*/);
7074 duk_put_prop(ctx
, comp_ctx
->curr_func
.varmap_idx
); /* [ ... name reg/null ] -> [ ... ] */
7082 DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld",
7083 (duk_tval
*) duk_get_tval(ctx
, comp_ctx
->curr_func
.varmap_idx
),
7084 (long) comp_ctx
->curr_func
.is_arguments_shadowed
));
7086 DUK_ASSERT_TOP(ctx
, entry_top
);
7090 DUK_ERROR_RANGE(thr
, DUK_STR_REG_LIMIT
);
7095 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_ARG_NAME
);
7101 * Parse a function-body-like expression (FunctionBody or Program
7102 * in E5 grammar) using a two-pass parse. The productions appear
7103 * in the following contexts:
7105 * - function expression
7106 * - function statement
7107 * - function declaration
7108 * - getter in object literal
7109 * - setter in object literal
7112 * - Function constructor body
7114 * This function only parses the statement list of the body; the argument
7115 * list and possible function name must be initialized by the caller.
7116 * For instance, for Function constructor, the argument names are originally
7117 * on the value stack. The parsing of statements ends either at an EOF or
7118 * a closing brace; this is controlled by an input flag.
7120 * Note that there are many differences affecting parsing and even code
7123 * - Global and eval code have an implicit return value generated
7124 * by the last statement; function code does not
7126 * - Global code, eval code, and Function constructor body end in
7127 * an EOF, other bodies in a closing brace ('}')
7129 * Upon entry, 'curr_tok' is ignored and the function will pull in the
7130 * first token on its own. Upon exit, 'curr_tok' is the terminating
7131 * token (EOF or closing brace).
7134 DUK_LOCAL
void duk__parse_func_body(duk_compiler_ctx
*comp_ctx
, duk_bool_t expect_eof
, duk_bool_t implicit_return_value
, duk_small_int_t expect_token
) {
7135 duk_compiler_func
*func
;
7138 duk_reg_t reg_stmt_value
= -1;
7139 duk_lexer_point lex_pt
;
7140 duk_reg_t temp_first
;
7141 duk_small_int_t compile_round
= 1;
7143 DUK_ASSERT(comp_ctx
!= NULL
);
7145 thr
= comp_ctx
->thr
;
7146 ctx
= (duk_context
*) thr
;
7147 DUK_ASSERT(thr
!= NULL
);
7149 func
= &comp_ctx
->curr_func
;
7150 DUK_ASSERT(func
!= NULL
);
7152 DUK__RECURSION_INCREASE(comp_ctx
, thr
);
7154 duk_require_stack(ctx
, DUK__FUNCTION_BODY_REQUIRE_SLOTS
);
7157 * Store lexer position for a later rewind
7160 DUK_LEXER_GETPOINT(&comp_ctx
->lex
, &lex_pt
);
7163 * Program code (global and eval code) has an implicit return value
7164 * from the last statement value (e.g. eval("1; 2+3;") returns 3).
7165 * This is not the case with functions. If implicit statement return
7166 * value is requested, all statements are coerced to a register
7167 * allocated here, and used in the implicit return statement below.
7170 /* XXX: this is pointless here because pass 1 is throw-away */
7171 if (implicit_return_value
) {
7172 reg_stmt_value
= DUK__ALLOCTEMP(comp_ctx
);
7174 /* If an implicit return value is needed by caller, it must be
7175 * initialized to 'undefined' because we don't know whether any
7176 * non-empty (where "empty" is a continuation type, and different
7177 * from an empty statement) statements will be executed.
7179 * However, since 1st pass is a throwaway one, no need to emit
7183 duk__emit_extraop_bc(comp_ctx
,
7184 DUK_EXTRAOP_LDUNDEF
,
7192 * Gather variable/function declarations needed for second pass.
7193 * Code generated is dummy and discarded.
7196 func
->in_directive_prologue
= 1;
7197 func
->in_scanning
= 1;
7198 func
->may_direct_eval
= 0;
7199 func
->id_access_arguments
= 0;
7200 func
->id_access_slow
= 0;
7201 func
->reg_stmt_value
= reg_stmt_value
;
7202 #if defined(DUK_USE_DEBUGGER_SUPPORT)
7203 func
->min_line
= DUK_INT_MAX
;
7207 /* duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp literal" mode with current strictness */
7208 if (expect_token
>= 0) {
7209 /* Eating a left curly; regexp mode is allowed by left curly
7210 * based on duk__token_lbp[] automatically.
7212 DUK_ASSERT(expect_token
== DUK_TOK_LCURLY
);
7213 duk__update_lineinfo_currtoken(comp_ctx
);
7214 duk__advance_expect(comp_ctx
, expect_token
);
7216 /* Need to set curr_token.t because lexing regexp mode depends on current
7217 * token type. Zero value causes "allow regexp" mode.
7219 comp_ctx
->curr_token
.t
= 0;
7220 duk__advance(comp_ctx
);
7223 DUK_DDD(DUK_DDDPRINT("begin 1st pass"));
7224 duk__parse_stmts(comp_ctx
,
7225 1, /* allow source elements */
7226 expect_eof
); /* expect EOF instead of } */
7227 DUK_DDD(DUK_DDDPRINT("end 1st pass"));
7230 * Second (and possibly third) pass.
7232 * Generate actual code. In most cases the need for shuffle
7233 * registers is detected during pass 1, but in some corner cases
7234 * we'll only detect it during pass 2 and a third pass is then
7235 * needed (see GH-115).
7239 duk_bool_t needs_shuffle_before
= comp_ctx
->curr_func
.needs_shuffle
;
7245 * duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp
7246 * literal" mode with current strictness.
7248 * curr_token line number info should be initialized for pass 2 before
7249 * generating prologue, to ensure prologue bytecode gets nice line numbers.
7252 DUK_DDD(DUK_DDDPRINT("rewind lexer"));
7253 DUK_LEXER_SETPOINT(&comp_ctx
->lex
, &lex_pt
);
7254 comp_ctx
->curr_token
.t
= 0; /* this is needed for regexp mode */
7255 comp_ctx
->curr_token
.start_line
= 0; /* needed for line number tracking (becomes prev_token.start_line) */
7256 duk__advance(comp_ctx
);
7259 * Reset function state and perform register allocation, which creates
7260 * 'varmap' for second pass. Function prologue for variable declarations,
7261 * binding value initializations etc is emitted as a by-product.
7263 * Strict mode restrictions for duplicate and invalid argument
7264 * names are checked here now that we know whether the function
7265 * is actually strict. See: test-dev-strict-mode-boundary.js.
7267 * Inner functions are compiled during pass 1 and are not reset.
7270 duk__reset_func_for_pass2(comp_ctx
);
7271 func
->in_directive_prologue
= 1;
7272 func
->in_scanning
= 0;
7274 /* must be able to emit code, alloc consts, etc. */
7276 duk__init_varmap_and_prologue_for_pass2(comp_ctx
,
7277 (implicit_return_value
? ®_stmt_value
: NULL
));
7278 func
->reg_stmt_value
= reg_stmt_value
;
7280 temp_first
= DUK__GETTEMP(comp_ctx
);
7282 func
->temp_first
= temp_first
;
7283 func
->temp_next
= temp_first
;
7284 func
->stmt_next
= 0;
7285 func
->label_next
= 0;
7287 /* XXX: init or assert catch depth etc -- all values */
7288 func
->id_access_arguments
= 0;
7289 func
->id_access_slow
= 0;
7292 * Check function name validity now that we know strictness.
7293 * This only applies to function declarations and expressions,
7294 * not setter/getter name.
7296 * See: test-dev-strict-mode-boundary.js
7299 if (func
->is_function
&& !func
->is_setget
&& func
->h_name
!= NULL
) {
7300 if (func
->is_strict
) {
7301 if (duk__hstring_is_eval_or_arguments(comp_ctx
, func
->h_name
)) {
7302 DUK_DDD(DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode"));
7303 goto error_funcname
;
7305 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func
->h_name
)) {
7306 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in strict mode"));
7307 goto error_funcname
;
7310 if (DUK_HSTRING_HAS_RESERVED_WORD(func
->h_name
) &&
7311 !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func
->h_name
)) {
7312 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in non-strict mode"));
7313 goto error_funcname
;
7319 * Second pass parsing.
7322 if (implicit_return_value
) {
7323 /* Default implicit return value. */
7324 duk__emit_extraop_bc(comp_ctx
,
7325 DUK_EXTRAOP_LDUNDEF
,
7329 DUK_DDD(DUK_DDDPRINT("begin 2nd pass"));
7330 duk__parse_stmts(comp_ctx
,
7331 1, /* allow source elements */
7332 expect_eof
); /* expect EOF instead of } */
7333 DUK_DDD(DUK_DDDPRINT("end 2nd pass"));
7335 duk__update_lineinfo_currtoken(comp_ctx
);
7337 if (needs_shuffle_before
== comp_ctx
->curr_func
.needs_shuffle
) {
7338 /* Shuffle decision not changed. */
7341 if (compile_round
>= 3) {
7342 /* Should never happen but avoid infinite loop just in case. */
7343 DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen"));
7344 DUK_ERROR_INTERNAL_DEFMSG(thr
);
7346 DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round
));
7350 * Emit a final RETURN.
7352 * It would be nice to avoid emitting an unnecessary "return" opcode
7353 * if the current PC is not reachable. However, this cannot be reliably
7354 * detected; even if the previous instruction is an unconditional jump,
7355 * there may be a previous jump which jumps to current PC (which is the
7356 * case for iteration and conditional statements, for instance).
7359 /* XXX: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts();
7360 * we could avoid the last RETURN if we could ensure there is no way to get here
7361 * (directly or via a jump)
7364 DUK_ASSERT(comp_ctx
->curr_func
.catch_depth
== 0);
7365 if (reg_stmt_value
>= 0) {
7366 duk__emit_a_b(comp_ctx
,
7367 DUK_OP_RETURN
| DUK__EMIT_FLAG_NO_SHUFFLE_A
,
7368 (duk_regconst_t
) DUK_BC_RETURN_FLAG_HAVE_RETVAL
/*flags*/,
7369 (duk_regconst_t
) reg_stmt_value
/*reg*/);
7371 duk__emit_a_b(comp_ctx
,
7372 DUK_OP_RETURN
| DUK__EMIT_FLAG_NO_SHUFFLE_A
,
7373 (duk_regconst_t
) 0 /*flags*/,
7374 (duk_regconst_t
) 0 /*reg(ignored)*/);
7378 * Peephole optimize JUMP chains.
7381 duk__peephole_optimize_bytecode(comp_ctx
);
7384 * comp_ctx->curr_func is now ready to be converted into an actual
7385 * function template.
7388 DUK__RECURSION_DECREASE(comp_ctx
, thr
);
7392 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_FUNC_NAME
);
7396 * Parse a function-like expression:
7398 * - function expression
7399 * - function declaration
7400 * - function statement (non-standard)
7403 * Adds the function to comp_ctx->curr_func function table and returns the
7406 * On entry, curr_token points to:
7408 * - the token after 'function' for function expression/declaration/statement
7409 * - the token after 'set' or 'get' for setter/getter
7412 /* Parse formals. */
7413 DUK_LOCAL
void duk__parse_func_formals(duk_compiler_ctx
*comp_ctx
) {
7414 duk_hthread
*thr
= comp_ctx
->thr
;
7415 duk_context
*ctx
= (duk_context
*) thr
;
7416 duk_bool_t first
= 1;
7420 if (comp_ctx
->curr_token
.t
== DUK_TOK_RPAREN
) {
7428 duk__advance_expect(comp_ctx
, DUK_TOK_COMMA
);
7431 /* Note: when parsing a formal list in non-strict context, e.g.
7432 * "implements" is parsed as an identifier. When the function is
7433 * later detected to be strict, the argument list must be rechecked
7434 * against a larger set of reserved words (that of strict mode).
7435 * This is handled by duk__parse_func_body(). Here we recognize
7436 * whatever tokens are considered reserved in current strictness
7437 * (which is not always enough).
7440 if (comp_ctx
->curr_token
.t
!= DUK_TOK_IDENTIFIER
) {
7441 DUK_ERROR_SYNTAX(thr
, "expected identifier");
7443 DUK_ASSERT(comp_ctx
->curr_token
.t
== DUK_TOK_IDENTIFIER
);
7444 DUK_ASSERT(comp_ctx
->curr_token
.str1
!= NULL
);
7445 DUK_DDD(DUK_DDDPRINT("formal argument: %!O",
7446 (duk_heaphdr
*) comp_ctx
->curr_token
.str1
));
7448 /* XXX: append primitive */
7449 duk_push_hstring(ctx
, comp_ctx
->curr_token
.str1
);
7450 n
= (duk_uarridx_t
) duk_get_length(ctx
, comp_ctx
->curr_func
.argnames_idx
);
7451 duk_put_prop_index(ctx
, comp_ctx
->curr_func
.argnames_idx
, n
);
7453 duk__advance(comp_ctx
); /* eat identifier */
7457 /* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is
7458 * correctly set up. Assumes that curr_token is just after 'function' (or
7461 DUK_LOCAL
void duk__parse_func_like_raw(duk_compiler_ctx
*comp_ctx
, duk_bool_t is_decl
, duk_bool_t is_setget
) {
7462 duk_hthread
*thr
= comp_ctx
->thr
;
7463 duk_context
*ctx
= (duk_context
*) thr
;
7465 DUK_ASSERT(comp_ctx
->curr_func
.num_formals
== 0);
7466 DUK_ASSERT(comp_ctx
->curr_func
.is_function
== 1);
7467 DUK_ASSERT(comp_ctx
->curr_func
.is_eval
== 0);
7468 DUK_ASSERT(comp_ctx
->curr_func
.is_global
== 0);
7469 DUK_ASSERT(comp_ctx
->curr_func
.is_setget
== is_setget
);
7470 DUK_ASSERT(comp_ctx
->curr_func
.is_decl
== is_decl
);
7472 duk__update_lineinfo_currtoken(comp_ctx
);
7475 * Function name (if any)
7477 * We don't check for prohibited names here, because we don't
7478 * yet know whether the function will be strict. Function body
7479 * parsing handles this retroactively.
7481 * For function expressions and declarations function name must
7482 * be an Identifer (excludes reserved words). For setter/getter
7483 * it is a PropertyName which allows reserved words and also
7484 * strings and numbers (e.g. "{ get 1() { ... } }").
7488 /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
7489 if (comp_ctx
->curr_token
.t_nores
== DUK_TOK_IDENTIFIER
||
7490 comp_ctx
->curr_token
.t
== DUK_TOK_STRING
) {
7491 duk_push_hstring(ctx
, comp_ctx
->curr_token
.str1
); /* keep in valstack */
7492 } else if (comp_ctx
->curr_token
.t
== DUK_TOK_NUMBER
) {
7493 duk_push_number(ctx
, comp_ctx
->curr_token
.num
);
7494 duk_to_string(ctx
, -1);
7496 DUK_ERROR_SYNTAX(thr
, DUK_STR_INVALID_GETSET_NAME
);
7498 comp_ctx
->curr_func
.h_name
= duk_get_hstring(ctx
, -1); /* borrowed reference */
7499 DUK_ASSERT(comp_ctx
->curr_func
.h_name
!= NULL
);
7500 duk__advance(comp_ctx
);
7502 /* Function name is an Identifier (not IdentifierName), but we get
7503 * the raw name (not recognizing keywords) here and perform the name
7504 * checks only after pass 1.
7506 if (comp_ctx
->curr_token
.t_nores
== DUK_TOK_IDENTIFIER
) {
7507 duk_push_hstring(ctx
, comp_ctx
->curr_token
.str1
); /* keep in valstack */
7508 comp_ctx
->curr_func
.h_name
= duk_get_hstring(ctx
, -1); /* borrowed reference */
7509 DUK_ASSERT(comp_ctx
->curr_func
.h_name
!= NULL
);
7510 duk__advance(comp_ctx
);
7512 /* valstack will be unbalanced, which is OK */
7513 DUK_ASSERT(!is_setget
);
7515 DUK_ERROR_SYNTAX(thr
, DUK_STR_FUNC_NAME_REQUIRED
);
7520 DUK_DDD(DUK_DDDPRINT("function name: %!O",
7521 (duk_heaphdr
*) comp_ctx
->curr_func
.h_name
));
7524 * Formal argument list
7526 * We don't check for prohibited names or for duplicate argument
7527 * names here, becase we don't yet know whether the function will
7528 * be strict. Function body parsing handles this retroactively.
7531 duk__advance_expect(comp_ctx
, DUK_TOK_LPAREN
);
7533 duk__parse_func_formals(comp_ctx
);
7535 DUK_ASSERT(comp_ctx
->curr_token
.t
== DUK_TOK_RPAREN
);
7536 duk__advance(comp_ctx
);
7539 * Parse function body
7542 duk__parse_func_body(comp_ctx
,
7544 0, /* implicit_return_value */
7545 DUK_TOK_LCURLY
); /* expect_token */
7548 * Convert duk_compiler_func to a function template and add it
7549 * to the parent function table.
7552 duk__convert_to_func_template(comp_ctx
, is_setget
/*force_no_namebind*/); /* -> [ ... func ] */
7555 /* Parse an inner function, adding the function template to the current function's
7556 * function table. Return a function number to be used by the outer function.
7558 * Avoiding O(depth^2) inner function parsing is handled here. On the first pass,
7559 * compile and register the function normally into the 'funcs' array, also recording
7560 * a lexer point (offset/line) to the closing brace of the function. On the second
7561 * pass, skip the function and return the same 'fnum' as on the first pass by using
7562 * a running counter.
7564 * An unfortunate side effect of this is that when parsing the inner function, almost
7565 * nothing is known of the outer function, i.e. the inner function's scope. We don't
7566 * need that information at the moment, but it would allow some optimizations if it
7569 DUK_LOCAL duk_int_t
duk__parse_func_like_fnum(duk_compiler_ctx
*comp_ctx
, duk_bool_t is_decl
, duk_bool_t is_setget
) {
7570 duk_hthread
*thr
= comp_ctx
->thr
;
7571 duk_context
*ctx
= (duk_context
*) thr
;
7572 duk_compiler_func old_func
;
7573 duk_idx_t entry_top
;
7577 * On second pass, skip the function.
7580 if (!comp_ctx
->curr_func
.in_scanning
) {
7581 duk_lexer_point lex_pt
;
7583 fnum
= comp_ctx
->curr_func
.fnum_next
++;
7584 duk_get_prop_index(ctx
, comp_ctx
->curr_func
.funcs_idx
, (duk_uarridx_t
) (fnum
* 3 + 1));
7585 lex_pt
.offset
= duk_to_int(ctx
, -1);
7587 duk_get_prop_index(ctx
, comp_ctx
->curr_func
.funcs_idx
, (duk_uarridx_t
) (fnum
* 3 + 2));
7588 lex_pt
.line
= duk_to_int(ctx
, -1);
7591 DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld",
7592 (long) lex_pt
.offset
, (long) lex_pt
.line
));
7594 DUK_LEXER_SETPOINT(&comp_ctx
->lex
, &lex_pt
);
7595 comp_ctx
->curr_token
.t
= 0; /* this is needed for regexp mode */
7596 comp_ctx
->curr_token
.start_line
= 0; /* needed for line number tracking (becomes prev_token.start_line) */
7597 duk__advance(comp_ctx
);
7598 duk__advance_expect(comp_ctx
, DUK_TOK_RCURLY
);
7604 * On first pass, perform actual parsing. Remember valstack top on entry
7605 * to restore it later, and switch to using a new function in comp_ctx.
7608 entry_top
= duk_get_top(ctx
);
7609 DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld",
7610 (long) entry_top
, (long) comp_ctx
->curr_token
.start_offset
));
7612 DUK_MEMCPY(&old_func
, &comp_ctx
->curr_func
, sizeof(duk_compiler_func
));
7614 DUK_MEMZERO(&comp_ctx
->curr_func
, sizeof(duk_compiler_func
));
7615 duk__init_func_valstack_slots(comp_ctx
);
7616 DUK_ASSERT(comp_ctx
->curr_func
.num_formals
== 0);
7618 /* inherit initial strictness from parent */
7619 comp_ctx
->curr_func
.is_strict
= old_func
.is_strict
;
7621 DUK_ASSERT(comp_ctx
->curr_func
.is_notail
== 0);
7622 comp_ctx
->curr_func
.is_function
= 1;
7623 DUK_ASSERT(comp_ctx
->curr_func
.is_eval
== 0);
7624 DUK_ASSERT(comp_ctx
->curr_func
.is_global
== 0);
7625 comp_ctx
->curr_func
.is_setget
= is_setget
;
7626 comp_ctx
->curr_func
.is_decl
= is_decl
;
7629 * Parse inner function
7632 duk__parse_func_like_raw(comp_ctx
, is_decl
, is_setget
); /* pushes function template */
7634 /* prev_token.start_offset points to the closing brace here; when skipping
7635 * we're going to reparse the closing brace to ensure semicolon insertion
7636 * etc work as expected.
7638 DUK_DDD(DUK_DDDPRINT("after func: prev_tok.start_offset=%ld, curr_tok.start_offset=%ld",
7639 (long) comp_ctx
->prev_token
.start_offset
, (long) comp_ctx
->curr_token
.start_offset
));
7640 DUK_ASSERT(comp_ctx
->lex
.input
[comp_ctx
->prev_token
.start_offset
] == (duk_uint8_t
) DUK_ASC_RCURLY
);
7642 /* XXX: append primitive */
7643 DUK_ASSERT(duk_get_length(ctx
, old_func
.funcs_idx
) == (duk_size_t
) (old_func
.fnum_next
* 3));
7644 fnum
= old_func
.fnum_next
++;
7646 if (fnum
> DUK__MAX_FUNCS
) {
7647 DUK_ERROR_RANGE(comp_ctx
->thr
, DUK_STR_FUNC_LIMIT
);
7650 /* array writes autoincrement length */
7651 (void) duk_put_prop_index(ctx
, old_func
.funcs_idx
, (duk_uarridx_t
) (fnum
* 3));
7652 duk_push_size_t(ctx
, comp_ctx
->prev_token
.start_offset
);
7653 (void) duk_put_prop_index(ctx
, old_func
.funcs_idx
, (duk_uarridx_t
) (fnum
* 3 + 1));
7654 duk_push_int(ctx
, comp_ctx
->prev_token
.start_line
);
7655 (void) duk_put_prop_index(ctx
, old_func
.funcs_idx
, (duk_uarridx_t
) (fnum
* 3 + 2));
7658 * Cleanup: restore original function, restore valstack state.
7661 DUK_MEMCPY((void *) &comp_ctx
->curr_func
, (void *) &old_func
, sizeof(duk_compiler_func
));
7662 duk_set_top(ctx
, entry_top
);
7664 DUK_ASSERT_TOP(ctx
, entry_top
);
7670 * Compile input string into an executable function template without
7673 * The string is parsed as the "Program" production of Ecmascript E5.
7674 * Compilation context can be either global code or eval code (see E5
7675 * Sections 14 and 15.1.2.1).
7677 * Input stack: [ ... filename ]
7678 * Output stack: [ ... func_template ]
7681 /* XXX: source code property */
7683 DUK_LOCAL duk_ret_t
duk__js_compile_raw(duk_context
*ctx
) {
7684 duk_hthread
*thr
= (duk_hthread
*) ctx
;
7685 duk_hstring
*h_filename
;
7686 duk__compiler_stkstate
*comp_stk
;
7687 duk_compiler_ctx
*comp_ctx
;
7688 duk_lexer_point
*lex_pt
;
7689 duk_compiler_func
*func
;
7690 duk_idx_t entry_top
;
7691 duk_bool_t is_strict
;
7693 duk_bool_t is_funcexpr
;
7694 duk_small_uint_t flags
;
7696 DUK_ASSERT(thr
!= NULL
);
7702 entry_top
= duk_get_top(ctx
);
7703 DUK_ASSERT(entry_top
>= 2);
7705 comp_stk
= (duk__compiler_stkstate
*) duk_require_pointer(ctx
, -1);
7706 comp_ctx
= &comp_stk
->comp_ctx_alloc
;
7707 lex_pt
= &comp_stk
->lex_pt_alloc
;
7708 DUK_ASSERT(comp_ctx
!= NULL
);
7709 DUK_ASSERT(lex_pt
!= NULL
);
7711 flags
= comp_stk
->flags
;
7712 is_eval
= (flags
& DUK_JS_COMPILE_FLAG_EVAL
? 1 : 0);
7713 is_strict
= (flags
& DUK_JS_COMPILE_FLAG_STRICT
? 1 : 0);
7714 is_funcexpr
= (flags
& DUK_JS_COMPILE_FLAG_FUNCEXPR
? 1 : 0);
7716 h_filename
= duk_get_hstring(ctx
, -2); /* may be undefined */
7719 * Init compiler and lexer contexts
7722 func
= &comp_ctx
->curr_func
;
7723 #ifdef DUK_USE_EXPLICIT_NULL_INIT
7724 comp_ctx
->thr
= NULL
;
7725 comp_ctx
->h_filename
= NULL
;
7726 comp_ctx
->prev_token
.str1
= NULL
;
7727 comp_ctx
->prev_token
.str2
= NULL
;
7728 comp_ctx
->curr_token
.str1
= NULL
;
7729 comp_ctx
->curr_token
.str2
= NULL
;
7732 duk_require_stack(ctx
, DUK__COMPILE_ENTRY_SLOTS
);
7734 duk_push_dynamic_buffer(ctx
, 0); /* entry_top + 0 */
7735 duk_push_undefined(ctx
); /* entry_top + 1 */
7736 duk_push_undefined(ctx
); /* entry_top + 2 */
7737 duk_push_undefined(ctx
); /* entry_top + 3 */
7738 duk_push_undefined(ctx
); /* entry_top + 4 */
7740 comp_ctx
->thr
= thr
;
7741 comp_ctx
->h_filename
= h_filename
;
7742 comp_ctx
->tok11_idx
= entry_top
+ 1;
7743 comp_ctx
->tok12_idx
= entry_top
+ 2;
7744 comp_ctx
->tok21_idx
= entry_top
+ 3;
7745 comp_ctx
->tok22_idx
= entry_top
+ 4;
7746 comp_ctx
->recursion_limit
= DUK_USE_COMPILER_RECLIMIT
;
7748 /* comp_ctx->lex has been pre-initialized by caller: it has been
7749 * zeroed and input/input_length has been set.
7751 comp_ctx
->lex
.thr
= thr
;
7752 /* comp_ctx->lex.input and comp_ctx->lex.input_length filled by caller */
7753 comp_ctx
->lex
.slot1_idx
= comp_ctx
->tok11_idx
;
7754 comp_ctx
->lex
.slot2_idx
= comp_ctx
->tok12_idx
;
7755 comp_ctx
->lex
.buf_idx
= entry_top
+ 0;
7756 comp_ctx
->lex
.buf
= (duk_hbuffer_dynamic
*) duk_get_hbuffer(ctx
, entry_top
+ 0);
7757 DUK_ASSERT(comp_ctx
->lex
.buf
!= NULL
);
7758 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx
->lex
.buf
) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx
->lex
.buf
));
7759 comp_ctx
->lex
.token_limit
= DUK_COMPILER_TOKEN_LIMIT
;
7763 DUK_LEXER_SETPOINT(&comp_ctx
->lex
, lex_pt
); /* fills window */
7764 comp_ctx
->curr_token
.start_line
= 0; /* needed for line number tracking (becomes prev_token.start_line) */
7767 * Initialize function state for a zero-argument function
7770 duk__init_func_valstack_slots(comp_ctx
);
7771 DUK_ASSERT(func
->num_formals
== 0);
7774 /* Name will be filled from function expression, not by caller.
7775 * This case is used by Function constructor and duk_compile()
7776 * API with the DUK_COMPILE_FUNCTION option.
7778 DUK_ASSERT(func
->h_name
== NULL
);
7780 duk_push_hstring_stridx(ctx
, (is_eval
? DUK_STRIDX_EVAL
:
7781 DUK_STRIDX_GLOBAL
));
7782 func
->h_name
= duk_get_hstring(ctx
, -1);
7786 * Parse a function body or a function-like expression, depending
7790 func
->is_strict
= is_strict
;
7791 func
->is_setget
= 0;
7795 func
->is_function
= 1;
7797 func
->is_global
= 0;
7799 duk__advance(comp_ctx
); /* init 'curr_token' */
7800 duk__advance_expect(comp_ctx
, DUK_TOK_FUNCTION
);
7801 (void) duk__parse_func_like_raw(comp_ctx
,
7805 func
->is_function
= 0;
7806 func
->is_eval
= is_eval
;
7807 func
->is_global
= !is_eval
;
7809 duk__parse_func_body(comp_ctx
,
7811 1, /* implicit_return_value */
7812 -1); /* expect_token */
7816 * Convert duk_compiler_func to a function template
7819 duk__convert_to_func_template(comp_ctx
, 0 /*force_no_namebind*/);
7822 * Wrapping duk_safe_call() will mangle the stack, just return stack top
7825 /* [ ... filename (temps) func ] */
7830 DUK_INTERNAL
void duk_js_compile(duk_hthread
*thr
, const duk_uint8_t
*src_buffer
, duk_size_t src_length
, duk_small_uint_t flags
) {
7831 duk_context
*ctx
= (duk_context
*) thr
;
7832 duk__compiler_stkstate comp_stk
;
7833 duk_compiler_ctx
*prev_ctx
;
7836 /* XXX: this illustrates that a C catchpoint implemented using duk_safe_call()
7837 * is a bit heavy at the moment. The wrapper compiles to ~180 bytes on x64.
7838 * Alternatives would be nice.
7841 DUK_ASSERT(thr
!= NULL
);
7842 DUK_ASSERT(src_buffer
!= NULL
);
7844 /* preinitialize lexer state partially */
7845 DUK_MEMZERO(&comp_stk
, sizeof(comp_stk
));
7846 comp_stk
.flags
= flags
;
7847 DUK_LEXER_INITCTX(&comp_stk
.comp_ctx_alloc
.lex
);
7848 comp_stk
.comp_ctx_alloc
.lex
.input
= src_buffer
;
7849 comp_stk
.comp_ctx_alloc
.lex
.input_length
= src_length
;
7851 duk_push_pointer(ctx
, (void *) &comp_stk
);
7853 /* [ ... filename &comp_stk ] */
7855 prev_ctx
= thr
->compile_ctx
;
7856 thr
->compile_ctx
= &comp_stk
.comp_ctx_alloc
; /* for duk_error_augment.c */
7857 safe_rc
= duk_safe_call(ctx
, duk__js_compile_raw
, 2 /*nargs*/, 1 /*nret*/);
7858 thr
->compile_ctx
= prev_ctx
; /* must restore reliably before returning */
7860 if (safe_rc
!= DUK_EXEC_SUCCESS
) {
7864 /* [ ... template ] */