]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/third_party/duktape-1.8.0/src-separate/duk_js_compiler.c
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / prometheus-cpp / 3rdparty / civetweb / src / third_party / duktape-1.8.0 / src-separate / duk_js_compiler.c
1 /*
2 * Ecmascript compiler.
3 *
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).
7 *
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
13 * function.
14 *
15 * The top-down recursive parser functions are named "duk__parse_XXX".
16 *
17 * Recursion limits are in key functions to prevent arbitrary C recursion:
18 * function body parsing, statement parsing, and expression parsing.
19 *
20 * See doc/compiler.rst for discussion on the design.
21 *
22 * A few typing notes:
23 *
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
27 */
28
29 #include "duk_internal.h"
30
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
33
34 /* for array and object literals */
35 #define DUK__MAX_ARRAY_INIT_VALUES 20
36 #define DUK__MAX_OBJECT_INIT_PAIRS 10
37
38 /* XXX: hack, remove when const lookup is not O(n) */
39 #define DUK__GETCONST_MAX_CONSTS_CHECK 256
40
41 /* These limits are based on bytecode limits. Max temps is limited
42 * by duk_hcompiledfunction nargs/nregs fields being 16 bits.
43 */
44 #define DUK__MAX_CONSTS DUK_BC_BC_MAX
45 #define DUK__MAX_FUNCS DUK_BC_BC_MAX
46 #define DUK__MAX_TEMPS 0xffffL
47
48 /* Initial bytecode size allocation. */
49 #define DUK__BC_INITIAL_INSTS 256
50
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)); \
54 } while (0)
55
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)); \
59 } while (0)
60
61 /* Value stack slot limits: these are quite approximate right now, and
62 * because they overlap in control flow, some could be eliminated.
63 */
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
69
70 /* Temporary structure used to pass a stack allocated region through
71 * duk_safe_call().
72 */
73 typedef struct {
74 duk_small_uint_t flags;
75 duk_compiler_ctx comp_ctx_alloc;
76 duk_lexer_point lex_pt_alloc;
77 } duk__compiler_stkstate;
78
79 /*
80 * Prototypes
81 */
82
83 /* lexing */
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);
87
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);
94
95 /* code emission */
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);
99 #if 0 /* unused */
100 DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op);
101 #endif
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);
104 #if 0 /* unused */
105 DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a);
106 #endif
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);
124
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);
133 DUK_LOCAL_DECL
134 duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
135 duk_ispec *x,
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);
142 DUK_LOCAL_DECL
143 duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
144 duk_ivalue *x,
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);
148 #if 0 /* unused */
149 DUK_LOCAL_DECL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
150 #endif
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);
154
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);
158
159 /* label handling */
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);
164
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);
170
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);
174
175 /* convenience helpers */
176 #if 0 /* unused */
177 DUK_LOCAL_DECL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
178 #endif
179 #if 0 /* unused */
180 DUK_LOCAL_DECL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
181 #endif
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);
184 #if 0 /* unused */
185 DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
186 #endif
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);
190 #if 0 /* unused */
191 DUK_LOCAL_DECL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
192 #endif
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);
195 #if 0 /* unused */
196 DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
197 #endif
198
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);
204
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);
221
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);
226
227 /*
228 * Parser control values for tokens. The token table is ordered by the
229 * DUK_TOK_XXX defines.
230 *
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
236 * flags).
237 */
238
239 /* XXX: actually single step levels would work just fine, clean up */
240
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
262
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 */
267
268 #define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
269
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))
272
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 */
374 };
375
376 /*
377 * Misc helpers
378 */
379
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);
385 }
386 comp_ctx->recursion_depth++;
387 }
388
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--;
393 }
394
395 DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
396 DUK_UNREF(comp_ctx);
397 DUK_ASSERT(h != NULL);
398 return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h);
399 }
400
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));
405 }
406
407 /*
408 * Parser duk__advance() token eating functions
409 */
410
411 /* XXX: valstack handling is awkward. Add a valstack helper which
412 * avoids dup():ing; valstack_copy(src, dst)?
413 */
414
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;
418 duk_bool_t regexp;
419
420 DUK_ASSERT(comp_ctx->curr_token.t >= 0 && comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
421
422 /*
423 * Use current token to decide whether a RegExp can follow.
424 *
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.
429 */
430
431 regexp = 1;
432 if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) {
433 regexp = 0;
434 }
435 if (comp_ctx->curr_func.reject_regexp_in_adv) {
436 comp_ctx->curr_func.reject_regexp_in_adv = 0;
437 regexp = 0;
438 }
439
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);
444 }
445
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);
450
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,
455 regexp);
456
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)));
471 }
472
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);
476 }
477
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);
481 }
482
483 /*
484 * Helpers for duk_compiler_func.
485 */
486
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;
492 duk_idx_t entry_top;
493
494 entry_top = duk_get_top(ctx);
495
496 DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */
497 #ifdef DUK_USE_EXPLICIT_NULL_INIT
498 func->h_name = NULL;
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;
506 #endif
507
508 duk_require_stack(ctx, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
509
510 DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr));
511 /* code_idx = entry_top + 0 */
512
513 duk_push_array(ctx);
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);
517
518 duk_push_array(ctx);
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);
523
524 duk_push_array(ctx);
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);
528
529 duk_push_array(ctx);
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);
533
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));
539
540 duk_push_array(ctx);
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);
544
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);
549 }
550
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;
556
557 /* reset bytecode buffer but keep current size; pass 2 will
558 * require same amount or more.
559 */
560 DUK_BW_RESET_SIZE(thr, &func->bw_code);
561
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 */
564 func->fnum_next = 0;
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 */
569
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);
575 }
576
577 /* cleanup varmap from any null entries, compact it, etc; returns number
578 * of final entries after cleanup.
579 */
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;
584 duk_hstring *h_key;
585 duk_tval *tv;
586 duk_uint32_t i, e_next;
587 duk_int_t ret;
588
589 /* [ ... varmap ] */
590
591 h_varmap = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
592 DUK_ASSERT(h_varmap != NULL);
593
594 ret = 0;
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);
598 if (!h_key) {
599 continue;
600 }
601
602 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h_varmap, i));
603
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.
609 */
610
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 */
617 } else {
618 ret++;
619 }
620 }
621
622 duk_compact(ctx, -1);
623
624 return ret;
625 }
626
627 /* convert duk_compiler_func into a function template, leaving the result
628 * on top of stack.
629 */
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;
642 duk_size_t i;
643 duk_tval *p_const;
644 duk_hobject **p_func;
645 duk_instr_t *p_instr;
646 duk_compiler_instr *q_instr;
647 duk_tval *tv;
648
649 DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template"));
650
651 /*
652 * Push result object and init its flags
653 */
654
655 /* Valstack should suffice here, required on function valstack init */
656
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);
660
661 if (func->is_function) {
662 DUK_DDD(DUK_DDDPRINT("function -> set NEWENV"));
663 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
664
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.
669 */
670
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);
675 }
676 }
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);
680 } else {
681 /* non-strict eval: env is caller's env or global env (direct vs. indirect call)
682 * global code: env is is global env
683 */
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));
686 }
687
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.
692 */
693 DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING"));
694 DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res);
695 }
696
697 if (func->is_strict) {
698 DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT"));
699 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res);
700 }
701
702 if (func->is_notail) {
703 DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL"));
704 DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res);
705 }
706
707 /*
708 * Build function fixed size 'data' buffer, which contains bytecode,
709 * constants, and inner function references.
710 *
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.
714 */
715
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);
720
721 data_size = consts_count * sizeof(duk_tval) +
722 funcs_count * sizeof(duk_hobject *) +
723 code_size;
724
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));
731
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);
735
736 DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
737 DUK_HEAPHDR_INCREF(thr, h_data);
738
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);
745 p_const++;
746 DUK_TVAL_INCREF(thr, tv); /* may be a string constant */
747
748 DUK_DDD(DUK_DDDPRINT("constant: %!T", (duk_tval *) tv));
749 }
750
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++) {
754 duk_hobject *h;
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));
762 *p_func++ = h;
763 DUK_HOBJECT_INCREF(thr, h);
764
765 DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO",
766 (void *) h, (duk_heaphdr *) h));
767 }
768
769 p_instr = (duk_instr_t *) p_func;
770 DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_res, p_instr);
771
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;
776 }
777 /* Note: 'q_instr' is still used below */
778
779 DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size);
780
781 duk_pop(ctx); /* 'data' (and everything in it) is reachable through h_res now */
782
783 /*
784 * Init object properties
785 *
786 * Properties should be added in decreasing order of access frequency.
787 * (Not very critical for function templates.)
788 */
789
790 DUK_DDD(DUK_DDDPRINT("init function properties"));
791
792 /* [ ... res ] */
793
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.
798 */
799 #if defined(DUK_USE_DEBUGGER_SUPPORT)
800 if (1) {
801 #else
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) */
805 #endif
806 duk_int_t num_used;
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));
811
812 if (num_used > 0) {
813 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
814 } else {
815 DUK_DDD(DUK_DDDPRINT("varmap is empty after cleanup -> no need to add"));
816 duk_pop(ctx);
817 }
818 }
819
820 /* _Formals: omitted if function is guaranteed not to need a (non-strict) arguments object */
821 if (1) {
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.
826 */
827 duk_dup(ctx, func->argnames_idx);
828 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
829 }
830
831 /* name */
832 if (func->h_name) {
833 duk_push_hstring(ctx, func->h_name);
834 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
835 }
836
837 /* _Source */
838 #if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
839 if (0) {
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).
846 *
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.
850 *
851 * Other issues:
852 *
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
856 */
857
858 /*
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.
862 *
863 * For instance, for constructed functions (v8):
864 *
865 * > a = new Function("foo", "bar", "print(foo)");
866 * [Function]
867 * > a.toString()
868 * 'function anonymous(foo,bar) {\nprint(foo)\n}'
869 *
870 * Similarly for e.g. getters (v8):
871 *
872 * > x = { get a(foo,bar) { print(foo); } }
873 * { a: [Getter] }
874 * > Object.getOwnPropertyDescriptor(x, 'a').get.toString()
875 * 'function a(foo,bar) { print(foo); }'
876 */
877
878 #if 0
879 duk_push_string(ctx, "XXX");
880 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
881 #endif
882 }
883 #endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
884
885 /* _Pc2line */
886 #if defined(DUK_USE_PC2LINE)
887 if (1) {
888 /*
889 * Size-optimized pc->line mapping.
890 */
891
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);
895
896 /* XXX: if assertions enabled, walk through all valid PCs
897 * and check line mapping.
898 */
899 }
900 #endif /* DUK_USE_PC2LINE */
901
902 /* fileName */
903 if (comp_ctx->h_filename) {
904 /*
905 * Source filename (or equivalent), for identifying thrown errors.
906 */
907
908 duk_push_hstring(ctx, comp_ctx->h_filename);
909 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
910 }
911
912 /*
913 * Init remaining result fields
914 *
915 * 'nregs' controls how large a register frame is allocated.
916 *
917 * 'nargs' controls how many formal arguments are written to registers:
918 * r0, ... r(nargs-1). The remaining registers are initialized to
919 * undefined.
920 */
921
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;
929 #endif
930
931 DUK_DD(DUK_DDPRINT("converted function: %!ixT",
932 (duk_tval *) duk_get_tval(ctx, -1)));
933
934 /*
935 * Compact the function template.
936 */
937
938 duk_compact(ctx, -1);
939
940 /*
941 * Debug dumping
942 */
943
944 #ifdef DUK_USE_DDDPRINT
945 {
946 duk_hcompiledfunction *h;
947 duk_instr_t *p, *p_start, *p_end;
948
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);
952
953 p = p_start;
954 while (p < p_end) {
955 DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I ; 0x%08lx op=%ld (%!C) a=%ld b=%ld c=%ld",
956 (long) (p - p_start),
957 (duk_instr_t) (*p),
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)));
964 p++;
965 }
966 }
967 #endif
968 }
969
970 /*
971 * Code emission helpers
972 *
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).
977 *
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
982 *
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.
991 *
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.
996 *
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.
999 */
1000
1001 /* Code emission flags, passed in the 'opcode' field. Opcode + flags
1002 * fit into 16 bits for now, so use duk_small_uint.t.
1003 */
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 */
1012
1013 /* XXX: clarify on when and where DUK__CONST_MARKER is allowed */
1014 /* XXX: opcode specific assertions on when consts are allowed */
1015
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));
1021 }
1022
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;
1027 }
1028
1029 /* emit instruction; could return PC but that's not needed in the majority
1030 * of cases.
1031 */
1032 DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
1033 #if defined(DUK_USE_PC2LINE)
1034 duk_int_t line;
1035 #endif
1036 duk_compiler_instr *instr;
1037
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));
1044
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));
1047
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
1055 * right now.
1056 */
1057 /* approximation, close enough */
1058 line = comp_ctx->prev_token.start_line;
1059 if (line == 0) {
1060 line = comp_ctx->curr_token.start_line;
1061 }
1062 #endif
1063
1064 instr->ins = ins;
1065 #if defined(DUK_USE_PC2LINE)
1066 instr->line = line;
1067 #endif
1068 #if defined(DUK_USE_DEBUGGER_SUPPORT)
1069 if (line < comp_ctx->curr_func.min_line) {
1070 comp_ctx->curr_func.min_line = line;
1071 }
1072 if (line > comp_ctx->curr_func.max_line) {
1073 comp_ctx->curr_func.max_line = line;
1074 }
1075 #endif
1076
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)) {
1079 goto fail_bc_limit;
1080 }
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)) {
1085 goto fail_bc_limit;
1086 }
1087 #else
1088 if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
1089 goto fail_bc_limit;
1090 }
1091 #endif
1092 #endif
1093
1094 return;
1095
1096 fail_bc_limit:
1097 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
1098 }
1099
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.
1104 */
1105 DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) {
1106 #if defined(DUK_USE_DEBUGGER_SUPPORT)
1107 duk_int_t line;
1108
1109 line = comp_ctx->curr_token.start_line;
1110 if (line == 0) {
1111 return;
1112 }
1113 if (line < comp_ctx->curr_func.min_line) {
1114 comp_ctx->curr_func.min_line = line;
1115 }
1116 if (line > comp_ctx->curr_func.max_line) {
1117 comp_ctx->curr_func.max_line = line;
1118 }
1119 #else
1120 DUK_UNREF(comp_ctx);
1121 #endif
1122 }
1123
1124 #if 0 /* unused */
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));
1127 }
1128 #endif
1129
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;
1136 duk_int_t tmp;
1137
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));
1140
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
1145 * bugs.
1146 */
1147
1148 DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
1149 DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
1150
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.
1155 */
1156
1157 /* Slot A */
1158
1159 #if defined(DUK_USE_SHUFFLE_TORTURE)
1160 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
1161 #else
1162 if (a <= DUK_BC_A_MAX) {
1163 #endif
1164 ;
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));
1173 } else {
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.
1178 */
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 */
1185 } else {
1186 /* Output shuffle needed after main operation */
1187 a_out = a;
1188 }
1189 }
1190 a = tmp;
1191 } else {
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;
1194 }
1195
1196 /* Slot B */
1197
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)
1205 if (0) {
1206 #else
1207 if (b <= 0xff) {
1208 #endif
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));
1214 b = tmp;
1215 } else {
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;
1218 }
1219 } else {
1220 #if defined(DUK_USE_SHUFFLE_TORTURE)
1221 if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) {
1222 #else
1223 if (b <= 0xff) {
1224 #endif
1225 ;
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;
1231 }
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 */
1237 b_out = b;
1238 }
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.
1247 */
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 */
1255 } else {
1256 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b));
1257 }
1258 }
1259 b = tmp;
1260 } else {
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;
1263 }
1264 }
1265
1266 /* Slot C */
1267
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)
1273 if (0) {
1274 #else
1275 if (c <= 0xff) {
1276 #endif
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));
1282 c = tmp;
1283 } else {
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;
1286 }
1287 } else {
1288 #if defined(DUK_USE_SHUFFLE_TORTURE)
1289 if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) {
1290 #else
1291 if (c <= 0xff) {
1292 #endif
1293 ;
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;
1299 }
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 */
1305 c_out = c;
1306 } else {
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.
1313 */
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 */
1319 } else {
1320 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
1321 }
1322 }
1323 c = tmp;
1324 } else {
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;
1327 }
1328 }
1329
1330 /* Main operation */
1331
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);
1338
1339 ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
1340 duk__emit(comp_ctx, ins);
1341
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.
1346 */
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);
1350 }
1351
1352 /* Output shuffling: only one output register is realistically possible.
1353 *
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.)
1357 */
1358
1359 if (a_out >= 0) {
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));
1371 }
1372
1373 return;
1374
1375 error_outofregs:
1376 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
1377 }
1378
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);
1381 }
1382
1383 #if 0 /* unused */
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);
1386 }
1387 #endif
1388
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) {
1390 duk_instr_t ins;
1391 duk_int_t tmp;
1392
1393 /* allow caller to give a const number with the DUK__CONST_MARKER */
1394 bc = bc & (~DUK__CONST_MARKER);
1395
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);
1401
1402 if (bc <= DUK_BC_BC_MAX) {
1403 ;
1404 } else {
1405 /* No BC shuffling now. */
1406 goto error_outofregs;
1407 }
1408
1409 #if defined(DUK_USE_SHUFFLE_TORTURE)
1410 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
1411 #else
1412 if (a <= DUK_BC_A_MAX) {
1413 #endif
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);
1425 } else {
1426 duk__emit(comp_ctx, ins);
1427 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a));
1428 }
1429 } else {
1430 goto error_outofregs;
1431 }
1432 return;
1433
1434 error_outofregs:
1435 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
1436 }
1437
1438 DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) {
1439 duk_instr_t ins;
1440
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);
1446
1447 if (abc <= DUK_BC_ABC_MAX) {
1448 ;
1449 } else {
1450 goto error_outofregs;
1451 }
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);
1458 return;
1459
1460 error_outofregs:
1461 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
1462 }
1463
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.
1469 */
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,
1473 b,
1474 c);
1475 }
1476
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.
1482 */
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,
1486 b,
1487 0);
1488 }
1489
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.
1495 */
1496 duk__emit_a_bc(comp_ctx,
1497 DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A,
1498 extraop,
1499 bc);
1500 }
1501
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.
1507 */
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,
1512 0,
1513 0);
1514 }
1515
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.
1520 */
1521
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));
1526 } else {
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);
1534 }
1535 }
1536
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*/);
1539 }
1540
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.
1544 */
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*/);
1547 }
1548 #else
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.
1552 */
1553 DUK_ASSERT(reg <= DUK_BC_A_MAX);
1554 duk__emit_load_int32(comp_ctx, reg, val);
1555 }
1556 #endif
1557
1558 DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) {
1559 duk_int_t curr_pc;
1560 duk_int_t offset;
1561
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));
1567 }
1568
1569 DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) {
1570 duk_int_t ret;
1571
1572 ret = duk__get_current_pc(comp_ctx); /* useful for patching jumps later */
1573 duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
1574 return ret;
1575 }
1576
1577 /* Insert an empty jump in the middle of code emitted earlier. This is
1578 * currently needed for compiling for-in.
1579 */
1580 DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
1581 #if defined(DUK_USE_PC2LINE)
1582 duk_int_t line;
1583 #endif
1584 duk_compiler_instr *instr;
1585 duk_size_t offset;
1586
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,
1591 offset,
1592 sizeof(duk_compiler_instr));
1593
1594 #if defined(DUK_USE_PC2LINE)
1595 line = comp_ctx->curr_token.start_line; /* approximation, close enough */
1596 #endif
1597 instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
1598 #if defined(DUK_USE_PC2LINE)
1599 instr->line = line;
1600 #endif
1601
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)) {
1604 goto fail_bc_limit;
1605 }
1606 return;
1607
1608 fail_bc_limit:
1609 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
1610 }
1611
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).
1614 */
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;
1617 duk_int_t offset;
1618
1619 /* allow negative PCs, behave as a no-op */
1620 if (jump_pc < 0) {
1621 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld",
1622 (long) jump_pc, (long) target_pc));
1623 return;
1624 }
1625 DUK_ASSERT(jump_pc >= 0);
1626
1627 /* XXX: range assert */
1628 instr = duk__get_instr_ptr(comp_ctx, jump_pc);
1629 DUK_ASSERT(instr != NULL);
1630
1631 /* XXX: range assert */
1632 offset = target_pc - jump_pc - 1;
1633
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));
1637 }
1638
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));
1641 }
1642
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;
1645
1646 DUK_ASSERT((reg_catch & DUK__CONST_MARKER) == 0);
1647
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.
1661 */
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);
1665 }
1666 instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname);
1667 } else {
1668 /* No catch variable, e.g. a try-finally; replace LDCONST with
1669 * NOP to avoid a bogus LDCONST.
1670 */
1671 instr->ins = DUK_ENC_OP_A(DUK_OP_EXTRA, DUK_EXTRAOP_NOP);
1672 }
1673
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);
1679 }
1680
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,
1684 0 /*false*/,
1685 regconst,
1686 0 /*unused*/);
1687 }
1688
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,
1692 1 /*true*/,
1693 regconst,
1694 0 /*unused*/);
1695 }
1696
1697 DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
1698 duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_INVALID, 0);
1699 }
1700
1701 /*
1702 * Peephole optimizer for finished bytecode.
1703 *
1704 * Does not remove opcodes; currently only straightens out unconditional
1705 * jump chains which are generated by several control structures.
1706 */
1707
1708 DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
1709 duk_compiler_instr *bc;
1710 duk_small_uint_t iter;
1711 duk_int_t i, n;
1712 duk_int_t count_opt;
1713
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. */
1717 #else
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 */
1719 #endif
1720 n = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
1721
1722 for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) {
1723 count_opt = 0;
1724
1725 for (i = 0; i < n; i++) {
1726 duk_instr_t ins;
1727 duk_int_t target_pc1;
1728 duk_int_t target_pc2;
1729
1730 ins = bc[i].ins;
1731 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
1732 continue;
1733 }
1734
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);
1739
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.
1743 */
1744
1745 ins = bc[target_pc1].ins;
1746 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
1747 continue;
1748 }
1749
1750 target_pc2 = target_pc1 + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
1751
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));
1754
1755 bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS);
1756
1757 count_opt++;
1758 }
1759
1760 DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld", (long) count_opt, (long) (iter + 1)));
1761
1762 if (count_opt == 0) {
1763 break;
1764 }
1765 }
1766 }
1767
1768 /*
1769 * Intermediate value helpers
1770 */
1771
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))
1780
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).
1784 */
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 */
1788
1789 /* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(ctx,x) */
1790
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)
1794
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)));
1799 }
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)));
1809 }
1810 #else
1811 #define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
1812 #define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0)
1813 #endif
1814
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;
1817
1818 dst->t = src->t;
1819 dst->regconst = src->regconst;
1820 duk_copy(ctx, src->valstack_idx, dst->valstack_idx);
1821 }
1822
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;
1825
1826 dst->t = src->t;
1827 dst->op = src->op;
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);
1834 }
1835
1836 /* XXX: to util */
1837 DUK_LOCAL duk_bool_t duk__is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
1838 duk_small_int_t c;
1839 duk_int32_t t;
1840
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.
1845 */
1846 t = (duk_int32_t) x;
1847 if ((duk_double_t) t == x) {
1848 *ival = t;
1849 return 1;
1850 }
1851 }
1852
1853 return 0;
1854 }
1855
1856 DUK_LOCAL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
1857 duk_reg_t res;
1858
1859 res = comp_ctx->curr_func.temp_next;
1860 comp_ctx->curr_func.temp_next += num;
1861
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);
1864 }
1865
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;
1869 }
1870
1871 return res;
1872 }
1873
1874 DUK_LOCAL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
1875 return duk__alloctemps(comp_ctx, 1);
1876 }
1877
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;
1882 }
1883 }
1884
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;
1890 duk_tval *tv1;
1891 duk_int_t i, n, n_check;
1892
1893 n = (duk_int_t) duk_get_length(ctx, f->consts_idx);
1894
1895 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
1896 DUK_ASSERT(tv1 != NULL);
1897
1898 #if defined(DUK_USE_FASTINT)
1899 /* Explicit check for fastint downgrade. */
1900 DUK_TVAL_CHKFAST_INPLACE(tv1);
1901 #endif
1902
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)).
1906 */
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);
1910
1911 /* Strict equality is NOT enough, because we cannot use the same
1912 * constant for e.g. +0 and -0.
1913 */
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));
1917 duk_pop(ctx);
1918 return (duk_regconst_t) (i | DUK__CONST_MARKER);
1919 }
1920 }
1921
1922 if (n > DUK__MAX_CONSTS) {
1923 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT);
1924 }
1925
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);
1930 }
1931
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:
1934 *
1935 * (1) a constant is allowed (sometimes the caller needs the result to
1936 * be in a register)
1937 *
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)
1941 *
1942 * (3) a forced register target needs to be used
1943 *
1944 * Bytecode may be emitted to generate the necessary value. The return
1945 * value is either a register or a constant.
1946 */
1947
1948 DUK_LOCAL
1949 duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
1950 duk_ispec *x,
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;
1955
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",
1958 (long) x->t,
1959 (long) x->regconst,
1960 (duk_tval *) duk_get_tval(ctx, x->valstack_idx),
1961 (long) forced_reg,
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)));
1966
1967 switch (x->t) {
1968 case DUK_ISPEC_VALUE: {
1969 duk_tval *tv;
1970
1971 tv = DUK_GET_TVAL_POSIDX(ctx, x->valstack_idx);
1972 DUK_ASSERT(tv != NULL);
1973
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.
1979 */
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;
1983 }
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;
1988 }
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;
1995 }
1996 case DUK_TAG_POINTER: {
1997 DUK_UNREACHABLE();
1998 break;
1999 }
2000 case DUK_TAG_STRING: {
2001 duk_hstring *h;
2002 duk_reg_t dest;
2003 duk_regconst_t constidx;
2004
2005 h = DUK_TVAL_GET_STRING(tv);
2006 DUK_UNREF(h);
2007 DUK_ASSERT(h != NULL);
2008
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 */
2015 }
2016 #endif
2017 duk_dup(ctx, x->valstack_idx);
2018 constidx = duk__getconst(comp_ctx);
2019
2020 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
2021 return constidx;
2022 }
2023
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;
2027 }
2028 case DUK_TAG_OBJECT: {
2029 DUK_UNREACHABLE();
2030 break;
2031 }
2032 case DUK_TAG_BUFFER: {
2033 DUK_UNREACHABLE();
2034 break;
2035 }
2036 case DUK_TAG_LIGHTFUNC: {
2037 DUK_UNREACHABLE();
2038 break;
2039 }
2040 #if defined(DUK_USE_FASTINT)
2041 case DUK_TAG_FASTINT:
2042 #endif
2043 default: {
2044 /* number */
2045 duk_reg_t dest;
2046 duk_regconst_t constidx;
2047 duk_double_t dval;
2048 duk_int32_t ival;
2049
2050 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
2051 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
2052 dval = DUK_TVAL_GET_NUMBER(tv);
2053
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.
2059 */
2060
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;
2065 }
2066 }
2067
2068 duk_dup(ctx, x->valstack_idx);
2069 constidx = duk__getconst(comp_ctx);
2070
2071 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
2072 return constidx;
2073 } else {
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;
2077 }
2078 }
2079 } /* end switch */
2080 }
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);
2087 } else {
2088 ; /* already in correct reg */
2089 }
2090 return (duk_regconst_t) forced_reg;
2091 }
2092
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;
2099 }
2100 return x->regconst;
2101 }
2102
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;
2108 }
2109 return x->regconst;
2110 }
2111 default: {
2112 break;
2113 }
2114 }
2115
2116 DUK_ERROR_INTERNAL_DEFMSG(thr);
2117 return 0;
2118 }
2119
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*/);
2123 }
2124
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
2128 * side effect.
2129 */
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;
2133
2134 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
2135 "forced_reg=%ld",
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));
2142
2143 switch (x->t) {
2144 case DUK_IVAL_PLAIN: {
2145 return;
2146 }
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;
2152 duk_reg_t dest;
2153 duk_tval *tv1;
2154 duk_tval *tv2;
2155
2156 DUK_DDD(DUK_DDDPRINT("arith to plain conversion"));
2157
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);
2165
2166 DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T",
2167 (duk_tval *) tv1,
2168 (duk_tval *) tv2));
2169
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);
2173 duk_double_t d3;
2174 duk_bool_t accept = 1;
2175
2176 DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld",
2177 (double) d1, (double) d2, (long) x->op));
2178 switch (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;
2184 }
2185
2186 if (accept) {
2187 duk_double_union du;
2188 du.d = d3;
2189 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
2190 d3 = du.d;
2191
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 */
2195 return;
2196 }
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);
2201 duk_concat(ctx, 2);
2202 duk_replace(ctx, x->x1.valstack_idx);
2203 x->t = DUK_IVAL_PLAIN;
2204 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
2205 return;
2206 }
2207 }
2208
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*/);
2211
2212 /* If forced reg, use it as destination. Otherwise try to
2213 * use either coerced ispec if it is a temporary.
2214 *
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.
2218 */
2219 if (forced_reg >= 0) {
2220 dest = forced_reg;
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;
2225 } else {
2226 dest = DUK__ALLOCTEMP(comp_ctx);
2227 }
2228
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.
2232 *
2233 * XXX: change calling code to avoid this situation in most cases.
2234 */
2235
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. */
2240 duk_reg_t tempreg;
2241 tempreg = DUK__ALLOCTEMP(comp_ctx);
2242 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, tempreg, arg2);
2243 arg2 = tempreg;
2244 }
2245
2246 if (DUK__ISREG(comp_ctx, arg1)) {
2247 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, arg1);
2248 } else {
2249 DUK_ASSERT(DUK__ISCONST(comp_ctx, arg1));
2250 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, arg1);
2251 }
2252 }
2253
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.
2258 */
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);
2265
2266 } else {
2267 DUK_ASSERT(DUK__ISREG(comp_ctx, dest));
2268 duk__emit_a_b_c(comp_ctx, x->op, (duk_regconst_t) dest, arg1, arg2);
2269 }
2270
2271 x->t = DUK_IVAL_PLAIN;
2272 x->x1.t = DUK_ISPEC_REGCONST;
2273 x->x1.regconst = (duk_regconst_t) dest;
2274 return;
2275 }
2276 case DUK_IVAL_PROP: {
2277 /* XXX: very similar to DUK_IVAL_ARITH - merge? */
2278 duk_regconst_t arg1;
2279 duk_regconst_t arg2;
2280 duk_reg_t dest;
2281
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*/);
2285
2286 /* Pick a destination register. If either base value or key
2287 * happens to be a temp value, reuse it as the destination.
2288 *
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.
2293 */
2294
2295 if (forced_reg >= 0) {
2296 dest = forced_reg;
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;
2301 } else {
2302 dest = DUK__ALLOCTEMP(comp_ctx);
2303 }
2304
2305 duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, (duk_regconst_t) dest, arg1, arg2);
2306
2307 x->t = DUK_IVAL_PLAIN;
2308 x->x1.t = DUK_ISPEC_REGCONST;
2309 x->x1.regconst = (duk_regconst_t) dest;
2310 return;
2311 }
2312 case DUK_IVAL_VAR: {
2313 /* x1 must be a string */
2314 duk_reg_t dest;
2315 duk_reg_t reg_varbind;
2316 duk_regconst_t rc_varname;
2317
2318 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
2319
2320 duk_dup(ctx, x->x1.valstack_idx);
2321 if (duk__lookup_lhs(comp_ctx, &reg_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;
2325 } else {
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;
2331 }
2332 return;
2333 }
2334 case DUK_IVAL_NONE:
2335 default: {
2336 DUK_D(DUK_DPRINT("invalid ivalue type: %ld", (long) x->t));
2337 break;
2338 }
2339 }
2340
2341 DUK_ERROR_INTERNAL_DEFMSG(thr);
2342 return;
2343 }
2344
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*/);
2348 }
2349
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) {
2352 duk_reg_t temp;
2353
2354 /* If duk__ivalue_toplain_raw() allocates a temp, forget it and
2355 * restore next temp state.
2356 */
2357 temp = DUK__GETTEMP(comp_ctx);
2358 duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
2359 DUK__SETTEMP(comp_ctx, temp);
2360 }
2361
2362 /* Coerce an duk_ivalue to a register or constant; result register may
2363 * be a temp or a bound register.
2364 *
2365 * The duk_ivalue argument ('x') is converted into a regconst as a
2366 * side effect.
2367 */
2368 DUK_LOCAL
2369 duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
2370 duk_ivalue *x,
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;
2375 duk_regconst_t reg;
2376 DUK_UNREF(thr);
2377 DUK_UNREF(ctx);
2378
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),
2386 (long) forced_reg,
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)));
2391
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);
2395
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;
2400
2401 return reg;
2402 }
2403
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*/);
2406 }
2407
2408 #if 0 /* unused */
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*/);
2411 }
2412 #endif
2413
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*/);
2417 }
2418
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*/);
2421 }
2422
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*/);
2425 }
2426
2427 /* The issues below can be solved with better flags */
2428
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.
2433 */
2434
2435 /*
2436 * Identifier handling
2437 */
2438
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;
2443 duk_reg_t ret;
2444
2445 DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
2446 (duk_tval *) duk_get_tval(ctx, -1)));
2447
2448 /*
2449 * Special name handling
2450 */
2451
2452 h_varname = duk_get_hstring(ctx, -1);
2453 DUK_ASSERT(h_varname != NULL);
2454
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;
2458 }
2459
2460 /*
2461 * Inside one or more 'with' statements fall back to slow path always.
2462 * (See e.g. test-stmt-with.js.)
2463 */
2464
2465 if (comp_ctx->curr_func.with_depth > 0) {
2466 DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path"));
2467 goto slow_path;
2468 }
2469
2470 /*
2471 * Any catch bindings ("catch (e)") also affect identifier binding.
2472 *
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.
2476 */
2477
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);
2481 duk_pop(ctx);
2482 } else {
2483 duk_pop(ctx);
2484 goto slow_path;
2485 }
2486
2487 DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret));
2488 return ret;
2489
2490 slow_path:
2491 DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path"));
2492
2493 comp_ctx->curr_func.id_access_slow = 1;
2494 return (duk_reg_t) -1;
2495 }
2496
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.
2504 */
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;
2510
2511 /* [ ... varname ] */
2512
2513 duk_dup_top(ctx);
2514 reg_varbind = duk__lookup_active_register_binding(comp_ctx);
2515
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) */
2519 duk_pop(ctx);
2520 return 1;
2521 } else {
2522 rc_varname = duk__getconst(comp_ctx);
2523 *out_reg_varbind = -1;
2524 *out_rc_varname = rc_varname;
2525 return 0;
2526 }
2527 }
2528
2529 /*
2530 * Label handling
2531 *
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.
2535 */
2536
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;
2540 duk_size_t n;
2541 duk_size_t new_size;
2542 duk_uint8_t *p;
2543 duk_labelinfo *li_start, *li;
2544
2545 /* Duplicate (shadowing) labels are not allowed, except for the empty
2546 * labels (which are used as default labels for switch and iteration
2547 * statements).
2548 *
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.
2552 */
2553
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);
2558
2559 while (li > li_start) {
2560 li--;
2561
2562 if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
2563 DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL);
2564 }
2565 }
2566
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);
2570
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 */
2574
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));
2580 li--;
2581
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
2586 * statement type.
2587 */
2588
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;
2594
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));
2598 }
2599
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) {
2602 duk_uint8_t *p;
2603 duk_labelinfo *li_start, *li;
2604
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));
2608
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).
2612 */
2613 while (li > li_start) {
2614 li--;
2615
2616 if (li->label_id != label_id) {
2617 break;
2618 }
2619
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));
2622
2623 li->flags = flags;
2624 }
2625 }
2626
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'.
2629 *
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.
2635 *
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.
2639 */
2640
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;
2645 duk_uint8_t *p;
2646 duk_labelinfo *li_start, *li_end, *li;
2647 duk_bool_t match = 0;
2648
2649 DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
2650 (duk_heaphdr *) h_label, (long) is_break));
2651
2652 DUK_UNREF(ctx);
2653
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));
2657 li = li_end;
2658
2659 /* Match labels starting from latest label because there can be duplicate empty
2660 * labels in the label set.
2661 */
2662 while (li > li_start) {
2663 li--;
2664
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));
2670 continue;
2671 }
2672
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));
2675
2676 /* currently all labels accept a break, so no explicit check for it now */
2677 DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK);
2678
2679 if (is_break) {
2680 /* break matches always */
2681 match = 1;
2682 break;
2683 } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) {
2684 /* iteration statements allow continue */
2685 match = 1;
2686 break;
2687 } else {
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.
2691 */
2692 if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
2693 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
2694 } else {
2695 DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not "
2696 "allow a continue -> continue lookup deeper in label stack"));
2697 }
2698 }
2699 }
2700 /* XXX: match flag is awkward, rework */
2701 if (!match) {
2702 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
2703 }
2704
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));
2708
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);
2713 }
2714
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;
2719
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);
2725 }
2726
2727 /*
2728 * Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers.
2729 *
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
2733 */
2734
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 */
2739
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 */
2751
2752 /* DUK_TOK_LBRACKET already eaten, current token is right after that */
2753 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
2754
2755 max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */
2756
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,
2760 reg_obj,
2761 0); /* XXX: patch initial size afterwards? */
2762 temp_start = DUK__GETTEMP(comp_ctx);
2763
2764 /*
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.
2768 *
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
2773 * inserted.
2774 */
2775
2776 curr_idx = 0;
2777 init_idx = 0; /* tracks maximum initialized index + 1 */
2778 start_idx = 0;
2779 require_comma = 0;
2780
2781 for (;;) {
2782 num_values = 0;
2783 DUK__SETTEMP(comp_ctx, temp_start);
2784
2785 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
2786 break;
2787 }
2788
2789 for (;;) {
2790 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
2791 /* the outer loop will recheck and exit */
2792 break;
2793 }
2794
2795 /* comma check */
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);
2800 require_comma = 0;
2801 continue;
2802 } else {
2803 goto syntax_error;
2804 }
2805 } else {
2806 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
2807 /* elision - flush */
2808 curr_idx++;
2809 duk__advance(comp_ctx);
2810 /* if num_values > 0, MPUTARR emitted by outer loop after break */
2811 break;
2812 }
2813 }
2814 /* else an array initializer element */
2815
2816 /* initial index */
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);
2821 }
2822
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);
2827
2828 num_values++;
2829 curr_idx++;
2830 require_comma = 1;
2831
2832 if (num_values >= max_init_values) {
2833 /* MPUTARR emitted by outer loop */
2834 break;
2835 }
2836 }
2837
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.
2846 */
2847 duk__emit_a_b_c(comp_ctx,
2848 DUK_OP_MPUTARR |
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;
2855
2856 /* num_values and temp_start reset at top of outer loop */
2857 }
2858 }
2859
2860 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
2861 duk__advance(comp_ctx);
2862
2863 DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld",
2864 (long) curr_idx, (long) init_idx));
2865
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);
2876 }
2877
2878 DUK__SETTEMP(comp_ctx, temp_start);
2879
2880 res->t = DUK_IVAL_PLAIN;
2881 res->x1.t = DUK_ISPEC_REGCONST;
2882 res->x1.regconst = (duk_regconst_t) reg_obj;
2883 return;
2884
2885 syntax_error:
2886 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL);
2887 }
2888
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;
2894
2895 /* [ ... key_obj key ] */
2896
2897 DUK_ASSERT(duk_is_string(ctx, -1));
2898
2899 /*
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:
2903 *
2904 * PropertyNameAndValueList: PropertyNameAndValueList , PropertyAssignment
2905 */
2906
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 ] */
2911
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) {
2914 /* step 4.a */
2915 DUK_DDD(DUK_DDDPRINT("duplicate key: plain key appears twice in strict mode"));
2916 return 1;
2917 }
2918 if (key_flags & (DUK__OBJ_LIT_KEY_GET | DUK__OBJ_LIT_KEY_SET)) {
2919 /* step 4.c */
2920 DUK_DDD(DUK_DDDPRINT("duplicate key: plain key encountered after setter/getter"));
2921 return 1;
2922 }
2923 } else {
2924 if (key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
2925 /* step 4.b */
2926 DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered after plain key"));
2927 return 1;
2928 }
2929 if (key_flags & new_key_flags) {
2930 /* step 4.d */
2931 DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered twice"));
2932 return 1;
2933 }
2934 }
2935
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));
2941 duk_dup(ctx, -1);
2942 duk_push_int(ctx, new_key_flags); /* [ ... key_obj key key flags ] */
2943 duk_put_prop(ctx, -4); /* [ ... key_obj key ] */
2944
2945 return 0;
2946 }
2947
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 */
2959
2960 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
2961
2962 max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */
2963
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,
2967 reg_obj,
2968 0); /* XXX: patch initial size afterwards? */
2969 temp_start = DUK__GETTEMP(comp_ctx);
2970
2971 /* temp object for tracking / detecting duplicate keys */
2972 duk_push_object(ctx);
2973
2974 /*
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.
2979 */
2980
2981 first = 1;
2982 for (;;) {
2983 num_pairs = 0;
2984 DUK__SETTEMP(comp_ctx, temp_start);
2985
2986 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
2987 break;
2988 }
2989
2990 for (;;) {
2991 /*
2992 * Three possible element formats:
2993 * 1) PropertyName : AssignmentExpression
2994 * 2) get PropertyName () { FunctionBody }
2995 * 3) set PropertyName ( PropertySetParameterList ) { FunctionBody }
2996 *
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:
3000 *
3001 * { get : 1 }
3002 *
3003 * and
3004 *
3005 * { get foo() { return 1 } }
3006 * { get get() { return 1 } } // 'get' as getter propertyname
3007 *
3008 * Finally, a trailing comma is allowed.
3009 *
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.
3014 */
3015
3016 DUK_DDD(DUK_DDDPRINT("object literal inner loop, curr_token->t = %ld",
3017 (long) comp_ctx->curr_token.t));
3018
3019 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
3020 /* the outer loop will recheck and exit */
3021 break;
3022 }
3023 if (num_pairs >= max_init_pairs) {
3024 /* MPUTOBJ emitted by outer loop */
3025 break;
3026 }
3027
3028 if (first) {
3029 first = 0;
3030 } else {
3031 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
3032 goto syntax_error;
3033 }
3034 duk__advance(comp_ctx);
3035 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
3036 /* trailing comma followed by rcurly */
3037 break;
3038 }
3039 }
3040
3041 /* advance to get one step of lookup */
3042 duk__advance(comp_ctx);
3043
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.
3048 */
3049
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) {
3055 /* getter/setter */
3056 duk_int_t fnum;
3057
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);
3066 } else {
3067 goto syntax_error;
3068 }
3069
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))) {
3073 goto syntax_error;
3074 }
3075 reg_key = duk__getconst(comp_ctx);
3076
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.
3085 */
3086 duk__emit_a_b_c(comp_ctx,
3087 DUK_OP_MPUTOBJ |
3088 DUK__EMIT_FLAG_NO_SHUFFLE_C |
3089 DUK__EMIT_FLAG_A_IS_SOURCE,
3090 reg_obj,
3091 temp_start,
3092 num_pairs);
3093 num_pairs = 0;
3094 DUK__SETTEMP(comp_ctx, temp_start);
3095 }
3096
3097 /* curr_token = get/set name */
3098 fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 1 /*is_setget*/);
3099
3100 DUK_ASSERT(DUK__GETTEMP(comp_ctx) == temp_start);
3101 reg_temp = DUK__ALLOCTEMP(comp_ctx);
3102 duk__emit_a_bc(comp_ctx,
3103 DUK_OP_LDCONST,
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,
3108 DUK_OP_CLOSURE,
3109 (duk_regconst_t) reg_temp,
3110 (duk_regconst_t) fnum);
3111
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).
3115 */
3116 duk__emit_extraop_b_c(comp_ctx,
3117 (is_get ? DUK_EXTRAOP_INITGET : DUK_EXTRAOP_INITSET),
3118 reg_obj,
3119 temp_start); /* temp_start+0 = key, temp_start+1 = closure */
3120
3121 DUK__SETTEMP(comp_ctx, temp_start);
3122 } else {
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);
3132 } else {
3133 goto syntax_error;
3134 }
3135
3136 DUK_ASSERT(duk_is_string(ctx, -1));
3137 if (duk__nud_object_literal_key_check(comp_ctx, DUK__OBJ_LIT_KEY_PLAIN)) {
3138 goto syntax_error;
3139 }
3140 reg_key = duk__getconst(comp_ctx);
3141
3142 reg_temp = DUK__ALLOCTEMP(comp_ctx);
3143 duk__emit_a_bc(comp_ctx,
3144 DUK_OP_LDCONST,
3145 (duk_regconst_t) reg_temp,
3146 (duk_regconst_t) reg_key);
3147 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
3148
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);
3153
3154 num_pairs++;
3155 }
3156 }
3157
3158 if (num_pairs > 0) {
3159 /* See MPUTOBJ comments above. */
3160 duk__emit_a_b_c(comp_ctx,
3161 DUK_OP_MPUTOBJ |
3162 DUK__EMIT_FLAG_NO_SHUFFLE_C |
3163 DUK__EMIT_FLAG_A_IS_SOURCE,
3164 reg_obj,
3165 temp_start,
3166 num_pairs);
3167
3168 /* num_pairs and temp_start reset at top of outer loop */
3169 }
3170 }
3171
3172 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
3173 duk__advance(comp_ctx);
3174
3175 DUK__SETTEMP(comp_ctx, temp_start);
3176
3177 res->t = DUK_IVAL_PLAIN;
3178 res->x1.t = DUK_ISPEC_REGCONST;
3179 res->x1.regconst = (duk_regconst_t) reg_obj;
3180
3181 DUK_DDD(DUK_DDDPRINT("final tracking object: %!T",
3182 (duk_tval *) duk_get_tval(ctx, -1)));
3183 duk_pop(ctx);
3184 return;
3185
3186 syntax_error:
3187 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL);
3188 }
3189
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.
3193 */
3194 DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
3195 duk_int_t nargs = 0;
3196 duk_reg_t reg_temp;
3197
3198 /* Note: expect that caller has already eaten the left paren */
3199
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));
3202
3203 for (;;) {
3204 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
3205 break;
3206 }
3207 if (nargs > 0) {
3208 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
3209 }
3210
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.
3214 *
3215 * This is not the cleanest possible approach.
3216 */
3217
3218 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* bump up "allocated" reg count, just in case */
3219 DUK__SETTEMP(comp_ctx, reg_temp);
3220
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 */
3223
3224 DUK__SETTEMP(comp_ctx, reg_temp + 1);
3225 nargs++;
3226
3227 DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld", (long) nargs, (long) reg_temp));
3228 }
3229
3230 /* eat the right paren */
3231 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
3232
3233 DUK_DDD(DUK_DDDPRINT("end parsing arguments"));
3234
3235 return nargs;
3236 }
3237
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);
3242 }
3243
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;
3247 duk_token *tk;
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 */
3251
3252 /*
3253 * ctx->prev_token token to process with duk__expr_nud()
3254 * ctx->curr_token updated by caller
3255 *
3256 * Note: the token in the switch below has already been eaten.
3257 */
3258
3259 temp_at_entry = DUK__GETTEMP(comp_ctx);
3260
3261 comp_ctx->curr_func.nud_count++;
3262
3263 tk = &comp_ctx->prev_token;
3264 tok = tk->t;
3265 res->t = DUK_IVAL_NONE;
3266
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));
3269
3270 switch (tok) {
3271
3272 /* PRIMARY EXPRESSIONS */
3273
3274 case DUK_TOK_THIS: {
3275 duk_reg_t reg_temp;
3276 reg_temp = DUK__ALLOCTEMP(comp_ctx);
3277 duk__emit_extraop_bc(comp_ctx,
3278 DUK_EXTRAOP_LDTHIS,
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;
3283 return;
3284 }
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);
3290 return;
3291 }
3292 case DUK_TOK_NULL: {
3293 duk_push_null(ctx);
3294 goto plain_value;
3295 }
3296 case DUK_TOK_TRUE: {
3297 duk_push_true(ctx);
3298 goto plain_value;
3299 }
3300 case DUK_TOK_FALSE: {
3301 duk_push_false(ctx);
3302 goto plain_value;
3303 }
3304 case DUK_TOK_NUMBER: {
3305 duk_push_number(ctx, tk->num);
3306 goto plain_value;
3307 }
3308 case DUK_TOK_STRING: {
3309 DUK_ASSERT(tk->str1 != NULL);
3310 duk_push_hstring(ctx, tk->str1);
3311 goto plain_value;
3312 }
3313 case DUK_TOK_REGEXP: {
3314 #ifdef DUK_USE_REGEXP_SUPPORT
3315 duk_reg_t reg_temp;
3316 duk_regconst_t rc_re_bytecode; /* const */
3317 duk_regconst_t rc_re_source; /* const */
3318
3319 DUK_ASSERT(tk->str1 != NULL);
3320 DUK_ASSERT(tk->str2 != NULL);
3321
3322 DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O",
3323 (duk_heaphdr *) tk->str1,
3324 (duk_heaphdr *) tk->str2));
3325
3326 reg_temp = DUK__ALLOCTEMP(comp_ctx);
3327 duk_push_hstring(ctx, tk->str1);
3328 duk_push_hstring(ctx, tk->str2);
3329
3330 /* [ ... pattern flags ] */
3331
3332 duk_regexp_compile(thr);
3333
3334 /* [ ... escaped_source bytecode ] */
3335
3336 rc_re_bytecode = duk__getconst(comp_ctx);
3337 rc_re_source = duk__getconst(comp_ctx);
3338
3339 duk__emit_a_b_c(comp_ctx,
3340 DUK_OP_REGEXP,
3341 (duk_regconst_t) reg_temp /*a*/,
3342 rc_re_bytecode /*b*/,
3343 rc_re_source /*c*/);
3344
3345 res->t = DUK_IVAL_PLAIN;
3346 res->x1.t = DUK_ISPEC_REGCONST;
3347 res->x1.regconst = (duk_regconst_t) reg_temp;
3348 return;
3349 #else /* DUK_USE_REGEXP_SUPPORT */
3350 goto syntax_error;
3351 #endif /* DUK_USE_REGEXP_SUPPORT */
3352 }
3353 case DUK_TOK_LBRACKET: {
3354 DUK_DDD(DUK_DDDPRINT("parsing array literal"));
3355 duk__nud_array_literal(comp_ctx, res);
3356 return;
3357 }
3358 case DUK_TOK_LCURLY: {
3359 DUK_DDD(DUK_DDDPRINT("parsing object literal"));
3360 duk__nud_object_literal(comp_ctx, res);
3361 return;
3362 }
3363 case DUK_TOK_LPAREN: {
3364 duk_bool_t prev_allow_in;
3365
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 */
3369
3370 duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, terminates at a ')' */
3371
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--;
3375 return;
3376 }
3377
3378 /* MEMBER/NEW/CALL EXPRESSIONS */
3379
3380 case DUK_TOK_NEW: {
3381 /*
3382 * Parsing an expression starting with 'new' is tricky because
3383 * there are multiple possible productions deriving from
3384 * LeftHandSideExpression which begin with 'new'.
3385 *
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).
3390 *
3391 * See doc/compiler.rst for discussion on the parsing approach,
3392 * and testcases/test-dev-new.js for a bunch of documented tests.
3393 */
3394
3395 duk_reg_t reg_target;
3396 duk_int_t nargs;
3397
3398 DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
3399
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);
3403
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 */
3410 } else {
3411 /* 'new' MemberExpression */
3412 DUK_DDD(DUK_DDDPRINT("new expression has no argument list"));
3413 nargs = 0;
3414 }
3415
3416 /* Opcode slot C is used in a non-standard way, so shuffling
3417 * is not allowed.
3418 */
3419 duk__emit_a_b_c(comp_ctx,
3420 DUK_OP_NEW | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
3421 0 /*unused*/,
3422 reg_target /*target*/,
3423 nargs /*num_args*/);
3424
3425 DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
3426
3427 res->t = DUK_IVAL_PLAIN;
3428 res->x1.t = DUK_ISPEC_REGCONST;
3429 res->x1.regconst = (duk_regconst_t) reg_target;
3430 return;
3431 }
3432
3433 /* FUNCTION EXPRESSIONS */
3434
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.
3440 *
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().
3445 */
3446
3447 duk_reg_t reg_temp;
3448 duk_int_t fnum;
3449
3450 reg_temp = DUK__ALLOCTEMP(comp_ctx);
3451
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));
3455
3456 duk__emit_a_bc(comp_ctx,
3457 DUK_OP_CLOSURE,
3458 (duk_regconst_t) reg_temp /*a*/,
3459 (duk_regconst_t) fnum /*bc*/);
3460
3461 res->t = DUK_IVAL_PLAIN;
3462 res->x1.t = DUK_ISPEC_REGCONST;
3463 res->x1.regconst = (duk_regconst_t) reg_temp;
3464 return;
3465 }
3466
3467 /* UNARY EXPRESSIONS */
3468
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).
3474 */
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).
3480 */
3481
3482 duk_reg_t reg_temp;
3483 duk_reg_t reg_varbind;
3484 duk_regconst_t rc_varname;
3485
3486 if (comp_ctx->curr_func.is_strict) {
3487 DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER);
3488 }
3489
3490 DUK__SETTEMP(comp_ctx, temp_at_entry);
3491 reg_temp = DUK__ALLOCTEMP(comp_ctx);
3492
3493 duk_dup(ctx, res->x1.valstack_idx);
3494 if (duk__lookup_lhs(comp_ctx, &reg_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);
3499 } else {
3500 duk_dup(ctx, res->x1.valstack_idx);
3501 rc_varname = duk__getconst(comp_ctx);
3502 duk__emit_a_b(comp_ctx,
3503 DUK_OP_DELVAR,
3504 (duk_regconst_t) reg_temp,
3505 (duk_regconst_t) rc_varname);
3506 }
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) {
3511 duk_reg_t reg_temp;
3512 duk_reg_t reg_obj;
3513 duk_regconst_t rc_key;
3514
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,
3520 DUK_OP_DELPROP,
3521 (duk_regconst_t) reg_temp,
3522 (duk_regconst_t) reg_obj,
3523 rc_key);
3524
3525 res->t = DUK_IVAL_PLAIN;
3526 res->x1.t = DUK_ISPEC_REGCONST;
3527 res->x1.regconst = (duk_regconst_t) reg_temp;
3528 } else {
3529 /* non-Reference deletion is always 'true', even in strict mode */
3530 duk_push_true(ctx);
3531 goto plain_value;
3532 }
3533 return;
3534 }
3535 case DUK_TOK_VOID: {
3536 duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
3537 duk_push_undefined(ctx);
3538 goto plain_value;
3539 }
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.
3545 */
3546 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
3547
3548 if (res->t == DUK_IVAL_VAR) {
3549 duk_reg_t reg_varbind;
3550 duk_regconst_t rc_varname;
3551 duk_reg_t reg_temp;
3552
3553 duk_dup(ctx, res->x1.valstack_idx);
3554 if (!duk__lookup_lhs(comp_ctx, &reg_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,
3560 reg_temp,
3561 rc_varname);
3562 res->t = DUK_IVAL_PLAIN;
3563 res->x1.t = DUK_ISPEC_REGCONST;
3564 res->x1.regconst = (duk_regconst_t) reg_temp;
3565 return;
3566 }
3567 }
3568
3569 args = (DUK_EXTRAOP_TYPEOF << 8) + 0;
3570 goto unary_extraop;
3571 }
3572 case DUK_TOK_INCREMENT: {
3573 args = (DUK_OP_PREINCR << 8) + 0;
3574 goto preincdec;
3575 }
3576 case DUK_TOK_DECREMENT: {
3577 args = (DUK_OP_PREDECR << 8) + 0;
3578 goto preincdec;
3579 }
3580 case DUK_TOK_ADD: {
3581 /* unary plus */
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 */
3586 ;
3587 return;
3588 }
3589 args = (DUK_EXTRAOP_UNP << 8) + 0;
3590 goto unary_extraop;
3591 }
3592 case DUK_TOK_SUB: {
3593 /* unary minus */
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)
3599 */
3600 duk_tval *tv_num;
3601 duk_double_union du;
3602
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);
3607 du.d = -du.d;
3608 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
3609 DUK_TVAL_SET_NUMBER(tv_num, du.d);
3610 return;
3611 }
3612 args = (DUK_EXTRAOP_UNM << 8) + 0;
3613 goto unary_extraop;
3614 }
3615 case DUK_TOK_BNOT: {
3616 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
3617 args = (DUK_EXTRAOP_BNOT << 8) + 0;
3618 goto unary_extraop;
3619 }
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'.
3625 */
3626 duk_tval *tv_val;
3627
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)) {
3631 duk_double_t d;
3632 d = DUK_TVAL_GET_NUMBER(tv_val);
3633 if (d == 0.0) {
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);
3637 return;
3638 } else if (d == 1.0) {
3639 DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false"));
3640 DUK_TVAL_SET_BOOLEAN_FALSE(tv_val);
3641 return;
3642 }
3643 } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) {
3644 duk_small_int_t v;
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);
3649 return;
3650 }
3651 }
3652 args = (DUK_EXTRAOP_LNOT << 8) + 0;
3653 goto unary_extraop;
3654 }
3655
3656 } /* end switch */
3657
3658 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
3659 return;
3660
3661 unary_extraop:
3662 {
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).
3665 */
3666
3667 duk_reg_t reg_temp;
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,
3670 (args >> 8),
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;
3675 return;
3676 }
3677
3678 preincdec:
3679 {
3680 /* preincrement and predecrement */
3681 duk_reg_t reg_res;
3682 duk_small_uint_t args_op = args >> 8;
3683
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);
3689
3690 reg_res = DUK__ALLOCTEMP(comp_ctx);
3691
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;
3697
3698 h_varname = duk_get_hstring(ctx, res->x1.valstack_idx);
3699 DUK_ASSERT(h_varname != NULL);
3700
3701 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
3702 goto syntax_error;
3703 }
3704
3705 duk_dup(ctx, res->x1.valstack_idx);
3706 if (duk__lookup_lhs(comp_ctx, &reg_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);
3711 } else {
3712 duk__emit_a_bc(comp_ctx,
3713 args_op + 4, /* e.g. DUK_OP_PREINCV */
3714 (duk_regconst_t) reg_res,
3715 rc_varname);
3716 }
3717
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,
3729 rc_key);
3730 } else {
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().
3735 */
3736
3737 duk__ivalue_toforcedreg(comp_ctx, res, reg_res);
3738 duk__emit_extraop_bc(comp_ctx,
3739 DUK_EXTRAOP_UNP,
3740 reg_res); /* for side effects, result ignored */
3741 duk__emit_extraop_only(comp_ctx,
3742 DUK_EXTRAOP_INVLHS);
3743 }
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);
3748 return;
3749 }
3750
3751 plain_value:
3752 {
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);
3757 return;
3758 }
3759
3760 syntax_error:
3761 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
3762 }
3763
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.
3767 */
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;
3771 duk_token *tk;
3772 duk_small_int_t tok;
3773 duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
3774
3775 /*
3776 * ctx->prev_token token to process with duk__expr_led()
3777 * ctx->curr_token updated by caller
3778 */
3779
3780 comp_ctx->curr_func.led_count++;
3781
3782 /* The token in the switch has already been eaten here */
3783 tk = &comp_ctx->prev_token;
3784 tok = tk->t;
3785
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));
3788
3789 /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */
3790
3791 switch (tok) {
3792
3793 /* PRIMARY EXPRESSIONS */
3794
3795 case DUK_TOK_PERIOD: {
3796 /* Property access expressions are critical for correct LHS ordering,
3797 * see comments in duk__expr()!
3798 *
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
3805 * RHS mutation.
3806 */
3807
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
3810 * unary ivalue?
3811 */
3812 duk__ivalue_toplain(comp_ctx, left);
3813
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);
3817 }
3818
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;
3825
3826 /* special RegExp literal handling after IdentifierName */
3827 comp_ctx->curr_func.reject_regexp_in_adv = 1;
3828
3829 duk__advance(comp_ctx);
3830 return;
3831 }
3832 case DUK_TOK_LBRACKET: {
3833 /* Property access expressions are critical for correct LHS ordering,
3834 * see comments in duk__expr()!
3835 */
3836
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
3841 * there?
3842 */
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).
3846 */
3847
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.
3853 */
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);
3857
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 */
3861 return;
3862 }
3863 case DUK_TOK_LPAREN: {
3864 /* function call */
3865 duk_reg_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
3866 duk_int_t nargs;
3867 duk_small_uint_t call_flags = 0;
3868
3869 /*
3870 * XXX: attempt to get the call result to "next temp" whenever
3871 * possible to avoid unnecessary register shuffles.
3872 *
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".
3875 */
3876
3877 /*
3878 * Setup call: target and 'this' binding. Three cases:
3879 *
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)
3883 */
3884
3885 if (left->t == DUK_IVAL_VAR) {
3886 duk_hstring *h_varname;
3887 duk_reg_t reg_varbind;
3888 duk_regconst_t rc_varname;
3889
3890 DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
3891
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.
3899 */
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;
3904
3905 comp_ctx->curr_func.may_direct_eval = 1;
3906 }
3907
3908 duk_dup(ctx, left->x1.valstack_idx);
3909 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
3910 duk__emit_a_b(comp_ctx,
3911 DUK_OP_CSREG,
3912 (duk_regconst_t) (reg_cs + 0),
3913 (duk_regconst_t) reg_varbind);
3914 } else {
3915 duk__emit_a_b(comp_ctx,
3916 DUK_OP_CSVAR,
3917 (duk_regconst_t) (reg_cs + 0),
3918 rc_varname);
3919 }
3920 } else if (left->t == DUK_IVAL_PROP) {
3921 DUK_DDD(DUK_DDDPRINT("function call with property base"));
3922
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,
3926 DUK_OP_CSPROP,
3927 (duk_regconst_t) (reg_cs + 0),
3928 (duk_regconst_t) (reg_cs + 0),
3929 (duk_regconst_t) (reg_cs + 1)); /* in-place setup */
3930 } else {
3931 DUK_DDD(DUK_DDDPRINT("function call with register base"));
3932
3933 duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
3934 duk__emit_a_b(comp_ctx,
3935 DUK_OP_CSREG,
3936 (duk_regconst_t) (reg_cs + 0),
3937 (duk_regconst_t) (reg_cs + 0)); /* in-place setup */
3938 }
3939
3940 DUK__SETTEMP(comp_ctx, reg_cs + 2);
3941 nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */
3942
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".
3946 */
3947
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 */
3954
3955 res->t = DUK_IVAL_PLAIN;
3956 res->x1.t = DUK_ISPEC_REGCONST;
3957 res->x1.regconst = (duk_regconst_t) reg_cs;
3958 return;
3959 }
3960
3961 /* POSTFIX EXPRESSION */
3962
3963 case DUK_TOK_INCREMENT: {
3964 args = (DUK_OP_POSTINCR << 8) + 0;
3965 goto postincdec;
3966 }
3967 case DUK_TOK_DECREMENT: {
3968 args = (DUK_OP_POSTDECR << 8) + 0;
3969 goto postincdec;
3970 }
3971
3972 /* MULTIPLICATIVE EXPRESSION */
3973
3974 case DUK_TOK_MUL: {
3975 args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
3976 goto binary;
3977 }
3978 case DUK_TOK_DIV: {
3979 args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
3980 goto binary;
3981 }
3982 case DUK_TOK_MOD: {
3983 args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
3984 goto binary;
3985 }
3986
3987 /* ADDITIVE EXPRESSION */
3988
3989 case DUK_TOK_ADD: {
3990 args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
3991 goto binary;
3992 }
3993 case DUK_TOK_SUB: {
3994 args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
3995 goto binary;
3996 }
3997
3998 /* SHIFT EXPRESSION */
3999
4000 case DUK_TOK_ALSHIFT: {
4001 /* << */
4002 args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT;
4003 goto binary;
4004 }
4005 case DUK_TOK_ARSHIFT: {
4006 /* >> */
4007 args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT;
4008 goto binary;
4009 }
4010 case DUK_TOK_RSHIFT: {
4011 /* >>> */
4012 args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT;
4013 goto binary;
4014 }
4015
4016 /* RELATIONAL EXPRESSION */
4017
4018 case DUK_TOK_LT: {
4019 /* < */
4020 args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL;
4021 goto binary;
4022 }
4023 case DUK_TOK_GT: {
4024 args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL;
4025 goto binary;
4026 }
4027 case DUK_TOK_LE: {
4028 args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL;
4029 goto binary;
4030 }
4031 case DUK_TOK_GE: {
4032 args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL;
4033 goto binary;
4034 }
4035 case DUK_TOK_INSTANCEOF: {
4036 args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_INSTOF << 8) + DUK__BP_RELATIONAL;
4037 goto binary;
4038 }
4039 case DUK_TOK_IN: {
4040 args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_IN << 8) + DUK__BP_RELATIONAL;
4041 goto binary;
4042 }
4043
4044 /* EQUALITY EXPRESSION */
4045
4046 case DUK_TOK_EQ: {
4047 args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY;
4048 goto binary;
4049 }
4050 case DUK_TOK_NEQ: {
4051 args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY;
4052 goto binary;
4053 }
4054 case DUK_TOK_SEQ: {
4055 args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY;
4056 goto binary;
4057 }
4058 case DUK_TOK_SNEQ: {
4059 args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY;
4060 goto binary;
4061 }
4062
4063 /* BITWISE EXPRESSIONS */
4064
4065 case DUK_TOK_BAND: {
4066 args = (DUK_OP_BAND << 8) + DUK__BP_BAND;
4067 goto binary;
4068 }
4069 case DUK_TOK_BXOR: {
4070 args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR;
4071 goto binary;
4072 }
4073 case DUK_TOK_BOR: {
4074 args = (DUK_OP_BOR << 8) + DUK__BP_BOR;
4075 goto binary;
4076 }
4077
4078 /* LOGICAL EXPRESSIONS */
4079
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;
4084 }
4085 case DUK_TOK_LOR: {
4086 /* syntactically left-associative but parsed as right-associative */
4087 args = (0 << 8) + DUK__BP_LOR - 1;
4088 goto binary_logical;
4089 }
4090
4091 /* CONDITIONAL EXPRESSION */
4092
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.
4096 */
4097 duk_reg_t reg_temp;
4098 duk_int_t pc_jump1;
4099 duk_int_t pc_jump2;
4100
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);
4111
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;
4116 return;
4117 }
4118
4119 /* ASSIGNMENT EXPRESSION */
4120
4121 case DUK_TOK_EQUALSIGN: {
4122 /*
4123 * Assignments are right associative, allows e.g.
4124 * a = 5;
4125 * a += b = 9; // same as a += (b = 9)
4126 * -> expression value 14, a = 14, b = 9
4127 *
4128 * Right associativiness is reflected in the BP for recursion,
4129 * "-1" ensures assignment operations are allowed.
4130 *
4131 * XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)?
4132 */
4133 args = (DUK_OP_NONE << 8) + DUK__BP_ASSIGNMENT - 1; /* DUK_OP_NONE marks a 'plain' assignment */
4134 goto assign;
4135 }
4136 case DUK_TOK_ADD_EQ: {
4137 /* right associative */
4138 args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1;
4139 goto assign;
4140 }
4141 case DUK_TOK_SUB_EQ: {
4142 /* right associative */
4143 args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1;
4144 goto assign;
4145 }
4146 case DUK_TOK_MUL_EQ: {
4147 /* right associative */
4148 args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1;
4149 goto assign;
4150 }
4151 case DUK_TOK_DIV_EQ: {
4152 /* right associative */
4153 args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1;
4154 goto assign;
4155 }
4156 case DUK_TOK_MOD_EQ: {
4157 /* right associative */
4158 args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1;
4159 goto assign;
4160 }
4161 case DUK_TOK_ALSHIFT_EQ: {
4162 /* right associative */
4163 args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1;
4164 goto assign;
4165 }
4166 case DUK_TOK_ARSHIFT_EQ: {
4167 /* right associative */
4168 args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1;
4169 goto assign;
4170 }
4171 case DUK_TOK_RSHIFT_EQ: {
4172 /* right associative */
4173 args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1;
4174 goto assign;
4175 }
4176 case DUK_TOK_BAND_EQ: {
4177 /* right associative */
4178 args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1;
4179 goto assign;
4180 }
4181 case DUK_TOK_BOR_EQ: {
4182 /* right associative */
4183 args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1;
4184 goto assign;
4185 }
4186 case DUK_TOK_BXOR_EQ: {
4187 /* right associative */
4188 args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1;
4189 goto assign;
4190 }
4191
4192 /* COMMA */
4193
4194 case DUK_TOK_COMMA: {
4195 /* right associative */
4196
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*/);
4199
4200 /* return 'res' (of right part) as our result */
4201 return;
4202 }
4203
4204 default: {
4205 break;
4206 }
4207 }
4208
4209 DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok));
4210 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
4211 return;
4212
4213 #if 0
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;
4217 }
4218 #endif
4219
4220 binary:
4221 /*
4222 * Shared handling of binary operations
4223 *
4224 * args = (is_extraop << 16) + (opcode << 8) + rbp
4225 */
4226 {
4227 duk__ivalue_toplain(comp_ctx, left);
4228 duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/);
4229
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);
4233
4234 res->t = (args >> 16) ? DUK_IVAL_ARITH_EXTRAOP : DUK_IVAL_ARITH;
4235 res->op = (args >> 8) & 0xff;
4236
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);
4240
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);
4244
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));
4247 return;
4248 }
4249
4250 binary_logical:
4251 /*
4252 * Shared handling for logical AND and logical OR.
4253 *
4254 * args = (truthval << 8) + rbp
4255 *
4256 * Truthval determines when to skip right-hand-side.
4257 * For logical AND truthval=1, for logical OR truthval=0.
4258 *
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.
4263 *
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.
4268 */
4269
4270 {
4271 duk_reg_t reg_temp;
4272 duk_int_t pc_jump;
4273 duk_small_uint_t args_truthval = args >> 8;
4274 duk_small_uint_t args_rbp = args & 0xff;
4275
4276 /* XXX: unoptimal use of temps, resetting */
4277
4278 reg_temp = DUK__ALLOCTEMP(comp_ctx);
4279
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);
4288
4289 res->t = DUK_IVAL_PLAIN;
4290 res->x1.t = DUK_ISPEC_REGCONST;
4291 res->x1.regconst = (duk_regconst_t) reg_temp;
4292 return;
4293 }
4294
4295 assign:
4296 /*
4297 * Shared assignment expression handling
4298 *
4299 * args = (opcode << 8) + rbp
4300 *
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.
4305 *
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.
4312 *
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
4323 * ignored.
4324 * See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js.
4325 */
4326
4327 {
4328 duk_small_uint_t args_op = args >> 8;
4329 duk_small_uint_t args_rbp = args & 0xff;
4330 duk_bool_t toplevel_assign;
4331
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
4335 * some other means.
4336 */
4337
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.
4346 */
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));
4353
4354 if (left->t == DUK_IVAL_VAR) {
4355 duk_hstring *h_varname;
4356 duk_reg_t reg_varbind;
4357 duk_regconst_t rc_varname;
4358
4359 DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
4360
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;
4366 }
4367 duk_dup(ctx, left->x1.valstack_idx);
4368 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
4369
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"));
4375 } else {
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);
4382 }
4383 }
4384 } else {
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
4388 * the pre-op value.
4389 */
4390 duk_reg_t reg_temp;
4391
4392 reg_temp = DUK__ALLOCTEMP(comp_ctx);
4393
4394 if (reg_varbind >= 0) {
4395 duk_reg_t reg_res;
4396 duk_reg_t reg_src;
4397 duk_int_t pc_temp_load;
4398 duk_int_t pc_before_rhs;
4399 duk_int_t pc_after_rhs;
4400
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;".
4405 */
4406 DUK_DD(DUK_DDPRINT("<op>= expression is top level, write directly to reg_varbind"));
4407 reg_res = reg_varbind;
4408 } else {
4409 /* Not safe to use 'reg_varbind' as assignment expression
4410 * value, so go through a temp.
4411 */
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);
4415 }
4416
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.
4422 */
4423
4424 pc_temp_load = duk__get_current_pc(comp_ctx);
4425 duk__emit_a_bc(comp_ctx,
4426 DUK_OP_LDREG,
4427 (duk_regconst_t) reg_temp,
4428 reg_varbind);
4429
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);
4434
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));
4438
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.
4443 */
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;
4447 } else {
4448 DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
4449 reg_src = reg_temp;
4450 }
4451
4452 duk__emit_a_b_c(comp_ctx,
4453 args_op,
4454 (duk_regconst_t) reg_res,
4455 (duk_regconst_t) reg_src,
4456 res->x1.regconst);
4457
4458 res->x1.regconst = (duk_regconst_t) reg_res;
4459
4460 /* Ensure compact use of temps. */
4461 if (DUK__ISTEMP(comp_ctx, reg_res)) {
4462 DUK__SETTEMP(comp_ctx, reg_res + 1);
4463 }
4464 } else {
4465 /* When LHS is not register bound, always go through a
4466 * temporary. No optimization for top level assignment.
4467 */
4468
4469 duk__emit_a_bc(comp_ctx,
4470 DUK_OP_GETVAR,
4471 (duk_regconst_t) reg_temp,
4472 rc_varname);
4473
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);
4476
4477 duk__emit_a_b_c(comp_ctx,
4478 args_op,
4479 (duk_regconst_t) reg_temp,
4480 (duk_regconst_t) reg_temp,
4481 res->x1.regconst);
4482 res->x1.regconst = (duk_regconst_t) reg_temp;
4483 }
4484
4485 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
4486 }
4487
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.
4493 */
4494
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.
4500 */
4501 if (toplevel_assign) {
4502 duk__ivalue_toforcedreg(comp_ctx, res, (duk_int_t) reg_varbind);
4503 } else {
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);
4507 }
4508 } else {
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.
4512 */
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);
4515 }
4516 } else {
4517 /* Only a reg fits into 'A' so coerce 'res' into a register
4518 * for PUTVAR.
4519 *
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.
4523 */
4524
4525 duk__ivalue_toreg(comp_ctx, res);
4526 duk__emit_a_bc(comp_ctx,
4527 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
4528 res->x1.regconst,
4529 rc_varname);
4530 }
4531
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 */
4535 duk_reg_t reg_obj;
4536 duk_regconst_t rc_key;
4537 duk_regconst_t rc_res;
4538 duk_reg_t reg_temp;
4539
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.
4546 *
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.
4549 */
4550
4551 reg_obj = duk__ispec_toregconst_raw(comp_ctx,
4552 &left->x1,
4553 -1 /*forced_reg*/,
4554 DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
4555
4556 rc_key = duk__ispec_toregconst_raw(comp_ctx,
4557 &left->x2,
4558 -1 /*forced_reg*/,
4559 DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
4560
4561 /* Evaluate RHS only when LHS is safe. */
4562
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;
4567 } else {
4568 reg_temp = DUK__ALLOCTEMP(comp_ctx);
4569 duk__emit_a_b_c(comp_ctx,
4570 DUK_OP_GETPROP,
4571 (duk_regconst_t) reg_temp,
4572 (duk_regconst_t) reg_obj,
4573 rc_key);
4574
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);
4577
4578 duk__emit_a_b_c(comp_ctx,
4579 args_op,
4580 (duk_regconst_t) reg_temp,
4581 (duk_regconst_t) reg_temp,
4582 res->x1.regconst);
4583 rc_res = (duk_regconst_t) reg_temp;
4584 }
4585
4586 duk__emit_a_b_c(comp_ctx,
4587 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
4588 (duk_regconst_t) reg_obj,
4589 rc_key,
4590 rc_res);
4591
4592 res->t = DUK_IVAL_PLAIN;
4593 res->x1.t = DUK_ISPEC_REGCONST;
4594 res->x1.regconst = rc_res;
4595 } else {
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:
4600 *
4601 * f() = g();
4602 *
4603 * must result in f() being evaluated, then g() being evaluated, and
4604 * finally, a ReferenceError being thrown. See E5 Section 11.13.1.
4605 */
4606
4607 duk_regconst_t rc_res;
4608
4609 /* First evaluate LHS fully to ensure all side effects are out. */
4610 duk__ivalue_toplain_ignore(comp_ctx, left);
4611
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.
4615 */
4616 rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
4617
4618 duk__emit_extraop_only(comp_ctx,
4619 DUK_EXTRAOP_INVLHS);
4620
4621 res->t = DUK_IVAL_PLAIN;
4622 res->x1.t = DUK_ISPEC_REGCONST;
4623 res->x1.regconst = rc_res;
4624 }
4625
4626 return;
4627 }
4628
4629 postincdec:
4630 {
4631 /*
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.
4636 *
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 '++'/'--'.
4640 */
4641
4642 duk_reg_t reg_res;
4643 duk_small_uint_t args_op = args >> 8;
4644
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);
4650
4651 reg_res = DUK__ALLOCTEMP(comp_ctx);
4652
4653 if (left->t == DUK_IVAL_VAR) {
4654 duk_hstring *h_varname;
4655 duk_reg_t reg_varbind;
4656 duk_regconst_t rc_varname;
4657
4658 h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
4659 DUK_ASSERT(h_varname != NULL);
4660
4661 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
4662 goto syntax_error;
4663 }
4664
4665 duk_dup(ctx, left->x1.valstack_idx);
4666 if (duk__lookup_lhs(comp_ctx, &reg_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);
4671 } else {
4672 duk__emit_a_bc(comp_ctx,
4673 args_op + 4, /* e.g. DUK_OP_POSTINCV */
4674 (duk_regconst_t) reg_res,
4675 rc_varname);
4676 }
4677
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;
4683
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,
4690 rc_key);
4691 } else {
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().
4696 */
4697 duk__ivalue_toforcedreg(comp_ctx, left, reg_res);
4698 duk__emit_extraop_bc(comp_ctx,
4699 DUK_EXTRAOP_UNP,
4700 reg_res); /* for side effects, result ignored */
4701 duk__emit_extraop_only(comp_ctx,
4702 DUK_EXTRAOP_INVLHS);
4703 }
4704
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);
4709 return;
4710 }
4711
4712 syntax_error:
4713 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
4714 return;
4715
4716 syntax_error_lvalue:
4717 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE);
4718 return;
4719 }
4720
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;
4723
4724 DUK_ASSERT(tok >= DUK_TOK_MINVAL && tok <= DUK_TOK_MAXVAL);
4725 DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
4726
4727 /* XXX: integrate support for this into led() instead?
4728 * Similar issue as post-increment/post-decrement.
4729 */
4730
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) {
4733 return 0;
4734 }
4735
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).
4743 */
4744 return 0;
4745 }
4746
4747 return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]); /* format is bit packed */
4748 }
4749
4750 /*
4751 * Expression parsing.
4752 *
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
4756 * statement).
4757 */
4758
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 */
4763
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;
4771
4772 DUK__RECURSION_INCREASE(comp_ctx, thr);
4773
4774 duk_require_stack(ctx, DUK__PARSE_EXPR_SLOTS);
4775
4776 /* filter out flags from exprtop rbp_flags here to save space */
4777 rbp = rbp_flags & DUK__EXPR_RBP_MASK;
4778
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));
4782
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);
4788
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.
4792 */
4793
4794 /* XXX: increase ctx->expr_tokens here for every consumed token
4795 * (this would be a nice statistic)?
4796 */
4797
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);
4803 }
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);
4808 goto cleanup;
4809 }
4810
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 */
4817 }
4818
4819 cleanup:
4820 /* final result is already in 'res' */
4821
4822 duk_pop_2(ctx);
4823
4824 DUK__RECURSION_DECREASE(comp_ctx, thr);
4825 }
4826
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;
4829
4830 /* Note: these variables must reside in 'curr_func' instead of the global
4831 * context: when parsing function expressions, expression parsing is nested.
4832 */
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);
4838
4839 duk__expr(comp_ctx, res, rbp_flags);
4840
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);
4843 }
4844 }
4845
4846 /* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop()
4847 * and result conversions.
4848 *
4849 * Each helper needs at least 2-3 calls to make it worth while to wrap.
4850 */
4851
4852 #if 0 /* unused */
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);
4856 }
4857 #endif
4858
4859 #if 0 /* unused */
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);
4863 }
4864 #endif
4865
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);
4870 }
4871
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);
4875 }
4876
4877 #if 0 /* unused */
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);
4881 }
4882 #endif
4883
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);
4887 }
4888
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);
4892 }
4893
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);
4897 }
4898
4899 #if 0 /* unused */
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);
4903 }
4904 #endif
4905
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);
4910 }
4911
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);
4915 }
4916
4917 #if 0 /* unused */
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);
4921 }
4922 #endif
4923
4924 /*
4925 * Parse an individual source element (top level statement) or a statement.
4926 *
4927 * Handles labeled statements automatically (peeling away labels before
4928 * parsing an expression that follows the label(s)).
4929 *
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).
4934 */
4935
4936 #ifdef DUK__HAS_VAL
4937 #undef DUK__HAS_VAL
4938 #endif
4939 #ifdef DUK__HAS_TERM
4940 #undef DUK__HAS_TERM
4941 #endif
4942 #ifdef DUK__ALLOW_AUTO_SEMI_ALWAYS
4943 #undef DUK__ALLOW_AUTO_SEMI_ALWAYS
4944 #endif
4945 #ifdef DUK__STILL_PROLOGUE
4946 #undef DUK__STILL_PROLOGUE
4947 #endif
4948 #ifdef DUK__IS_TERMINAL
4949 #undef DUK__IS_TERMINAL
4950 #endif
4951
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) */
4957
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
4960 * as a temporary.
4961 *
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'.
4965 *
4966 * Finally, out_rc_varname and out_reg_varbind are updated to reflect where
4967 * the identifier is bound:
4968 *
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
4971 *
4972 * These allow the caller to use the variable for further assignment, e.g.
4973 * as is done in 'for-in' parsing.
4974 */
4975
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;
4982
4983 /* assume 'var' has been eaten */
4984
4985 /* Note: Identifier rejects reserved words */
4986 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
4987 goto syntax_error;
4988 }
4989 h_varname = comp_ctx->curr_token.str1;
4990
4991 DUK_ASSERT(h_varname != NULL);
4992
4993 /* strict mode restrictions (E5 Section 12.2.1) */
4994 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
4995 goto syntax_error;
4996 }
4997
4998 /* register declarations in first pass */
4999 if (comp_ctx->curr_func.in_scanning) {
5000 duk_uarridx_t n;
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);
5008 }
5009
5010 duk_push_hstring(ctx, h_varname); /* push before advancing to keep reachable */
5011
5012 /* register binding lookup is based on varmap (even in first pass) */
5013 duk_dup_top(ctx);
5014 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
5015
5016 duk__advance(comp_ctx); /* eat identifier */
5017
5018 if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) {
5019 duk__advance(comp_ctx);
5020
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));
5023
5024 duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/); /* AssignmentExpression */
5025
5026 if (reg_varbind >= 0) {
5027 duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
5028 } else {
5029 duk_reg_t reg_val;
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,
5034 rc_varname);
5035 }
5036 } else {
5037 if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) {
5038 /* Used for minimal 'const': initializer required. */
5039 goto syntax_error;
5040 }
5041 }
5042
5043 duk_pop(ctx); /* pop varname */
5044
5045 *out_rc_varname = rc_varname;
5046 *out_reg_varbind = reg_varbind;
5047
5048 return;
5049
5050 syntax_error:
5051 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION);
5052 }
5053
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;
5057
5058 duk__advance(comp_ctx); /* eat 'var' */
5059
5060 for (;;) {
5061 /* rc_varname and reg_varbind are ignored here */
5062 duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, &reg_varbind, &rc_varname);
5063
5064 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
5065 break;
5066 }
5067 duk__advance(comp_ctx);
5068 }
5069 }
5070
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 */
5077
5078 DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
5079
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.
5084 */
5085
5086 reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2);
5087
5088 temp_reset = DUK__GETTEMP(comp_ctx);
5089
5090 /*
5091 * For/for-in main variants are:
5092 *
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
5097 *
5098 * Parsing these without arbitrary lookahead or backtracking is relatively
5099 * tricky but we manage to do so for now.
5100 *
5101 * See doc/compiler.rst for a detailed discussion of control flow
5102 * issues, evaluation order issues, etc.
5103 */
5104
5105 duk__advance(comp_ctx); /* eat 'for' */
5106 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
5107
5108 DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld", (long) duk__get_current_pc(comp_ctx)));
5109
5110 /* a label site has been emitted by duk__parse_stmt() automatically
5111 * (it will also emit the ENDLABEL).
5112 */
5113
5114 if (comp_ctx->curr_token.t == DUK_TOK_VAR) {
5115 /*
5116 * Variant 2 or 4
5117 */
5118
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 */
5121
5122 duk__advance(comp_ctx); /* eat 'var' */
5123 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
5124 DUK__SETTEMP(comp_ctx, temp_reset);
5125
5126 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
5127 /*
5128 * Variant 4
5129 */
5130
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,
5135 DUK_OP_LDREG,
5136 (duk_regconst_t) reg_varbind,
5137 (duk_regconst_t) (reg_temps + 0));
5138 } else {
5139 duk__emit_a_bc(comp_ctx,
5140 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
5141 (duk_regconst_t) (reg_temps + 0),
5142 rc_varname);
5143 }
5144 goto parse_3_or_4;
5145 } else {
5146 /*
5147 * Variant 2
5148 */
5149
5150 DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement"));
5151 for (;;) {
5152 /* more initializers */
5153 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
5154 break;
5155 }
5156 DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer"));
5157
5158 duk__advance(comp_ctx); /* eat comma */
5159 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
5160 }
5161 goto parse_1_or_2;
5162 }
5163 } else {
5164 /*
5165 * Variant 1 or 3
5166 */
5167
5168 pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here (variant 3) */
5169
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".
5172 */
5173
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) {
5177 /*
5178 * Variant 3
5179 */
5180
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 */
5185 }
5186
5187 if (res->t == DUK_IVAL_VAR) {
5188 duk_reg_t reg_varbind;
5189 duk_regconst_t rc_varname;
5190
5191 duk_dup(ctx, res->x1.valstack_idx);
5192 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
5193 duk__emit_a_bc(comp_ctx,
5194 DUK_OP_LDREG,
5195 (duk_regconst_t) reg_varbind,
5196 (duk_regconst_t) (reg_temps + 0));
5197 } else {
5198 duk__emit_a_bc(comp_ctx,
5199 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
5200 (duk_regconst_t) (reg_temps + 0),
5201 rc_varname);
5202 }
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.
5206 */
5207 duk_reg_t reg_obj;
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,
5214 rc_key,
5215 (duk_regconst_t) (reg_temps + 0));
5216 } else {
5217 duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */
5218 duk__emit_extraop_only(comp_ctx,
5219 DUK_EXTRAOP_INVLHS);
5220 }
5221 goto parse_3_or_4;
5222 } else {
5223 /*
5224 * Variant 1
5225 */
5226
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);
5229 goto parse_1_or_2;
5230 }
5231 }
5232
5233 parse_1_or_2:
5234 /*
5235 * Parse variant 1 or 2. The first part expression (which differs
5236 * in the variants) has already been parsed and its code emitted.
5237 *
5238 * reg_temps + 0: unused
5239 * reg_temps + 1: unused
5240 */
5241 {
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;
5246
5247 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2"));
5248
5249 /* "release" preallocated temps since we won't need them */
5250 temp_reset = reg_temps + 0;
5251 DUK__SETTEMP(comp_ctx, temp_reset);
5252
5253 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
5254
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 */
5261 } else {
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 */
5266 }
5267 DUK__SETTEMP(comp_ctx, temp_reset);
5268
5269 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
5270
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 */
5275 expr_c_empty = 1;
5276 /* JUMP L1 omitted */
5277 } else {
5278 duk__ivalue_toplain_ignore(comp_ctx, res);
5279 expr_c_empty = 0;
5280 duk__emit_jump(comp_ctx, pc_l1);
5281 }
5282 DUK__SETTEMP(comp_ctx, temp_reset);
5283
5284 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
5285
5286 pc_l3 = duk__get_current_pc(comp_ctx);
5287 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
5288 if (expr_c_empty) {
5289 duk__emit_jump(comp_ctx, pc_l1);
5290 } else {
5291 duk__emit_jump(comp_ctx, pc_l2);
5292 }
5293 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
5294
5295 pc_l4 = duk__get_current_pc(comp_ctx);
5296
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));
5301
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,
5305 pc_label_site + 1,
5306 pc_l4); /* break jump */
5307 duk__patch_jump(comp_ctx,
5308 pc_label_site + 2,
5309 expr_c_empty ? pc_l1 : pc_l2); /* continue jump */
5310 }
5311 goto finished;
5312
5313 parse_3_or_4:
5314 /*
5315 * Parse variant 3 or 4.
5316 *
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.
5321 *
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.
5325 *
5326 * Variables set before entering here:
5327 *
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
5331 */
5332 {
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;
5336
5337 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs));
5338
5339 DUK__SETTEMP(comp_ctx, temp_reset);
5340
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.
5346 */
5347
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 */
5351
5352 /* The code for writing reg_temps + 0 to the left hand side has already
5353 * been emitted.
5354 */
5355
5356 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* -> loop body */
5357
5358 duk__advance(comp_ctx); /* eat 'in' */
5359
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).
5364 */
5365
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);
5374
5375 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
5376
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 */
5380
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).
5386 */
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 */
5394
5395 pc_l5 = duk__get_current_pc(comp_ctx);
5396
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.
5400 */
5401
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));
5408
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 */
5415 }
5416 goto finished;
5417
5418 finished:
5419 DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement"));
5420 return;
5421
5422 syntax_error:
5423 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR);
5424 }
5425
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) */
5435
5436 /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */
5437
5438 /*
5439 * Switch is pretty complicated because of several conflicting concerns:
5440 *
5441 * - Want to generate code without an intermediate representation,
5442 * i.e., in one go
5443 *
5444 * - Case selectors are expressions, not values, and may thus e.g. throw
5445 * exceptions (which causes evaluation order concerns)
5446 *
5447 * - Evaluation semantics of case selectors and default clause need to be
5448 * carefully implemented to provide correct behavior even with case value
5449 * side effects
5450 *
5451 * - Fall through case and default clauses; avoiding dead JUMPs if case
5452 * ends with an unconditional jump (a break or a continue)
5453 *
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
5457 *
5458 * See E5 Section 12.11. Also see doc/compiler.rst for compilation
5459 * discussion.
5460 */
5461
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);
5467
5468 DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch));
5469
5470 temp_at_loop = DUK__GETTEMP(comp_ctx);
5471
5472 for (;;) {
5473 duk_int_t num_stmts;
5474 duk_small_int_t tok;
5475
5476 /* sufficient for keeping temp reg numbers in check */
5477 DUK__SETTEMP(comp_ctx, temp_at_loop);
5478
5479 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
5480 break;
5481 }
5482
5483 /*
5484 * Parse a case or default clause.
5485 */
5486
5487 if (comp_ctx->curr_token.t == DUK_TOK_CASE) {
5488 /*
5489 * Case clause.
5490 *
5491 * Note: cannot use reg_case as a temp register (for SEQ target)
5492 * because it may be a constant.
5493 */
5494
5495 duk__patch_jump_here(comp_ctx, pc_prevcase); /* chain jumps for case
5496 * evaluation and checking
5497 */
5498
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);
5502
5503 reg_temp = DUK__ALLOCTEMP(comp_ctx);
5504 duk__emit_a_b_c(comp_ctx,
5505 DUK_OP_SEQ,
5506 (duk_regconst_t) reg_temp,
5507 rc_switch,
5508 rc_case);
5509 duk__emit_if_true_skip(comp_ctx, (duk_regconst_t) reg_temp);
5510
5511 /* jump to next case clause */
5512 pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */
5513
5514 /* statements go here (if any) on next loop */
5515 } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) {
5516 /*
5517 * Default clause.
5518 */
5519
5520 if (pc_default >= 0) {
5521 goto syntax_error;
5522 }
5523 duk__advance(comp_ctx);
5524 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
5525
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.
5529 */
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);
5533 }
5534
5535 /* default clause matches next statement list (if any) */
5536 pc_default = -2;
5537 } else {
5538 /* Code is not accepted before the first case/default clause */
5539 goto syntax_error;
5540 }
5541
5542 /*
5543 * Parse code after the clause. Possible terminators are
5544 * 'case', 'default', and '}'.
5545 *
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.
5550 */
5551
5552 num_stmts = 0;
5553 if (pc_default == -2) {
5554 pc_default = duk__get_current_pc(comp_ctx);
5555 }
5556
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.
5560 */
5561 duk__patch_jump_here(comp_ctx, pc_prevstmt); /* chain jumps for 'fall-through'
5562 * after a case matches.
5563 */
5564
5565 for (;;) {
5566 tok = comp_ctx->curr_token.t;
5567 if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT ||
5568 tok == DUK_TOK_RCURLY) {
5569 break;
5570 }
5571 num_stmts++;
5572 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
5573 }
5574
5575 /* fall-through jump to next code of next case (backpatched) */
5576 pc_prevstmt = duk__emit_jump_empty(comp_ctx);
5577
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'.
5581 *
5582 * Perhaps duk__parse_stmt() could provide some info on whether
5583 * the statement is a "dead end"?
5584 *
5585 * If implemented, just set pc_prevstmt to -1 when not needed.
5586 */
5587 }
5588
5589 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
5590 duk__advance(comp_ctx);
5591
5592 /* default case control flow patchup; note that if pc_prevcase < 0
5593 * (i.e. no case clauses), control enters default case automatically.
5594 */
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);
5598 } else {
5599 /* default case does not exist, or no statements present
5600 * after default case: finish case evaluation
5601 */
5602 duk__patch_jump_here(comp_ctx, pc_prevcase);
5603 }
5604
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.
5607 */
5608 duk__patch_jump_here(comp_ctx, pc_prevstmt);
5609
5610 /* continue jump not patched, an INVALID opcode remains there */
5611 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
5612
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.
5617 */
5618
5619 return;
5620
5621 syntax_error:
5622 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH);
5623 }
5624
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;
5629
5630 DUK_DDD(DUK_DDDPRINT("begin parsing if statement"));
5631
5632 temp_reset = DUK__GETTEMP(comp_ctx);
5633
5634 duk__advance(comp_ctx); /* eat 'if' */
5635 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
5636
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);
5641
5642 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
5643
5644 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
5645
5646 /* The 'else' ambiguity is resolved by 'else' binding to the innermost
5647 * construct, so greedy matching is correct here.
5648 */
5649
5650 if (comp_ctx->curr_token.t == DUK_TOK_ELSE) {
5651 duk_int_t pc_jump_end;
5652
5653 DUK_DDD(DUK_DDDPRINT("if has else part"));
5654
5655 duk__advance(comp_ctx);
5656
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);
5659
5660 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
5661
5662 duk__patch_jump_here(comp_ctx, pc_jump_end);
5663 } else {
5664 DUK_DDD(DUK_DDDPRINT("if does not have else part"));
5665
5666 duk__patch_jump_here(comp_ctx, pc_jump_false);
5667 }
5668
5669 DUK_DDD(DUK_DDDPRINT("end parsing if statement"));
5670 }
5671
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;
5674 duk_int_t pc_start;
5675
5676 DUK_DDD(DUK_DDDPRINT("begin parsing do statement"));
5677
5678 duk__advance(comp_ctx); /* eat 'do' */
5679
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 */
5683
5684 duk__advance_expect(comp_ctx, DUK_TOK_WHILE);
5685 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
5686
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 */
5691
5692 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
5693
5694 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
5695
5696 DUK_DDD(DUK_DDDPRINT("end parsing do statement"));
5697 }
5698
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;
5702 duk_int_t pc_start;
5703 duk_int_t pc_jump_false;
5704
5705 DUK_DDD(DUK_DDDPRINT("begin parsing while statement"));
5706
5707 temp_reset = DUK__GETTEMP(comp_ctx);
5708
5709 duk__advance(comp_ctx); /* eat 'while' */
5710
5711 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
5712
5713 pc_start = duk__get_current_pc(comp_ctx);
5714 duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
5715
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);
5720
5721 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
5722
5723 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
5724 duk__emit_jump(comp_ctx, pc_start);
5725
5726 duk__patch_jump_here(comp_ctx, pc_jump_false);
5727 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
5728
5729 DUK_DDD(DUK_DDDPRINT("end parsing while statement"));
5730 }
5731
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);
5735 duk_int_t label_id;
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;
5739
5740 DUK_UNREF(res);
5741
5742 duk__advance(comp_ctx); /* eat 'break' or 'continue' */
5743
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 */
5748
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);
5755 } else {
5756 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL);
5757 }
5758
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.
5763 */
5764
5765 if (label_catch_depth == comp_ctx->curr_func.catch_depth &&
5766 label_is_closest) {
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));
5772
5773 duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2));
5774 } else {
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));
5780
5781 duk__emit_extraop_bc(comp_ctx,
5782 is_break ? DUK_EXTRAOP_BREAK : DUK_EXTRAOP_CONTINUE,
5783 (duk_regconst_t) label_id);
5784 }
5785 }
5786
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;
5791
5792 duk__advance(comp_ctx); /* eat 'return' */
5793
5794 /* A 'return' statement is only allowed inside an actual function body,
5795 * not as part of eval or global code.
5796 */
5797 if (!comp_ctx->curr_func.is_function) {
5798 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN);
5799 }
5800
5801 ret_flags = 0;
5802
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"));
5807 rc_val = 0;
5808 } else {
5809 duk_int_t pc_before_expr;
5810 duk_int_t pc_after_expr;
5811
5812 DUK_DDD(DUK_DDDPRINT("return with a value"));
5813
5814 DUK_UNREF(pc_before_expr);
5815 DUK_UNREF(pc_after_expr);
5816
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);
5820
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.)
5829 *
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
5837 * be incorrect.
5838 *
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
5847 * below.
5848 *
5849 * See: test-bug-comma-expr-gh131.js.
5850 *
5851 * The non-standard 'caller' property disables tail calls
5852 * because they pose some special cases which haven't been
5853 * fixed yet.
5854 */
5855
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;
5861
5862 instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1);
5863 DUK_ASSERT(instr != NULL);
5864
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);
5874 }
5875 }
5876 #endif /* DUK_USE_TAILCALL */
5877
5878 ret_flags = DUK_BC_RETURN_FLAG_HAVE_RETVAL;
5879 }
5880
5881 duk__emit_a_b(comp_ctx,
5882 DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
5883 (duk_regconst_t) ret_flags /*flags*/,
5884 rc_val /*reg*/);
5885 }
5886
5887 DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
5888 duk_reg_t reg_val;
5889
5890 duk__advance(comp_ctx); /* eat 'throw' */
5891
5892 /* Unlike break/continue, throw statement does not allow an empty value. */
5893
5894 if (comp_ctx->curr_token.lineterm) {
5895 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW);
5896 }
5897
5898 reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
5899 duk__emit_extraop_bc(comp_ctx,
5900 DUK_EXTRAOP_THROW,
5901 (duk_regconst_t) reg_val);
5902 }
5903
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;
5914
5915 DUK_UNREF(res);
5916
5917 /*
5918 * See the following documentation for discussion:
5919 *
5920 * doc/execution.rst: control flow details
5921 *
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).
5927 *
5928 * Finally part has a 'let scoped' variable, which requires a few kinks
5929 * here.
5930 */
5931
5932 comp_ctx->curr_func.catch_depth++;
5933
5934 duk__advance(comp_ctx); /* eat 'try' */
5935
5936 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
5937
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.)
5942 */
5943 pc_ldconst = duk__get_current_pc(comp_ctx);
5944 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_catch, 0 /*patched later*/);
5945
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) */
5950
5951 /* try part */
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);
5957
5958 if (comp_ctx->curr_token.t == DUK_TOK_CATCH) {
5959 /*
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).
5963 */
5964
5965 /*
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.
5972 *
5973 * See: test-bug-catch-binding-2.js.
5974 *
5975 * XXX: improve to get fast path access to most catch clauses.
5976 */
5977
5978 duk_hstring *h_var;
5979 duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */
5980
5981 DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(ctx)));
5982
5983 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
5984
5985 pc_catch = duk__get_current_pc(comp_ctx);
5986
5987 duk__advance(comp_ctx);
5988 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
5989
5990 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
5991 /* Identifier, i.e. don't allow reserved words */
5992 goto syntax_error;
5993 }
5994 h_var = comp_ctx->curr_token.str1;
5995 DUK_ASSERT(h_var != NULL);
5996
5997 duk_push_hstring(ctx, h_var); /* keep in on valstack, use borrowed ref below */
5998
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"));
6003 goto syntax_error;
6004 }
6005
6006 duk_dup_top(ctx);
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));
6010
6011 duk__advance(comp_ctx);
6012 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
6013
6014 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
6015
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)));
6018
6019 duk_dup_top(ctx);
6020 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
6021 if (duk_is_undefined(ctx, -1)) {
6022 varmap_value = -2;
6023 } else if (duk_is_null(ctx, -1)) {
6024 varmap_value = -1;
6025 } else {
6026 DUK_ASSERT(duk_is_number(ctx, -1));
6027 varmap_value = duk_get_int(ctx, -1);
6028 DUK_ASSERT(varmap_value >= 0);
6029 }
6030 duk_pop(ctx);
6031
6032 #if 0
6033 /* It'd be nice to do something like this - but it doesn't
6034 * work for closures created inside the catch clause.
6035 */
6036 duk_dup_top(ctx);
6037 duk_push_int(ctx, (duk_int_t) (reg_catch + 0));
6038 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
6039 #endif
6040 duk_dup_top(ctx);
6041 duk_push_null(ctx);
6042 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
6043
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*/);
6048
6049 DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
6050 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
6051
6052 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
6053 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
6054
6055 if (varmap_value == -2) {
6056 /* not present */
6057 duk_del_prop(ctx, comp_ctx->curr_func.varmap_idx);
6058 } else {
6059 if (varmap_value == -1) {
6060 duk_push_null(ctx);
6061 } else {
6062 DUK_ASSERT(varmap_value >= 0);
6063 duk_push_int(ctx, varmap_value);
6064 }
6065 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
6066 }
6067 /* varname is popped by above code */
6068
6069 DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
6070 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
6071
6072 duk__emit_extraop_only(comp_ctx,
6073 DUK_EXTRAOP_ENDCATCH);
6074
6075 /*
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.
6079 */
6080
6081 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
6082
6083 DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(ctx)));
6084 }
6085
6086 if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
6087 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY;
6088
6089 pc_finally = duk__get_current_pc(comp_ctx);
6090
6091 duk__advance(comp_ctx);
6092
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,
6097 DUK_EXTRAOP_ENDFIN,
6098 reg_catch); /* rethrow */
6099 }
6100
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 */
6104 goto syntax_error;
6105 }
6106
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.
6110 */
6111
6112 duk__patch_trycatch(comp_ctx,
6113 pc_ldconst,
6114 pc_trycatch,
6115 reg_catch,
6116 rc_varname,
6117 trycatch_flags);
6118
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);
6122 }
6123
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);
6127 } else {
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);
6130 }
6131
6132 comp_ctx->curr_func.catch_depth--;
6133 return;
6134
6135 syntax_error:
6136 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY);
6137 }
6138
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;
6144
6145 if (comp_ctx->curr_func.is_strict) {
6146 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE);
6147 }
6148
6149 comp_ctx->curr_func.catch_depth++;
6150
6151 duk__advance(comp_ctx); /* eat 'with' */
6152
6153 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
6154
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);
6158
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 */
6167
6168 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
6169 duk__emit_extraop_only(comp_ctx,
6170 DUK_EXTRAOP_ENDTRY);
6171
6172 pc_finished = duk__get_current_pc(comp_ctx);
6173
6174 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished);
6175
6176 comp_ctx->curr_func.catch_depth--;
6177 }
6178
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) {
6182 return label_id;
6183 }
6184
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));
6187
6188 duk__emit_extraop_bc(comp_ctx,
6189 DUK_EXTRAOP_LABEL,
6190 (duk_regconst_t) label_id);
6191 duk__emit_invalid(comp_ctx);
6192 duk__emit_invalid(comp_ctx);
6193
6194 return label_id;
6195 }
6196
6197 /* Parse a single statement.
6198 *
6199 * Creates a label site (with an empty label) automatically for iteration
6200 * statements. Also "peels off" any label statements for explicit labels.
6201 */
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" */
6209 duk_int_t stmt_id;
6210 duk_small_uint_t stmt_flags = 0;
6211 duk_int_t label_id = -1;
6212 duk_small_uint_t tok;
6213
6214 DUK__RECURSION_INCREASE(comp_ctx, thr);
6215
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;
6221
6222 DUK_UNREF(stmt_id);
6223
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));
6229
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.)
6234 */
6235 comp_ctx->curr_func.in_directive_prologue = 0;
6236
6237 retry_parse:
6238
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));
6242
6243 /*
6244 * Detect iteration statements; if encountered, establish an
6245 * empty label.
6246 */
6247
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"));
6252
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*/,
6257 label_id);
6258 }
6259
6260 /*
6261 * Main switch for statement / source element type.
6262 */
6263
6264 switch (comp_ctx->curr_token.t) {
6265 case DUK_TOK_FUNCTION: {
6266 /*
6267 * Function declaration, function expression, or (non-standard)
6268 * function statement.
6269 *
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.
6277 */
6278
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.
6282 */
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 */
6288 {
6289 /* FunctionDeclaration: not strictly a statement but handled as such.
6290 *
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().
6295 */
6296
6297 duk_int_t fnum;
6298
6299 DUK_DDD(DUK_DDDPRINT("function declaration statement"));
6300
6301 duk__advance(comp_ctx); /* eat 'function' */
6302 fnum = duk__parse_func_like_fnum(comp_ctx, 1 /*is_decl*/, 0 /*is_setget*/);
6303
6304 if (comp_ctx->curr_func.in_scanning) {
6305 duk_uarridx_t n;
6306 duk_hstring *h_funcname;
6307
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);
6312
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);
6320
6321 duk_pop_n(ctx, 2);
6322 }
6323
6324 /* no statement value (unlike function expression) */
6325 stmt_flags = 0;
6326 break;
6327 } else {
6328 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED);
6329 }
6330 break;
6331 }
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 */
6339 }
6340 stmt_flags = 0;
6341 break;
6342 }
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;
6347 break;
6348 }
6349 case DUK_TOK_VAR: {
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;
6353 break;
6354 }
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;
6359 break;
6360 }
6361 case DUK_TOK_IF: {
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 */
6366 }
6367 stmt_flags = 0;
6368 break;
6369 }
6370 case DUK_TOK_DO: {
6371 /*
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:
6375 *
6376 * https://bugs.ecmascript.org/show_bug.cgi?id=8
6377 *
6378 * See doc/compiler.rst for details.
6379 */
6380 DUK_DDD(DUK_DDDPRINT("do statement"));
6381 DUK_ASSERT(label_id >= 0);
6382 duk__update_label_flags(comp_ctx,
6383 label_id,
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 */
6387 break;
6388 }
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,
6393 label_id,
6394 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
6395 duk__parse_while_stmt(comp_ctx, res, pc_at_entry);
6396 stmt_flags = 0;
6397 break;
6398 }
6399 case DUK_TOK_FOR: {
6400 /*
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.
6404 *
6405 * See the helper for the messy stuff.
6406 */
6407 DUK_DDD(DUK_DDDPRINT("for/for-in statement"));
6408 DUK_ASSERT(label_id >= 0);
6409 duk__update_label_flags(comp_ctx,
6410 label_id,
6411 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
6412 duk__parse_for_stmt(comp_ctx, res, pc_at_entry);
6413 stmt_flags = 0;
6414 break;
6415 }
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;
6421 break;
6422 }
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;
6427 break;
6428 }
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 */
6435 }
6436 comp_ctx->curr_func.with_depth--;
6437 stmt_flags = 0;
6438 break;
6439 }
6440 case DUK_TOK_SWITCH: {
6441 /*
6442 * The switch statement is pretty messy to compile.
6443 * See the helper for details.
6444 */
6445 DUK_DDD(DUK_DDDPRINT("switch statement"));
6446 DUK_ASSERT(label_id >= 0);
6447 duk__update_label_flags(comp_ctx,
6448 label_id,
6449 DUK_LABEL_FLAG_ALLOW_BREAK); /* don't allow continue */
6450 duk__parse_switch_stmt(comp_ctx, res, pc_at_entry);
6451 stmt_flags = 0;
6452 break;
6453 }
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;
6458 break;
6459 }
6460 case DUK_TOK_TRY: {
6461 DUK_DDD(DUK_DDDPRINT("try statement"));
6462 duk__parse_try_stmt(comp_ctx, res);
6463 stmt_flags = 0;
6464 break;
6465 }
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);
6471 #else
6472 DUK_DDD(DUK_DDDPRINT("debugger statement: ignored"));
6473 #endif
6474 stmt_flags = DUK__HAS_TERM;
6475 break;
6476 }
6477 default: {
6478 /*
6479 * Else, must be one of:
6480 * - ExpressionStatement, possibly a directive (String)
6481 * - LabelledStatement (Identifier followed by ':')
6482 *
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.
6487 *
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:
6492 *
6493 * 'use strict'; // valid 'use strict' directive
6494 * 'use\u0020strict'; // valid directive, not a 'use strict' directive
6495 * ('use strict'); // not a valid directive
6496 *
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.
6503 *
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.
6507 *
6508 * A similar approach is used for labels.
6509 */
6510
6511 duk_bool_t single_token;
6512
6513 DUK_DDD(DUK_DDDPRINT("expression statement"));
6514 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
6515
6516 single_token = (comp_ctx->curr_func.nud_count == 1 && /* one token */
6517 comp_ctx->curr_func.led_count == 0); /* no operators */
6518
6519 if (single_token &&
6520 comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
6521 comp_ctx->curr_token.t == DUK_TOK_COLON) {
6522 /*
6523 * Detected label
6524 */
6525
6526 duk_hstring *h_lab;
6527
6528 /* expected ival */
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);
6534
6535 DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'",
6536 (duk_heaphdr *) h_lab));
6537
6538 duk__advance(comp_ctx); /* eat colon */
6539
6540 label_id = duk__stmt_label_site(comp_ctx, label_id);
6541
6542 duk__add_label(comp_ctx,
6543 h_lab,
6544 pc_at_entry /*pc_label*/,
6545 label_id);
6546
6547 /* a statement following a label cannot be a source element
6548 * (a function declaration).
6549 */
6550 allow_source_elem = 0;
6551
6552 DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing"));
6553 goto retry_parse;
6554 }
6555
6556 stmt_flags = 0;
6557
6558 if (dir_prol_at_entry && /* still in prologue */
6559 single_token && /* single string token */
6560 comp_ctx->prev_token.t == DUK_TOK_STRING) {
6561 /*
6562 * Detected a directive
6563 */
6564 duk_hstring *h_dir;
6565
6566 /* expected ival */
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);
6572
6573 DUK_DDD(DUK_DDDPRINT("potential directive: %!O", h_dir));
6574
6575 stmt_flags |= DUK__STILL_PROLOGUE;
6576
6577 /* Note: escaped characters differentiate directives */
6578
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"));
6582 } else {
6583 /*
6584 * The length comparisons are present to handle
6585 * strings like "use strict\u0000foo" as required.
6586 */
6587
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;
6594 #else
6595 DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring"));
6596 #endif
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;
6602 } else {
6603 DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
6604 "directive prologue", (duk_hobject *) h_dir));
6605 }
6606 }
6607 } else {
6608 DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; "
6609 "prologue terminated if still active"));
6610 }
6611
6612 stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM;
6613 }
6614 } /* end switch (tok) */
6615
6616 /*
6617 * Statement value handling.
6618 *
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).
6623 *
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;").
6630 */
6631
6632 /* XXX: what about statements which leave a half-cooked value in 'res'
6633 * but have no stmt value? Any such statements?
6634 */
6635
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);
6640 } else {
6641 duk__ivalue_toplain_ignore(comp_ctx, res);
6642 }
6643 } else {
6644 ;
6645 }
6646
6647 /*
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.
6651 */
6652
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);
6657 } else {
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)"));
6664 } else {
6665 DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT);
6666 }
6667 }
6668 } else {
6669 DUK_DDD(DUK_DDDPRINT("statement has no terminator"));
6670 }
6671
6672 /*
6673 * Directive prologue tracking.
6674 */
6675
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;
6679 }
6680
6681 /*
6682 * Cleanups (all statement parsing flows through here).
6683 *
6684 * Pop label site and reset labels. Reset 'next temp' to value at
6685 * entry to reuse temps.
6686 */
6687
6688 if (label_id >= 0) {
6689 duk__emit_extraop_bc(comp_ctx,
6690 DUK_EXTRAOP_ENDLABEL,
6691 (duk_regconst_t) label_id);
6692 }
6693
6694 DUK__SETTEMP(comp_ctx, temp_at_entry);
6695
6696 duk__reset_labels_to_length(comp_ctx, labels_len_at_entry);
6697
6698 /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */
6699
6700 DUK__RECURSION_DECREASE(comp_ctx, thr);
6701 }
6702
6703 #undef DUK__HAS_VAL
6704 #undef DUK__HAS_TERM
6705 #undef DUK__ALLOW_AUTO_SEMI_ALWAYS
6706
6707 /*
6708 * Parse a statement list.
6709 *
6710 * Handles automatic semicolon insertion and implicit return value.
6711 *
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).
6716 */
6717
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;
6723
6724 /* Setup state. Initial ivalue is 'undefined'. */
6725
6726 duk_require_stack(ctx, DUK__PARSE_STATEMENTS_SLOTS);
6727
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).
6731 */
6732
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);
6740
6741 /* Parse statements until a closing token (EOF or '}') is found. */
6742
6743 for (;;) {
6744 /* Check whether statement list ends. */
6745
6746 if (expect_eof) {
6747 if (comp_ctx->curr_token.t == DUK_TOK_EOF) {
6748 break;
6749 }
6750 } else {
6751 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
6752 break;
6753 }
6754 }
6755
6756 /* Check statement type based on the first token type.
6757 *
6758 * Note: expression parsing helpers expect 'curr_tok' to
6759 * contain the first token of the expression upon entry.
6760 */
6761
6762 DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)", (long) comp_ctx->curr_token.t));
6763
6764 duk__parse_stmt(comp_ctx, res, allow_source_elem);
6765 }
6766
6767 duk__advance(comp_ctx);
6768
6769 /* Tear down state. */
6770
6771 duk_pop_2(ctx);
6772 }
6773
6774 /*
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.
6778 *
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.
6784 *
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.
6790 *
6791 * Some bindings in E5 are not configurable (= deletable) and almost all
6792 * are mutable (writable). Exceptions are:
6793 *
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.
6797 *
6798 * - The "name" binding for a named function expression. This is also
6799 * handled through an explicit slow path environment record.
6800 */
6801
6802 /* XXX: add support for variables to not be register bound always, to
6803 * handle cases with a very large number of variables?
6804 */
6805
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;
6815 duk_uarridx_t i;
6816 #ifdef DUK_USE_ASSERTIONS
6817 duk_idx_t entry_top;
6818 #endif
6819
6820 #ifdef DUK_USE_ASSERTIONS
6821 entry_top = duk_get_top(ctx);
6822 #endif
6823
6824 /*
6825 * Preliminaries
6826 */
6827
6828 configurable_bindings = comp_ctx->curr_func.is_eval;
6829 DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld", (long) configurable_bindings));
6830
6831 /* varmap is already in comp_ctx->curr_func.varmap_idx */
6832
6833 /*
6834 * Function formal arguments, always bound to registers
6835 * (there's no support for shuffling them now).
6836 */
6837
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 */
6841
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);
6846
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"));
6850 goto error_argname;
6851 }
6852 duk_dup_top(ctx);
6853 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
6854 DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
6855 goto error_argname;
6856 }
6857
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
6861 * parsing.
6862 *
6863 * We only need to do this in strict mode because non-strict
6864 * keyword are always detected in formal argument parsing.
6865 */
6866
6867 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) {
6868 goto error_argname;
6869 }
6870 }
6871
6872 /* overwrite any previous binding of the same name; the effect is
6873 * that last argument of a certain name wins.
6874 */
6875
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); /* -> [ ... ] */
6880
6881 /* no code needs to be emitted, the regs already have values */
6882 }
6883
6884 /* use temp_next for tracking register allocations */
6885 DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_reg_t) num_args);
6886
6887 /*
6888 * After arguments, allocate special registers (like shuffling temps)
6889 */
6890
6891 if (out_stmt_value_reg) {
6892 *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
6893 }
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));
6903 }
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;
6907 }
6908
6909 /*
6910 * Function declarations
6911 */
6912
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",
6915 (long) num_decls,
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;
6919 duk_int_t fnum;
6920
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;
6925 duk_pop(ctx);
6926
6927 if (decl_type != DUK_DECL_TYPE_FUNC) {
6928 continue;
6929 }
6930
6931 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
6932
6933 /* XXX: spilling */
6934 if (comp_ctx->curr_func.is_function) {
6935 duk_reg_t reg_bind;
6936 duk_dup_top(ctx);
6937 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
6938 /* shadowed; update value */
6939 duk_dup_top(ctx);
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,
6943 DUK_OP_CLOSURE,
6944 (duk_regconst_t) reg_bind,
6945 (duk_regconst_t) fnum);
6946 } else {
6947 /* function: always register bound */
6948 reg_bind = DUK__ALLOCTEMP(comp_ctx);
6949 duk__emit_a_bc(comp_ctx,
6950 DUK_OP_CLOSURE,
6951 (duk_regconst_t) reg_bind,
6952 (duk_regconst_t) fnum);
6953 duk_push_int(ctx, (duk_int_t) reg_bind);
6954 }
6955 } else {
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).
6959 *
6960 * DECLVAR will not re-declare a variable as such, but will
6961 * update the binding value.
6962 */
6963
6964 duk_reg_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
6965 duk_dup_top(ctx);
6966 rc_name = duk__getconst(comp_ctx);
6967 duk_push_null(ctx);
6968
6969 duk__emit_a_bc(comp_ctx,
6970 DUK_OP_CLOSURE,
6971 (duk_regconst_t) reg_temp,
6972 (duk_regconst_t) fnum);
6973
6974 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
6975 DUK_PROPDESC_FLAG_ENUMERABLE |
6976 DUK_BC_DECLVAR_FLAG_FUNC_DECL;
6977
6978 if (configurable_bindings) {
6979 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
6980 }
6981
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*/,
6985 rc_name /*name*/,
6986 (duk_regconst_t) reg_temp /*value*/);
6987
6988 DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */
6989 }
6990
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)));
6994
6995 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
6996 }
6997
6998 /*
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.
7003 */
7004
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;
7009 }
7010
7011 /*
7012 * Variable declarations.
7013 *
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.
7017 */
7018
7019 for (i = 0; i < num_decls; i += 2) {
7020 duk_int_t decl_type;
7021
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;
7025 duk_pop(ctx);
7026
7027 if (decl_type != DUK_DECL_TYPE_VAR) {
7028 continue;
7029 }
7030
7031 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
7032
7033 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
7034 /* shadowed, ignore */
7035 } else {
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);
7039
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"));
7046 duk_pop(ctx);
7047 continue;
7048 }
7049
7050 /* XXX: spilling */
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);
7055 } else {
7056 duk_dup_top(ctx);
7057 rc_name = duk__getconst(comp_ctx);
7058 duk_push_null(ctx);
7059
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;
7065 }
7066
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*/,
7070 rc_name /*name*/,
7071 (duk_regconst_t) 0 /*value*/);
7072 }
7073
7074 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
7075 }
7076 }
7077
7078 /*
7079 * Wrap up
7080 */
7081
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));
7085
7086 DUK_ASSERT_TOP(ctx, entry_top);
7087 return;
7088
7089 error_outofregs:
7090 DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT);
7091 DUK_UNREACHABLE();
7092 return;
7093
7094 error_argname:
7095 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME);
7096 DUK_UNREACHABLE();
7097 return;
7098 }
7099
7100 /*
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:
7104 *
7105 * - function expression
7106 * - function statement
7107 * - function declaration
7108 * - getter in object literal
7109 * - setter in object literal
7110 * - global code
7111 * - eval code
7112 * - Function constructor body
7113 *
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.
7119 *
7120 * Note that there are many differences affecting parsing and even code
7121 * generation:
7122 *
7123 * - Global and eval code have an implicit return value generated
7124 * by the last statement; function code does not
7125 *
7126 * - Global code, eval code, and Function constructor body end in
7127 * an EOF, other bodies in a closing brace ('}')
7128 *
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).
7132 */
7133
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;
7136 duk_hthread *thr;
7137 duk_context *ctx;
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;
7142
7143 DUK_ASSERT(comp_ctx != NULL);
7144
7145 thr = comp_ctx->thr;
7146 ctx = (duk_context *) thr;
7147 DUK_ASSERT(thr != NULL);
7148
7149 func = &comp_ctx->curr_func;
7150 DUK_ASSERT(func != NULL);
7151
7152 DUK__RECURSION_INCREASE(comp_ctx, thr);
7153
7154 duk_require_stack(ctx, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
7155
7156 /*
7157 * Store lexer position for a later rewind
7158 */
7159
7160 DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt);
7161
7162 /*
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.
7168 */
7169
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);
7173
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.
7178 *
7179 * However, since 1st pass is a throwaway one, no need to emit
7180 * it here.
7181 */
7182 #if 0
7183 duk__emit_extraop_bc(comp_ctx,
7184 DUK_EXTRAOP_LDUNDEF,
7185 0);
7186 #endif
7187 }
7188
7189 /*
7190 * First pass.
7191 *
7192 * Gather variable/function declarations needed for second pass.
7193 * Code generated is dummy and discarded.
7194 */
7195
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;
7204 func->max_line = 0;
7205 #endif
7206
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.
7211 */
7212 DUK_ASSERT(expect_token == DUK_TOK_LCURLY);
7213 duk__update_lineinfo_currtoken(comp_ctx);
7214 duk__advance_expect(comp_ctx, expect_token);
7215 } else {
7216 /* Need to set curr_token.t because lexing regexp mode depends on current
7217 * token type. Zero value causes "allow regexp" mode.
7218 */
7219 comp_ctx->curr_token.t = 0;
7220 duk__advance(comp_ctx);
7221 }
7222
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"));
7228
7229 /*
7230 * Second (and possibly third) pass.
7231 *
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).
7236 */
7237
7238 for (;;) {
7239 duk_bool_t needs_shuffle_before = comp_ctx->curr_func.needs_shuffle;
7240 compile_round++;
7241
7242 /*
7243 * Rewind lexer.
7244 *
7245 * duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp
7246 * literal" mode with current strictness.
7247 *
7248 * curr_token line number info should be initialized for pass 2 before
7249 * generating prologue, to ensure prologue bytecode gets nice line numbers.
7250 */
7251
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);
7257
7258 /*
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.
7262 *
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.
7266 *
7267 * Inner functions are compiled during pass 1 and are not reset.
7268 */
7269
7270 duk__reset_func_for_pass2(comp_ctx);
7271 func->in_directive_prologue = 1;
7272 func->in_scanning = 0;
7273
7274 /* must be able to emit code, alloc consts, etc. */
7275
7276 duk__init_varmap_and_prologue_for_pass2(comp_ctx,
7277 (implicit_return_value ? &reg_stmt_value : NULL));
7278 func->reg_stmt_value = reg_stmt_value;
7279
7280 temp_first = DUK__GETTEMP(comp_ctx);
7281
7282 func->temp_first = temp_first;
7283 func->temp_next = temp_first;
7284 func->stmt_next = 0;
7285 func->label_next = 0;
7286
7287 /* XXX: init or assert catch depth etc -- all values */
7288 func->id_access_arguments = 0;
7289 func->id_access_slow = 0;
7290
7291 /*
7292 * Check function name validity now that we know strictness.
7293 * This only applies to function declarations and expressions,
7294 * not setter/getter name.
7295 *
7296 * See: test-dev-strict-mode-boundary.js
7297 */
7298
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;
7304 }
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;
7308 }
7309 } else {
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;
7314 }
7315 }
7316 }
7317
7318 /*
7319 * Second pass parsing.
7320 */
7321
7322 if (implicit_return_value) {
7323 /* Default implicit return value. */
7324 duk__emit_extraop_bc(comp_ctx,
7325 DUK_EXTRAOP_LDUNDEF,
7326 0);
7327 }
7328
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"));
7334
7335 duk__update_lineinfo_currtoken(comp_ctx);
7336
7337 if (needs_shuffle_before == comp_ctx->curr_func.needs_shuffle) {
7338 /* Shuffle decision not changed. */
7339 break;
7340 }
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);
7345 }
7346 DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round));
7347 }
7348
7349 /*
7350 * Emit a final RETURN.
7351 *
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).
7357 */
7358
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)
7362 */
7363
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*/);
7370 } else {
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)*/);
7375 }
7376
7377 /*
7378 * Peephole optimize JUMP chains.
7379 */
7380
7381 duk__peephole_optimize_bytecode(comp_ctx);
7382
7383 /*
7384 * comp_ctx->curr_func is now ready to be converted into an actual
7385 * function template.
7386 */
7387
7388 DUK__RECURSION_DECREASE(comp_ctx, thr);
7389 return;
7390
7391 error_funcname:
7392 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME);
7393 }
7394
7395 /*
7396 * Parse a function-like expression:
7397 *
7398 * - function expression
7399 * - function declaration
7400 * - function statement (non-standard)
7401 * - setter/getter
7402 *
7403 * Adds the function to comp_ctx->curr_func function table and returns the
7404 * function number.
7405 *
7406 * On entry, curr_token points to:
7407 *
7408 * - the token after 'function' for function expression/declaration/statement
7409 * - the token after 'set' or 'get' for setter/getter
7410 */
7411
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;
7417 duk_uarridx_t n;
7418
7419 for (;;) {
7420 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
7421 break;
7422 }
7423
7424 if (first) {
7425 /* no comma */
7426 first = 0;
7427 } else {
7428 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
7429 }
7430
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).
7438 */
7439
7440 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
7441 DUK_ERROR_SYNTAX(thr, "expected identifier");
7442 }
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));
7447
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);
7452
7453 duk__advance(comp_ctx); /* eat identifier */
7454 }
7455 }
7456
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
7459 * 'set'/'get' etc).
7460 */
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;
7464
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);
7471
7472 duk__update_lineinfo_currtoken(comp_ctx);
7473
7474 /*
7475 * Function name (if any)
7476 *
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.
7480 *
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() { ... } }").
7485 */
7486
7487 if (is_setget) {
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);
7495 } else {
7496 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME);
7497 }
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);
7501 } else {
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.
7505 */
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);
7511 } else {
7512 /* valstack will be unbalanced, which is OK */
7513 DUK_ASSERT(!is_setget);
7514 if (is_decl) {
7515 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED);
7516 }
7517 }
7518 }
7519
7520 DUK_DDD(DUK_DDDPRINT("function name: %!O",
7521 (duk_heaphdr *) comp_ctx->curr_func.h_name));
7522
7523 /*
7524 * Formal argument list
7525 *
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.
7529 */
7530
7531 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
7532
7533 duk__parse_func_formals(comp_ctx);
7534
7535 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN);
7536 duk__advance(comp_ctx);
7537
7538 /*
7539 * Parse function body
7540 */
7541
7542 duk__parse_func_body(comp_ctx,
7543 0, /* expect_eof */
7544 0, /* implicit_return_value */
7545 DUK_TOK_LCURLY); /* expect_token */
7546
7547 /*
7548 * Convert duk_compiler_func to a function template and add it
7549 * to the parent function table.
7550 */
7551
7552 duk__convert_to_func_template(comp_ctx, is_setget /*force_no_namebind*/); /* -> [ ... func ] */
7553 }
7554
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.
7557 *
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.
7563 *
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
7567 * were used.
7568 */
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;
7574 duk_int_t fnum;
7575
7576 /*
7577 * On second pass, skip the function.
7578 */
7579
7580 if (!comp_ctx->curr_func.in_scanning) {
7581 duk_lexer_point lex_pt;
7582
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);
7586 duk_pop(ctx);
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);
7589 duk_pop(ctx);
7590
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));
7593
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);
7599
7600 return fnum;
7601 }
7602
7603 /*
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.
7606 */
7607
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));
7611
7612 DUK_MEMCPY(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func));
7613
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);
7617
7618 /* inherit initial strictness from parent */
7619 comp_ctx->curr_func.is_strict = old_func.is_strict;
7620
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;
7627
7628 /*
7629 * Parse inner function
7630 */
7631
7632 duk__parse_func_like_raw(comp_ctx, is_decl, is_setget); /* pushes function template */
7633
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.
7637 */
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);
7641
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++;
7645
7646 if (fnum > DUK__MAX_FUNCS) {
7647 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT);
7648 }
7649
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));
7656
7657 /*
7658 * Cleanup: restore original function, restore valstack state.
7659 */
7660
7661 DUK_MEMCPY((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func));
7662 duk_set_top(ctx, entry_top);
7663
7664 DUK_ASSERT_TOP(ctx, entry_top);
7665
7666 return fnum;
7667 }
7668
7669 /*
7670 * Compile input string into an executable function template without
7671 * arguments.
7672 *
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).
7676 *
7677 * Input stack: [ ... filename ]
7678 * Output stack: [ ... func_template ]
7679 */
7680
7681 /* XXX: source code property */
7682
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;
7692 duk_bool_t is_eval;
7693 duk_bool_t is_funcexpr;
7694 duk_small_uint_t flags;
7695
7696 DUK_ASSERT(thr != NULL);
7697
7698 /*
7699 * Arguments check
7700 */
7701
7702 entry_top = duk_get_top(ctx);
7703 DUK_ASSERT(entry_top >= 2);
7704
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);
7710
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);
7715
7716 h_filename = duk_get_hstring(ctx, -2); /* may be undefined */
7717
7718 /*
7719 * Init compiler and lexer contexts
7720 */
7721
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;
7730 #endif
7731
7732 duk_require_stack(ctx, DUK__COMPILE_ENTRY_SLOTS);
7733
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 */
7739
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;
7747
7748 /* comp_ctx->lex has been pre-initialized by caller: it has been
7749 * zeroed and input/input_length has been set.
7750 */
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;
7760
7761 lex_pt->offset = 0;
7762 lex_pt->line = 1;
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) */
7765
7766 /*
7767 * Initialize function state for a zero-argument function
7768 */
7769
7770 duk__init_func_valstack_slots(comp_ctx);
7771 DUK_ASSERT(func->num_formals == 0);
7772
7773 if (is_funcexpr) {
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.
7777 */
7778 DUK_ASSERT(func->h_name == NULL);
7779 } else {
7780 duk_push_hstring_stridx(ctx, (is_eval ? DUK_STRIDX_EVAL :
7781 DUK_STRIDX_GLOBAL));
7782 func->h_name = duk_get_hstring(ctx, -1);
7783 }
7784
7785 /*
7786 * Parse a function body or a function-like expression, depending
7787 * on flags.
7788 */
7789
7790 func->is_strict = is_strict;
7791 func->is_setget = 0;
7792 func->is_decl = 0;
7793
7794 if (is_funcexpr) {
7795 func->is_function = 1;
7796 func->is_eval = 0;
7797 func->is_global = 0;
7798
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,
7802 0, /* is_decl */
7803 0); /* is_setget */
7804 } else {
7805 func->is_function = 0;
7806 func->is_eval = is_eval;
7807 func->is_global = !is_eval;
7808
7809 duk__parse_func_body(comp_ctx,
7810 1, /* expect_eof */
7811 1, /* implicit_return_value */
7812 -1); /* expect_token */
7813 }
7814
7815 /*
7816 * Convert duk_compiler_func to a function template
7817 */
7818
7819 duk__convert_to_func_template(comp_ctx, 0 /*force_no_namebind*/);
7820
7821 /*
7822 * Wrapping duk_safe_call() will mangle the stack, just return stack top
7823 */
7824
7825 /* [ ... filename (temps) func ] */
7826
7827 return 1;
7828 }
7829
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;
7834 duk_ret_t safe_rc;
7835
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.
7839 */
7840
7841 DUK_ASSERT(thr != NULL);
7842 DUK_ASSERT(src_buffer != NULL);
7843
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;
7850
7851 duk_push_pointer(ctx, (void *) &comp_stk);
7852
7853 /* [ ... filename &comp_stk ] */
7854
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 */
7859
7860 if (safe_rc != DUK_EXEC_SUCCESS) {
7861 duk_throw(ctx);
7862 }
7863
7864 /* [ ... template ] */
7865 }