48 |
#include "jstypes.h" |
#include "jstypes.h" |
49 |
#include "jsatom.h" |
#include "jsatom.h" |
50 |
#include "jsopcode.h" |
#include "jsopcode.h" |
51 |
|
#include "jsparse.h" |
52 |
#include "jsscript.h" |
#include "jsscript.h" |
53 |
#include "jsprvtd.h" |
#include "jsprvtd.h" |
54 |
#include "jspubtd.h" |
#include "jspubtd.h" |
126 |
struct JSStmtInfo { |
struct JSStmtInfo { |
127 |
uint16 type; /* statement type */ |
uint16 type; /* statement type */ |
128 |
uint16 flags; /* flags, see below */ |
uint16 flags; /* flags, see below */ |
129 |
|
uint32 blockid; /* for simplified dominance computation */ |
130 |
ptrdiff_t update; /* loop update offset (top if none) */ |
ptrdiff_t update; /* loop update offset (top if none) */ |
131 |
ptrdiff_t breaks; /* offset of last break in loop */ |
ptrdiff_t breaks; /* offset of last break in loop */ |
132 |
ptrdiff_t continues; /* offset of last continue in loop */ |
ptrdiff_t continues; /* offset of last continue in loop */ |
133 |
union { |
union { |
134 |
JSAtom *label; /* name of LABEL */ |
JSAtom *label; /* name of LABEL */ |
135 |
JSObject *blockObj; /* block scope object */ |
JSObject *blockObj; /* block scope object */ |
136 |
} u; |
}; |
137 |
JSStmtInfo *down; /* info for enclosing statement */ |
JSStmtInfo *down; /* info for enclosing statement */ |
138 |
JSStmtInfo *downScope; /* next enclosing lexical scope */ |
JSStmtInfo *downScope; /* next enclosing lexical scope */ |
139 |
}; |
}; |
154 |
#define GOSUBS(stmt) ((stmt).breaks) |
#define GOSUBS(stmt) ((stmt).breaks) |
155 |
#define GUARDJUMP(stmt) ((stmt).continues) |
#define GUARDJUMP(stmt) ((stmt).continues) |
156 |
|
|
|
#define AT_TOP_LEVEL(tc) \ |
|
|
(!(tc)->topStmt || ((tc)->topStmt->flags & SIF_BODY_BLOCK)) |
|
|
|
|
157 |
#define SET_STATEMENT_TOP(stmt, top) \ |
#define SET_STATEMENT_TOP(stmt, top) \ |
158 |
((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1)) |
((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1)) |
159 |
|
|
160 |
|
#ifdef JS_SCOPE_DEPTH_METER |
161 |
|
# define JS_SCOPE_DEPTH_METERING(code) ((void) (code)) |
162 |
|
#else |
163 |
|
# define JS_SCOPE_DEPTH_METERING(code) ((void) 0) |
164 |
|
#endif |
165 |
|
|
166 |
struct JSTreeContext { /* tree context for semantic checks */ |
struct JSTreeContext { /* tree context for semantic checks */ |
167 |
uint16 flags; /* statement state flags, see below */ |
uint16 flags; /* statement state flags, see below */ |
168 |
uint16 ngvars; /* max. no. of global variables/regexps */ |
uint16 ngvars; /* max. no. of global variables/regexps */ |
169 |
|
uint32 bodyid; /* block number of program/function body */ |
170 |
|
uint32 blockidGen; /* preincremented block number generator */ |
171 |
JSStmtInfo *topStmt; /* top of statement info stack */ |
JSStmtInfo *topStmt; /* top of statement info stack */ |
172 |
JSStmtInfo *topScopeStmt; /* top lexical scope statement */ |
JSStmtInfo *topScopeStmt; /* top lexical scope statement */ |
173 |
JSObject *blockChain; /* compile time block scope chain (NB: one |
JSObject *blockChain; /* compile time block scope chain (NB: one |
174 |
deeper than the topScopeStmt/downScope |
deeper than the topScopeStmt/downScope |
175 |
chain when in head of let block/expr) */ |
chain when in head of let block/expr) */ |
176 |
JSParseNode *blockNode; /* parse node for a lexical scope. |
JSParseNode *blockNode; /* parse node for a block with let declarations |
177 |
XXX combine with blockChain? */ |
(block with its own lexical scope) */ |
178 |
JSAtomList decls; /* function, const, and var declarations */ |
JSAtomList decls; /* function, const, and var declarations */ |
179 |
JSParseContext *parseContext; |
JSCompiler *compiler; /* ptr to common parsing and lexing data */ |
180 |
|
|
181 |
union { |
union { |
|
|
|
182 |
JSFunction *fun; /* function to store argument and variable |
JSFunction *fun; /* function to store argument and variable |
183 |
names when flags & TCF_IN_FUNCTION */ |
names when flags & TCF_IN_FUNCTION */ |
184 |
JSObject *scopeChain; /* scope chain object for the script */ |
JSObject *scopeChain; /* scope chain object for the script */ |
185 |
} u; |
}; |
186 |
|
|
187 |
|
JSAtomList lexdeps; /* unresolved lexical name dependencies */ |
188 |
|
JSTreeContext *parent; /* enclosing function or global context */ |
189 |
|
uintN staticLevel; /* static compilation unit nesting level */ |
190 |
|
|
191 |
|
JSFunctionBox *funbox; /* null or box for function we're compiling |
192 |
|
if (flags & TCF_IN_FUNCTION) and not in |
193 |
|
JSCompiler::compileFunctionBody */ |
194 |
|
JSFunctionBox *functionList; |
195 |
|
|
196 |
#ifdef JS_SCOPE_DEPTH_METER |
#ifdef JS_SCOPE_DEPTH_METER |
197 |
uint16 scopeDepth; /* current lexical scope chain depth */ |
uint16 scopeDepth; /* current lexical scope chain depth */ |
198 |
uint16 maxScopeDepth; /* maximum lexical scope chain depth */ |
uint16 maxScopeDepth; /* maximum lexical scope chain depth */ |
199 |
#endif |
#endif |
200 |
|
|
201 |
|
JSTreeContext(JSCompiler *jsc) |
202 |
|
: flags(0), ngvars(0), bodyid(0), blockidGen(0), |
203 |
|
topStmt(NULL), topScopeStmt(NULL), blockChain(NULL), blockNode(NULL), |
204 |
|
compiler(jsc), scopeChain(NULL), parent(NULL), staticLevel(0), |
205 |
|
funbox(NULL), functionList(NULL) |
206 |
|
{ |
207 |
|
JS_SCOPE_DEPTH_METERING(scopeDepth = maxScopeDepth = 0); |
208 |
|
} |
209 |
|
|
210 |
|
/* |
211 |
|
* For functions the tree context is constructed and destructed a second |
212 |
|
* time during code generation. To avoid a redundant stats update in such |
213 |
|
* cases, we store (uintN) -1 in maxScopeDepth. |
214 |
|
*/ |
215 |
|
~JSTreeContext() { |
216 |
|
JS_SCOPE_DEPTH_METERING(maxScopeDepth == (uintN) -1 || |
217 |
|
JS_BASIC_STATS_ACCUM(&compiler |
218 |
|
->context |
219 |
|
->runtime |
220 |
|
->lexicalScopeDepthStats, |
221 |
|
maxScopeDepth)); |
222 |
|
} |
223 |
|
|
224 |
|
uintN blockid() { return topStmt ? topStmt->blockid : bodyid; } |
225 |
|
|
226 |
|
bool atTopLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); } |
227 |
|
|
228 |
|
/* Test whether we're in a statement of given type. */ |
229 |
|
bool inStatement(JSStmtType type); |
230 |
}; |
}; |
231 |
|
|
|
#define TCF_IN_FUNCTION 0x01 /* parsing inside function body */ |
|
|
#define TCF_RETURN_EXPR 0x02 /* function has 'return expr;' */ |
|
|
#define TCF_RETURN_VOID 0x04 /* function has 'return;' */ |
|
|
#define TCF_IN_FOR_INIT 0x08 /* parsing init expr of for; exclude 'in' */ |
|
|
#define TCF_FUN_CLOSURE_VS_VAR 0x10 /* function and var with same name */ |
|
|
#define TCF_FUN_USES_NONLOCALS 0x20 /* function refers to non-local names */ |
|
|
#define TCF_FUN_HEAVYWEIGHT 0x40 /* function needs Call object per call */ |
|
|
#define TCF_FUN_IS_GENERATOR 0x80 /* parsed yield statement in function */ |
|
|
#define TCF_HAS_DEFXMLNS 0x100 /* default xml namespace = ...; parsed */ |
|
|
#define TCF_HAS_FUNCTION_STMT 0x200 /* block contains a function statement */ |
|
|
#define TCF_GENEXP_LAMBDA 0x400 /* flag lambda from generator expression */ |
|
|
#define TCF_COMPILE_N_GO 0x800 /* compiler-and-go mode of script, can |
|
|
optimize name references based on scope |
|
|
chain */ |
|
|
#define TCF_NO_SCRIPT_RVAL 0x1000 /* API caller does not want result value |
|
|
from global script */ |
|
232 |
/* |
/* |
233 |
* Flags to propagate out of the blocks. |
* Flags to propagate out of the blocks. |
234 |
*/ |
*/ |
235 |
#define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID) |
#define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID) |
236 |
|
|
237 |
/* |
/* |
238 |
* Flags to propagate from FunctionBody. |
* TreeContext flags must fit in 16 bits, and all bits are in use now. Widening |
239 |
*/ |
* requires changing JSFunctionBox.tcflags too and repacking. Alternative fix |
240 |
#define TCF_FUN_FLAGS (TCF_FUN_IS_GENERATOR | \ |
* gets rid of flags, probably starting with TCF_HAS_FUNCTION_STMT. |
241 |
TCF_FUN_HEAVYWEIGHT | \ |
*/ |
242 |
TCF_FUN_USES_NONLOCALS | \ |
#define TCF_COMPILING 0x01 /* JSTreeContext is JSCodeGenerator */ |
243 |
TCF_FUN_CLOSURE_VS_VAR) |
#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */ |
244 |
|
#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */ |
245 |
|
#define TCF_RETURN_VOID 0x08 /* function has 'return;' */ |
246 |
|
#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */ |
247 |
|
#define TCF_FUN_SETS_OUTER_NAME 0x20 /* function set outer name (lexical or free) */ |
248 |
|
#define TCF_FUN_PARAM_ARGUMENTS 0x40 /* function has parameter named arguments */ |
249 |
|
#define TCF_FUN_USES_ARGUMENTS 0x80 /* function uses arguments except as a |
250 |
|
parameter name */ |
251 |
|
#define TCF_FUN_HEAVYWEIGHT 0x100 /* function needs Call object per call */ |
252 |
|
#define TCF_FUN_IS_GENERATOR 0x200 /* parsed yield statement in function */ |
253 |
|
#define TCF_FUN_IS_FUNARG 0x400 /* function escapes as an argument, return |
254 |
|
value, or via the heap */ |
255 |
|
#define TCF_HAS_FUNCTION_STMT 0x800 /* block contains a function statement */ |
256 |
|
#define TCF_GENEXP_LAMBDA 0x1000 /* flag lambda from generator expression */ |
257 |
|
#define TCF_COMPILE_N_GO 0x2000 /* compiler-and-go mode of script, can |
258 |
|
optimize name references based on scope |
259 |
|
chain */ |
260 |
|
#define TCF_NO_SCRIPT_RVAL 0x4000 /* API caller does not want result value |
261 |
|
from global script */ |
262 |
|
#define TCF_HAS_SHARPS 0x8000 /* source contains sharp defs or uses */ |
263 |
|
|
264 |
|
/* |
265 |
|
* Sticky deoptimization flags to propagate from FunctionBody. |
266 |
|
*/ |
267 |
|
#define TCF_FUN_FLAGS (TCF_FUN_SETS_OUTER_NAME | \ |
268 |
|
TCF_FUN_USES_ARGUMENTS | \ |
269 |
|
TCF_FUN_PARAM_ARGUMENTS | \ |
270 |
|
TCF_FUN_HEAVYWEIGHT | \ |
271 |
|
TCF_FUN_IS_GENERATOR | \ |
272 |
|
TCF_FUN_IS_FUNARG | \ |
273 |
|
TCF_HAS_SHARPS) |
274 |
|
|
275 |
/* |
/* |
276 |
* Flags field, not stored in JSTreeContext.flags, for passing staticDepth |
* Flags field, not stored in JSTreeContext.flags, for passing a static level |
277 |
* into js_CompileScript. |
* into js_CompileScript. |
278 |
*/ |
*/ |
279 |
#define TCF_STATIC_DEPTH_MASK 0xffff0000 |
#define TCF_STATIC_LEVEL_MASK 0xffff0000 |
280 |
#define TCF_GET_STATIC_DEPTH(f) ((uint32)(f) >> 16) |
#define TCF_GET_STATIC_LEVEL(f) ((uint32)(f) >> 16) |
281 |
#define TCF_PUT_STATIC_DEPTH(d) ((uint16)(d) << 16) |
#define TCF_PUT_STATIC_LEVEL(d) ((uint16)(d) << 16) |
|
|
|
|
#ifdef JS_SCOPE_DEPTH_METER |
|
|
# define JS_SCOPE_DEPTH_METERING(code) ((void) (code)) |
|
|
#else |
|
|
# define JS_SCOPE_DEPTH_METERING(code) ((void) 0) |
|
|
#endif |
|
|
|
|
|
#define TREE_CONTEXT_INIT(tc, pc) \ |
|
|
((tc)->flags = (tc)->ngvars = 0, \ |
|
|
(tc)->topStmt = (tc)->topScopeStmt = NULL, \ |
|
|
(tc)->blockChain = NULL, \ |
|
|
ATOM_LIST_INIT(&(tc)->decls), \ |
|
|
(tc)->blockNode = NULL, \ |
|
|
(tc)->parseContext = (pc), \ |
|
|
(tc)->u.scopeChain = NULL, \ |
|
|
JS_SCOPE_DEPTH_METERING((tc)->scopeDepth = (tc)->maxScopeDepth = 0)) |
|
|
|
|
|
/* |
|
|
* For functions TREE_CONTEXT_FINISH is called the second time to finish the |
|
|
* extra tc created during code generation. We skip stats update in such |
|
|
* cases. |
|
|
*/ |
|
|
#define TREE_CONTEXT_FINISH(cx, tc) \ |
|
|
JS_SCOPE_DEPTH_METERING( \ |
|
|
(tc)->maxScopeDepth == (uintN) -1 || \ |
|
|
JS_BASIC_STATS_ACCUM(&(cx)->runtime->lexicalScopeDepthStats, \ |
|
|
(tc)->maxScopeDepth)) |
|
282 |
|
|
283 |
/* |
/* |
284 |
* Span-dependent instructions are jumps whose span (from the jump bytecode to |
* Span-dependent instructions are jumps whose span (from the jump bytecode to |
348 |
JSTryNode *prev; |
JSTryNode *prev; |
349 |
}; |
}; |
350 |
|
|
351 |
typedef struct JSEmittedObjectList { |
struct JSCGObjectList { |
352 |
uint32 length; /* number of emitted so far objects */ |
uint32 length; /* number of emitted so far objects */ |
353 |
JSParsedObjectBox *lastPob; /* last emitted object */ |
JSObjectBox *lastbox; /* last emitted object */ |
|
} JSEmittedObjectList; |
|
354 |
|
|
355 |
extern void |
JSCGObjectList() : length(0), lastbox(NULL) {} |
|
FinishParsedObjects(JSEmittedObjectList *emittedList, JSObjectArray *objectMap); |
|
356 |
|
|
357 |
struct JSCodeGenerator { |
uintN index(JSObjectBox *objbox); |
358 |
JSTreeContext treeContext; /* base state: statement info stack, etc. */ |
void finish(JSObjectArray *array); |
359 |
|
}; |
360 |
|
|
361 |
|
struct JSCodeGenerator : public JSTreeContext |
362 |
|
{ |
363 |
JSArenaPool *codePool; /* pointer to thread code arena pool */ |
JSArenaPool *codePool; /* pointer to thread code arena pool */ |
364 |
JSArenaPool *notePool; /* pointer to thread srcnote arena pool */ |
JSArenaPool *notePool; /* pointer to thread srcnote arena pool */ |
365 |
void *codeMark; /* low watermark in cg->codePool */ |
void *codeMark; /* low watermark in cg->codePool */ |
398 |
uintN emitLevel; /* js_EmitTree recursion level */ |
uintN emitLevel; /* js_EmitTree recursion level */ |
399 |
JSAtomList constList; /* compile time constants */ |
JSAtomList constList; /* compile time constants */ |
400 |
|
|
401 |
JSEmittedObjectList objectList; /* list of emitted so far objects */ |
JSCGObjectList objectList; /* list of emitted objects */ |
402 |
JSEmittedObjectList regexpList; /* list of emitted so far regexp |
JSCGObjectList regexpList; /* list of emitted regexp that will be |
403 |
that will be cloned during execution */ |
cloned during execution */ |
404 |
|
|
|
uintN staticDepth; /* static frame chain depth */ |
|
405 |
JSAtomList upvarList; /* map of atoms to upvar indexes */ |
JSAtomList upvarList; /* map of atoms to upvar indexes */ |
406 |
JSUpvarArray upvarMap; /* indexed upvar pairs (JS_realloc'ed) */ |
JSUpvarArray upvarMap; /* indexed upvar pairs (JS_realloc'ed) */ |
407 |
JSCodeGenerator *parent; /* enclosing function or global context */ |
|
408 |
|
/* |
409 |
|
* Initialize cg to allocate bytecode space from codePool, source note |
410 |
|
* space from notePool, and all other arena-allocated temporaries from |
411 |
|
* jsc->context->tempPool. |
412 |
|
*/ |
413 |
|
JSCodeGenerator(JSCompiler *jsc, |
414 |
|
JSArenaPool *codePool, JSArenaPool *notePool, |
415 |
|
uintN lineno); |
416 |
|
|
417 |
|
/* |
418 |
|
* Release cg->codePool, cg->notePool, and compiler->context->tempPool to |
419 |
|
* marks set by JSCodeGenerator's ctor. Note that cgs are magic: they own |
420 |
|
* the arena pool "tops-of-stack" space above their codeMark, noteMark, and |
421 |
|
* tempMark points. This means you cannot alloc from tempPool and save the |
422 |
|
* pointer beyond the next JSCodeGenerator destructor call. |
423 |
|
*/ |
424 |
|
~JSCodeGenerator(); |
425 |
}; |
}; |
426 |
|
|
427 |
#define CG_TS(cg) TS((cg)->treeContext.parseContext) |
#define CG_TS(cg) TS((cg)->compiler) |
428 |
|
|
429 |
#define CG_BASE(cg) ((cg)->current->base) |
#define CG_BASE(cg) ((cg)->current->base) |
430 |
#define CG_LIMIT(cg) ((cg)->current->limit) |
#define CG_LIMIT(cg) ((cg)->current->limit) |
449 |
#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog) |
#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog) |
450 |
|
|
451 |
/* |
/* |
|
* Initialize cg to allocate bytecode space from codePool, source note space |
|
|
* from notePool, and all other arena-allocated temporaries from cx->tempPool. |
|
|
*/ |
|
|
extern JS_FRIEND_API(void) |
|
|
js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc, |
|
|
JSArenaPool *codePool, JSArenaPool *notePool, |
|
|
uintN lineno); |
|
|
|
|
|
/* |
|
|
* Release cg->codePool, cg->notePool, and cx->tempPool to marks set by |
|
|
* js_InitCodeGenerator. Note that cgs are magic: they own the arena pool |
|
|
* "tops-of-stack" space above their codeMark, noteMark, and tempMark points. |
|
|
* This means you cannot alloc from tempPool and save the pointer beyond the |
|
|
* next JS_FinishCodeGenerator. |
|
|
*/ |
|
|
extern JS_FRIEND_API(void) |
|
|
js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg); |
|
|
|
|
|
/* |
|
452 |
* Emit one bytecode. |
* Emit one bytecode. |
453 |
*/ |
*/ |
454 |
extern ptrdiff_t |
extern ptrdiff_t |
497 |
js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, |
js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, |
498 |
ptrdiff_t off); |
ptrdiff_t off); |
499 |
|
|
|
/* Test whether we're in a statement of given type. */ |
|
|
extern JSBool |
|
|
js_InStatement(JSTreeContext *tc, JSStmtType type); |
|
|
|
|
|
/* Test whether we're in a with statement. */ |
|
|
#define js_InWithStatement(tc) js_InStatement(tc, STMT_WITH) |
|
|
|
|
500 |
/* |
/* |
501 |
* Push the C-stack-allocated struct at stmt onto the stmtInfo stack. |
* Push the C-stack-allocated struct at stmt onto the stmtInfo stack. |
502 |
*/ |
*/ |
521 |
js_PopStatement(JSTreeContext *tc); |
js_PopStatement(JSTreeContext *tc); |
522 |
|
|
523 |
/* |
/* |
524 |
* Like js_PopStatement(&cg->treeContext), also patch breaks and continues |
* Like js_PopStatement(cg), also patch breaks and continues unless the top |
525 |
* unless the top statement info record represents a try-catch-finally suite. |
* statement info record represents a try-catch-finally suite. May fail if a |
526 |
* May fail if a jump offset overflows. |
* jump offset overflows. |
527 |
*/ |
*/ |
528 |
extern JSBool |
extern JSBool |
529 |
js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg); |
js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg); |
559 |
* found. Otherwise return null. |
* found. Otherwise return null. |
560 |
*/ |
*/ |
561 |
extern JSStmtInfo * |
extern JSStmtInfo * |
562 |
js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp); |
js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, |
563 |
|
JSStmtInfo *stmt = NULL); |
564 |
|
|
565 |
/* |
/* |
566 |
* Emit code into cg for the tree rooted at pn. |
* Emit code into cg for the tree rooted at pn. |
611 |
SRC_INITPROP = 1, /* disjoint meaning applied to JSOP_INITELEM or |
SRC_INITPROP = 1, /* disjoint meaning applied to JSOP_INITELEM or |
612 |
to an index label in a regular (structuring) |
to an index label in a regular (structuring) |
613 |
or a destructuring object initialiser */ |
or a destructuring object initialiser */ |
614 |
SRC_GENEXP = 1, /* JSOP_ANONFUNOBJ from generator expression */ |
SRC_GENEXP = 1, /* JSOP_LAMBDA from generator expression */ |
615 |
SRC_IF_ELSE = 2, /* JSOP_IFEQ bytecode is from an if-then-else */ |
SRC_IF_ELSE = 2, /* JSOP_IFEQ bytecode is from an if-then-else */ |
616 |
SRC_FOR_IN = 2, /* JSOP_GOTO to for-in loop condition from |
SRC_FOR_IN = 2, /* JSOP_GOTO to for-in loop condition from |
617 |
before loop (same arity as SRC_IF_ELSE) */ |
before loop (same arity as SRC_IF_ELSE) */ |
621 |
do-while loop */ |
do-while loop */ |
622 |
SRC_CONTINUE = 5, /* JSOP_GOTO is a continue, not a break; |
SRC_CONTINUE = 5, /* JSOP_GOTO is a continue, not a break; |
623 |
also used on JSOP_ENDINIT if extra comma |
also used on JSOP_ENDINIT if extra comma |
624 |
at end of array literal: [1,2,,] */ |
at end of array literal: [1,2,,]; |
625 |
|
JSOP_DUP continuing destructuring pattern */ |
626 |
SRC_DECL = 6, /* type of a declaration (var, const, let*) */ |
SRC_DECL = 6, /* type of a declaration (var, const, let*) */ |
627 |
SRC_DESTRUCT = 6, /* JSOP_DUP starting a destructuring assignment |
SRC_DESTRUCT = 6, /* JSOP_DUP starting a destructuring assignment |
628 |
operation, with SRC_DECL_* offset operand */ |
operation, with SRC_DECL_* offset operand */ |