1 |
siliconforks |
332 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
|
|
* vim: set ts=8 sw=4 et tw=79: |
3 |
|
|
* |
4 |
|
|
* ***** BEGIN LICENSE BLOCK ***** |
5 |
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
6 |
|
|
* |
7 |
|
|
* The contents of this file are subject to the Mozilla Public License Version |
8 |
|
|
* 1.1 (the "License"); you may not use this file except in compliance with |
9 |
|
|
* the License. You may obtain a copy of the License at |
10 |
|
|
* http://www.mozilla.org/MPL/ |
11 |
|
|
* |
12 |
|
|
* Software distributed under the License is distributed on an "AS IS" basis, |
13 |
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
14 |
|
|
* for the specific language governing rights and limitations under the |
15 |
|
|
* License. |
16 |
|
|
* |
17 |
|
|
* The Original Code is Mozilla Communicator client code, released |
18 |
|
|
* March 31, 1998. |
19 |
|
|
* |
20 |
|
|
* The Initial Developer of the Original Code is |
21 |
|
|
* Netscape Communications Corporation. |
22 |
|
|
* Portions created by the Initial Developer are Copyright (C) 1998 |
23 |
|
|
* the Initial Developer. All Rights Reserved. |
24 |
|
|
* |
25 |
|
|
* Contributor(s): |
26 |
|
|
* |
27 |
|
|
* Alternatively, the contents of this file may be used under the terms of |
28 |
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"), |
29 |
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
30 |
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead |
31 |
|
|
* of those above. If you wish to allow use of your version of this file only |
32 |
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to |
33 |
|
|
* use your version of this file under the terms of the MPL, indicate your |
34 |
|
|
* decision by deleting the provisions above and replace them with the notice |
35 |
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete |
36 |
|
|
* the provisions above, a recipient may use your version of this file under |
37 |
|
|
* the terms of any one of the MPL, the GPL or the LGPL. |
38 |
|
|
* |
39 |
|
|
* ***** END LICENSE BLOCK ***** */ |
40 |
|
|
|
41 |
|
|
#ifndef jsemit_h___ |
42 |
|
|
#define jsemit_h___ |
43 |
|
|
/* |
44 |
|
|
* JS bytecode generation. |
45 |
|
|
*/ |
46 |
|
|
|
47 |
|
|
#include "jsstddef.h" |
48 |
|
|
#include "jstypes.h" |
49 |
|
|
#include "jsatom.h" |
50 |
|
|
#include "jsopcode.h" |
51 |
siliconforks |
460 |
#include "jsparse.h" |
52 |
siliconforks |
332 |
#include "jsscript.h" |
53 |
|
|
#include "jsprvtd.h" |
54 |
|
|
#include "jspubtd.h" |
55 |
|
|
|
56 |
|
|
JS_BEGIN_EXTERN_C |
57 |
|
|
|
58 |
|
|
/* |
59 |
|
|
* NB: If you add enumerators for scope statements, add them between STMT_WITH |
60 |
|
|
* and STMT_CATCH, or you will break the STMT_TYPE_IS_SCOPE macro. If you add |
61 |
|
|
* non-looping statement enumerators, add them before STMT_DO_LOOP or you will |
62 |
|
|
* break the STMT_TYPE_IS_LOOP macro. |
63 |
|
|
* |
64 |
|
|
* Also remember to keep the statementName array in jsemit.c in sync. |
65 |
|
|
*/ |
66 |
|
|
typedef enum JSStmtType { |
67 |
|
|
STMT_LABEL, /* labeled statement: L: s */ |
68 |
|
|
STMT_IF, /* if (then) statement */ |
69 |
|
|
STMT_ELSE, /* else clause of if statement */ |
70 |
siliconforks |
399 |
STMT_SEQ, /* synthetic sequence of statements */ |
71 |
siliconforks |
332 |
STMT_BLOCK, /* compound statement: { s1[;... sN] } */ |
72 |
|
|
STMT_SWITCH, /* switch statement */ |
73 |
|
|
STMT_WITH, /* with statement */ |
74 |
|
|
STMT_CATCH, /* catch block */ |
75 |
|
|
STMT_TRY, /* try block */ |
76 |
|
|
STMT_FINALLY, /* finally block */ |
77 |
|
|
STMT_SUBROUTINE, /* gosub-target subroutine body */ |
78 |
|
|
STMT_DO_LOOP, /* do/while loop statement */ |
79 |
|
|
STMT_FOR_LOOP, /* for loop statement */ |
80 |
|
|
STMT_FOR_IN_LOOP, /* for/in loop statement */ |
81 |
|
|
STMT_WHILE_LOOP, /* while loop statement */ |
82 |
|
|
STMT_LIMIT |
83 |
|
|
} JSStmtType; |
84 |
|
|
|
85 |
|
|
#define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b))) |
86 |
|
|
|
87 |
|
|
/* |
88 |
|
|
* A comment on the encoding of the JSStmtType enum and type-testing macros: |
89 |
|
|
* |
90 |
|
|
* STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may |
91 |
|
|
* become, a lexical scope. It therefore includes block and switch (the two |
92 |
|
|
* low-numbered "maybe" scope types) and excludes with (with has dynamic scope |
93 |
|
|
* pending the "reformed with" in ES4/JS2). It includes all try-catch-finally |
94 |
|
|
* types, which are high-numbered maybe-scope types. |
95 |
|
|
* |
96 |
|
|
* STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly |
97 |
|
|
* links to other scoping statement info records. It excludes the two early |
98 |
|
|
* "maybe" types, block and switch, as well as the try and both finally types, |
99 |
|
|
* since try and the other trailing maybe-scope types don't need block scope |
100 |
|
|
* unless they contain let declarations. |
101 |
|
|
* |
102 |
|
|
* We treat WITH as a static scope because it prevents lexical binding from |
103 |
|
|
* continuing further up the static scope chain. With the lost "reformed with" |
104 |
|
|
* proposal for ES4, we would be able to model it statically, too. |
105 |
|
|
*/ |
106 |
|
|
#define STMT_TYPE_MAYBE_SCOPE(type) \ |
107 |
|
|
(type != STMT_WITH && \ |
108 |
|
|
STMT_TYPE_IN_RANGE(type, STMT_BLOCK, STMT_SUBROUTINE)) |
109 |
|
|
|
110 |
|
|
#define STMT_TYPE_LINKS_SCOPE(type) \ |
111 |
|
|
STMT_TYPE_IN_RANGE(type, STMT_WITH, STMT_CATCH) |
112 |
|
|
|
113 |
|
|
#define STMT_TYPE_IS_TRYING(type) \ |
114 |
|
|
STMT_TYPE_IN_RANGE(type, STMT_TRY, STMT_SUBROUTINE) |
115 |
|
|
|
116 |
|
|
#define STMT_TYPE_IS_LOOP(type) ((type) >= STMT_DO_LOOP) |
117 |
|
|
|
118 |
|
|
#define STMT_MAYBE_SCOPE(stmt) STMT_TYPE_MAYBE_SCOPE((stmt)->type) |
119 |
|
|
#define STMT_LINKS_SCOPE(stmt) (STMT_TYPE_LINKS_SCOPE((stmt)->type) || \ |
120 |
|
|
((stmt)->flags & SIF_SCOPE)) |
121 |
|
|
#define STMT_IS_TRYING(stmt) STMT_TYPE_IS_TRYING((stmt)->type) |
122 |
|
|
#define STMT_IS_LOOP(stmt) STMT_TYPE_IS_LOOP((stmt)->type) |
123 |
|
|
|
124 |
|
|
typedef struct JSStmtInfo JSStmtInfo; |
125 |
|
|
|
126 |
|
|
struct JSStmtInfo { |
127 |
|
|
uint16 type; /* statement type */ |
128 |
|
|
uint16 flags; /* flags, see below */ |
129 |
siliconforks |
460 |
uint32 blockid; /* for simplified dominance computation */ |
130 |
siliconforks |
332 |
ptrdiff_t update; /* loop update offset (top if none) */ |
131 |
|
|
ptrdiff_t breaks; /* offset of last break in loop */ |
132 |
|
|
ptrdiff_t continues; /* offset of last continue in loop */ |
133 |
|
|
union { |
134 |
|
|
JSAtom *label; /* name of LABEL */ |
135 |
|
|
JSObject *blockObj; /* block scope object */ |
136 |
siliconforks |
460 |
}; |
137 |
siliconforks |
332 |
JSStmtInfo *down; /* info for enclosing statement */ |
138 |
|
|
JSStmtInfo *downScope; /* next enclosing lexical scope */ |
139 |
|
|
}; |
140 |
|
|
|
141 |
|
|
#define SIF_SCOPE 0x0001 /* statement has its own lexical scope */ |
142 |
|
|
#define SIF_BODY_BLOCK 0x0002 /* STMT_BLOCK type is a function body */ |
143 |
|
|
#define SIF_FOR_BLOCK 0x0004 /* for (let ...) induced block scope */ |
144 |
|
|
|
145 |
|
|
/* |
146 |
|
|
* To reuse space in JSStmtInfo, rename breaks and continues for use during |
147 |
|
|
* try/catch/finally code generation and backpatching. To match most common |
148 |
|
|
* use cases, the macro argument is a struct, not a struct pointer. Only a |
149 |
|
|
* loop, switch, or label statement info record can have breaks and continues, |
150 |
|
|
* and only a for loop has an update backpatch chain, so it's safe to overlay |
151 |
|
|
* these for the "trying" JSStmtTypes. |
152 |
|
|
*/ |
153 |
|
|
#define CATCHNOTE(stmt) ((stmt).update) |
154 |
|
|
#define GOSUBS(stmt) ((stmt).breaks) |
155 |
|
|
#define GUARDJUMP(stmt) ((stmt).continues) |
156 |
|
|
|
157 |
|
|
#define SET_STATEMENT_TOP(stmt, top) \ |
158 |
|
|
((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1)) |
159 |
|
|
|
160 |
siliconforks |
460 |
#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 |
siliconforks |
332 |
struct JSTreeContext { /* tree context for semantic checks */ |
167 |
|
|
uint16 flags; /* statement state flags, see below */ |
168 |
|
|
uint16 ngvars; /* max. no. of global variables/regexps */ |
169 |
siliconforks |
460 |
uint32 bodyid; /* block number of program/function body */ |
170 |
|
|
uint32 blockidGen; /* preincremented block number generator */ |
171 |
siliconforks |
332 |
JSStmtInfo *topStmt; /* top of statement info stack */ |
172 |
|
|
JSStmtInfo *topScopeStmt; /* top lexical scope statement */ |
173 |
|
|
JSObject *blockChain; /* compile time block scope chain (NB: one |
174 |
|
|
deeper than the topScopeStmt/downScope |
175 |
|
|
chain when in head of let block/expr) */ |
176 |
siliconforks |
460 |
JSParseNode *blockNode; /* parse node for a block with let declarations |
177 |
|
|
(block with its own lexical scope) */ |
178 |
siliconforks |
332 |
JSAtomList decls; /* function, const, and var declarations */ |
179 |
siliconforks |
460 |
JSCompiler *compiler; /* ptr to common parsing and lexing data */ |
180 |
siliconforks |
332 |
|
181 |
|
|
union { |
182 |
|
|
JSFunction *fun; /* function to store argument and variable |
183 |
|
|
names when flags & TCF_IN_FUNCTION */ |
184 |
|
|
JSObject *scopeChain; /* scope chain object for the script */ |
185 |
siliconforks |
460 |
}; |
186 |
siliconforks |
332 |
|
187 |
siliconforks |
460 |
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 |
siliconforks |
332 |
#ifdef JS_SCOPE_DEPTH_METER |
197 |
|
|
uint16 scopeDepth; /* current lexical scope chain depth */ |
198 |
|
|
uint16 maxScopeDepth; /* maximum lexical scope chain depth */ |
199 |
|
|
#endif |
200 |
siliconforks |
460 |
|
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 |
siliconforks |
332 |
}; |
231 |
|
|
|
232 |
|
|
/* |
233 |
|
|
* Flags to propagate out of the blocks. |
234 |
|
|
*/ |
235 |
|
|
#define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID) |
236 |
|
|
|
237 |
|
|
/* |
238 |
siliconforks |
460 |
* 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 |
|
|
* gets rid of flags, probably starting with TCF_HAS_FUNCTION_STMT. |
241 |
siliconforks |
332 |
*/ |
242 |
siliconforks |
460 |
#define TCF_COMPILING 0x01 /* JSTreeContext is JSCodeGenerator */ |
243 |
|
|
#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 |
siliconforks |
332 |
|
264 |
|
|
/* |
265 |
siliconforks |
460 |
* Sticky deoptimization flags to propagate from FunctionBody. |
266 |
siliconforks |
332 |
*/ |
267 |
siliconforks |
460 |
#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 |
siliconforks |
332 |
|
275 |
|
|
/* |
276 |
siliconforks |
460 |
* Flags field, not stored in JSTreeContext.flags, for passing a static level |
277 |
|
|
* into js_CompileScript. |
278 |
siliconforks |
332 |
*/ |
279 |
siliconforks |
460 |
#define TCF_STATIC_LEVEL_MASK 0xffff0000 |
280 |
|
|
#define TCF_GET_STATIC_LEVEL(f) ((uint32)(f) >> 16) |
281 |
|
|
#define TCF_PUT_STATIC_LEVEL(d) ((uint16)(d) << 16) |
282 |
siliconforks |
332 |
|
283 |
|
|
/* |
284 |
|
|
* Span-dependent instructions are jumps whose span (from the jump bytecode to |
285 |
|
|
* the jump target) may require 2 or 4 bytes of immediate operand. |
286 |
|
|
*/ |
287 |
|
|
typedef struct JSSpanDep JSSpanDep; |
288 |
|
|
typedef struct JSJumpTarget JSJumpTarget; |
289 |
|
|
|
290 |
|
|
struct JSSpanDep { |
291 |
|
|
ptrdiff_t top; /* offset of first bytecode in an opcode */ |
292 |
|
|
ptrdiff_t offset; /* offset - 1 within opcode of jump operand */ |
293 |
|
|
ptrdiff_t before; /* original offset - 1 of jump operand */ |
294 |
|
|
JSJumpTarget *target; /* tagged target pointer or backpatch delta */ |
295 |
|
|
}; |
296 |
|
|
|
297 |
|
|
/* |
298 |
|
|
* Jump targets are stored in an AVL tree, for O(log(n)) lookup with targets |
299 |
|
|
* sorted by offset from left to right, so that targets after a span-dependent |
300 |
|
|
* instruction whose jump offset operand must be extended can be found quickly |
301 |
|
|
* and adjusted upward (toward higher offsets). |
302 |
|
|
*/ |
303 |
|
|
struct JSJumpTarget { |
304 |
|
|
ptrdiff_t offset; /* offset of span-dependent jump target */ |
305 |
|
|
int balance; /* AVL tree balance number */ |
306 |
|
|
JSJumpTarget *kids[2]; /* left and right AVL tree child pointers */ |
307 |
|
|
}; |
308 |
|
|
|
309 |
|
|
#define JT_LEFT 0 |
310 |
|
|
#define JT_RIGHT 1 |
311 |
|
|
#define JT_OTHER_DIR(dir) (1 - (dir)) |
312 |
|
|
#define JT_IMBALANCE(dir) (((dir) << 1) - 1) |
313 |
|
|
#define JT_DIR(imbalance) (((imbalance) + 1) >> 1) |
314 |
|
|
|
315 |
|
|
/* |
316 |
|
|
* Backpatch deltas are encoded in JSSpanDep.target if JT_TAG_BIT is clear, |
317 |
|
|
* so we can maintain backpatch chains when using span dependency records to |
318 |
|
|
* hold jump offsets that overflow 16 bits. |
319 |
|
|
*/ |
320 |
|
|
#define JT_TAG_BIT ((jsword) 1) |
321 |
|
|
#define JT_UNTAG_SHIFT 1 |
322 |
|
|
#define JT_SET_TAG(jt) ((JSJumpTarget *)((jsword)(jt) | JT_TAG_BIT)) |
323 |
|
|
#define JT_CLR_TAG(jt) ((JSJumpTarget *)((jsword)(jt) & ~JT_TAG_BIT)) |
324 |
|
|
#define JT_HAS_TAG(jt) ((jsword)(jt) & JT_TAG_BIT) |
325 |
|
|
|
326 |
|
|
#define BITS_PER_PTRDIFF (sizeof(ptrdiff_t) * JS_BITS_PER_BYTE) |
327 |
|
|
#define BITS_PER_BPDELTA (BITS_PER_PTRDIFF - 1 - JT_UNTAG_SHIFT) |
328 |
|
|
#define BPDELTA_MAX (((ptrdiff_t)1 << BITS_PER_BPDELTA) - 1) |
329 |
|
|
#define BPDELTA_TO_JT(bp) ((JSJumpTarget *)((bp) << JT_UNTAG_SHIFT)) |
330 |
|
|
#define JT_TO_BPDELTA(jt) ((ptrdiff_t)((jsword)(jt) >> JT_UNTAG_SHIFT)) |
331 |
|
|
|
332 |
|
|
#define SD_SET_TARGET(sd,jt) ((sd)->target = JT_SET_TAG(jt)) |
333 |
|
|
#define SD_GET_TARGET(sd) (JS_ASSERT(JT_HAS_TAG((sd)->target)), \ |
334 |
|
|
JT_CLR_TAG((sd)->target)) |
335 |
|
|
#define SD_SET_BPDELTA(sd,bp) ((sd)->target = BPDELTA_TO_JT(bp)) |
336 |
|
|
#define SD_GET_BPDELTA(sd) (JS_ASSERT(!JT_HAS_TAG((sd)->target)), \ |
337 |
|
|
JT_TO_BPDELTA((sd)->target)) |
338 |
|
|
|
339 |
|
|
/* Avoid asserting twice by expanding SD_GET_TARGET in the "then" clause. */ |
340 |
|
|
#define SD_SPAN(sd,pivot) (SD_GET_TARGET(sd) \ |
341 |
|
|
? JT_CLR_TAG((sd)->target)->offset - (pivot) \ |
342 |
|
|
: 0) |
343 |
|
|
|
344 |
|
|
typedef struct JSTryNode JSTryNode; |
345 |
|
|
|
346 |
|
|
struct JSTryNode { |
347 |
|
|
JSTryNote note; |
348 |
|
|
JSTryNode *prev; |
349 |
|
|
}; |
350 |
|
|
|
351 |
siliconforks |
460 |
struct JSCGObjectList { |
352 |
siliconforks |
332 |
uint32 length; /* number of emitted so far objects */ |
353 |
siliconforks |
460 |
JSObjectBox *lastbox; /* last emitted object */ |
354 |
siliconforks |
332 |
|
355 |
siliconforks |
460 |
JSCGObjectList() : length(0), lastbox(NULL) {} |
356 |
siliconforks |
332 |
|
357 |
siliconforks |
460 |
uintN index(JSObjectBox *objbox); |
358 |
|
|
void finish(JSObjectArray *array); |
359 |
|
|
}; |
360 |
siliconforks |
332 |
|
361 |
siliconforks |
460 |
struct JSCodeGenerator : public JSTreeContext |
362 |
|
|
{ |
363 |
siliconforks |
332 |
JSArenaPool *codePool; /* pointer to thread code arena pool */ |
364 |
|
|
JSArenaPool *notePool; /* pointer to thread srcnote arena pool */ |
365 |
|
|
void *codeMark; /* low watermark in cg->codePool */ |
366 |
|
|
void *noteMark; /* low watermark in cg->notePool */ |
367 |
|
|
|
368 |
|
|
struct { |
369 |
|
|
jsbytecode *base; /* base of JS bytecode vector */ |
370 |
|
|
jsbytecode *limit; /* one byte beyond end of bytecode */ |
371 |
|
|
jsbytecode *next; /* pointer to next free bytecode */ |
372 |
|
|
jssrcnote *notes; /* source notes, see below */ |
373 |
|
|
uintN noteCount; /* number of source notes so far */ |
374 |
|
|
uintN noteMask; /* growth increment for notes */ |
375 |
|
|
ptrdiff_t lastNoteOffset; /* code offset for last source note */ |
376 |
|
|
uintN currentLine; /* line number for tree-based srcnote gen */ |
377 |
|
|
} prolog, main, *current; |
378 |
|
|
|
379 |
|
|
JSAtomList atomList; /* literals indexed for mapping */ |
380 |
|
|
uintN firstLine; /* first line, for js_NewScriptFromCG */ |
381 |
|
|
|
382 |
|
|
intN stackDepth; /* current stack depth in script frame */ |
383 |
|
|
uintN maxStackDepth; /* maximum stack depth so far */ |
384 |
|
|
|
385 |
|
|
uintN ntrynotes; /* number of allocated so far try notes */ |
386 |
|
|
JSTryNode *lastTryNode; /* the last allocated try node */ |
387 |
|
|
|
388 |
|
|
JSSpanDep *spanDeps; /* span dependent instruction records */ |
389 |
|
|
JSJumpTarget *jumpTargets; /* AVL tree of jump target offsets */ |
390 |
|
|
JSJumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */ |
391 |
|
|
uintN numSpanDeps; /* number of span dependencies */ |
392 |
|
|
uintN numJumpTargets; /* number of jump targets */ |
393 |
|
|
ptrdiff_t spanDepTodo; /* offset from main.base of potentially |
394 |
|
|
unoptimized spandeps */ |
395 |
|
|
|
396 |
|
|
uintN arrayCompDepth; /* stack depth of array in comprehension */ |
397 |
|
|
|
398 |
|
|
uintN emitLevel; /* js_EmitTree recursion level */ |
399 |
|
|
JSAtomList constList; /* compile time constants */ |
400 |
|
|
|
401 |
siliconforks |
460 |
JSCGObjectList objectList; /* list of emitted objects */ |
402 |
|
|
JSCGObjectList regexpList; /* list of emitted regexp that will be |
403 |
|
|
cloned during execution */ |
404 |
siliconforks |
332 |
|
405 |
|
|
JSAtomList upvarList; /* map of atoms to upvar indexes */ |
406 |
|
|
JSUpvarArray upvarMap; /* indexed upvar pairs (JS_realloc'ed) */ |
407 |
siliconforks |
460 |
|
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 |
siliconforks |
332 |
}; |
426 |
|
|
|
427 |
siliconforks |
460 |
#define CG_TS(cg) TS((cg)->compiler) |
428 |
siliconforks |
332 |
|
429 |
|
|
#define CG_BASE(cg) ((cg)->current->base) |
430 |
|
|
#define CG_LIMIT(cg) ((cg)->current->limit) |
431 |
|
|
#define CG_NEXT(cg) ((cg)->current->next) |
432 |
|
|
#define CG_CODE(cg,offset) (CG_BASE(cg) + (offset)) |
433 |
|
|
#define CG_OFFSET(cg) PTRDIFF(CG_NEXT(cg), CG_BASE(cg), jsbytecode) |
434 |
|
|
|
435 |
|
|
#define CG_NOTES(cg) ((cg)->current->notes) |
436 |
|
|
#define CG_NOTE_COUNT(cg) ((cg)->current->noteCount) |
437 |
|
|
#define CG_NOTE_MASK(cg) ((cg)->current->noteMask) |
438 |
|
|
#define CG_LAST_NOTE_OFFSET(cg) ((cg)->current->lastNoteOffset) |
439 |
|
|
#define CG_CURRENT_LINE(cg) ((cg)->current->currentLine) |
440 |
|
|
|
441 |
|
|
#define CG_PROLOG_BASE(cg) ((cg)->prolog.base) |
442 |
|
|
#define CG_PROLOG_LIMIT(cg) ((cg)->prolog.limit) |
443 |
|
|
#define CG_PROLOG_NEXT(cg) ((cg)->prolog.next) |
444 |
|
|
#define CG_PROLOG_CODE(cg,poff) (CG_PROLOG_BASE(cg) + (poff)) |
445 |
|
|
#define CG_PROLOG_OFFSET(cg) PTRDIFF(CG_PROLOG_NEXT(cg), CG_PROLOG_BASE(cg),\ |
446 |
|
|
jsbytecode) |
447 |
|
|
|
448 |
|
|
#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main) |
449 |
|
|
#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog) |
450 |
|
|
|
451 |
|
|
/* |
452 |
|
|
* Emit one bytecode. |
453 |
|
|
*/ |
454 |
|
|
extern ptrdiff_t |
455 |
|
|
js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op); |
456 |
|
|
|
457 |
|
|
/* |
458 |
|
|
* Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1). |
459 |
|
|
*/ |
460 |
|
|
extern ptrdiff_t |
461 |
|
|
js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1); |
462 |
|
|
|
463 |
|
|
/* |
464 |
|
|
* Emit three bytecodes, an opcode with two bytes of immediate operands. |
465 |
|
|
*/ |
466 |
|
|
extern ptrdiff_t |
467 |
|
|
js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, |
468 |
|
|
jsbytecode op2); |
469 |
|
|
|
470 |
|
|
/* |
471 |
|
|
* Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand. |
472 |
|
|
*/ |
473 |
|
|
extern ptrdiff_t |
474 |
|
|
js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra); |
475 |
|
|
|
476 |
|
|
/* |
477 |
|
|
* Unsafe macro to call js_SetJumpOffset and return false if it does. |
478 |
|
|
*/ |
479 |
|
|
#define CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,BAD_EXIT) \ |
480 |
|
|
JS_BEGIN_MACRO \ |
481 |
|
|
if (!js_SetJumpOffset(cx, cg, pc, off)) { \ |
482 |
|
|
BAD_EXIT; \ |
483 |
|
|
} \ |
484 |
|
|
JS_END_MACRO |
485 |
|
|
|
486 |
|
|
#define CHECK_AND_SET_JUMP_OFFSET(cx,cg,pc,off) \ |
487 |
|
|
CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,return JS_FALSE) |
488 |
|
|
|
489 |
|
|
#define CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx,cg,off,BAD_EXIT) \ |
490 |
|
|
CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx, cg, CG_CODE(cg,off), \ |
491 |
|
|
CG_OFFSET(cg) - (off), BAD_EXIT) |
492 |
|
|
|
493 |
|
|
#define CHECK_AND_SET_JUMP_OFFSET_AT(cx,cg,off) \ |
494 |
|
|
CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, off, return JS_FALSE) |
495 |
|
|
|
496 |
|
|
extern JSBool |
497 |
|
|
js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, |
498 |
|
|
ptrdiff_t off); |
499 |
|
|
|
500 |
|
|
/* |
501 |
|
|
* Push the C-stack-allocated struct at stmt onto the stmtInfo stack. |
502 |
|
|
*/ |
503 |
|
|
extern void |
504 |
|
|
js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, |
505 |
|
|
ptrdiff_t top); |
506 |
|
|
|
507 |
|
|
/* |
508 |
|
|
* Push a block scope statement and link blockObj into tc->blockChain. To pop |
509 |
|
|
* this statement info record, use js_PopStatement as usual, or if appropriate |
510 |
|
|
* (if generating code), js_PopStatementCG. |
511 |
|
|
*/ |
512 |
|
|
extern void |
513 |
|
|
js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj, |
514 |
|
|
ptrdiff_t top); |
515 |
|
|
|
516 |
|
|
/* |
517 |
|
|
* Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it |
518 |
|
|
* is up to the caller to free it. |
519 |
|
|
*/ |
520 |
|
|
extern void |
521 |
|
|
js_PopStatement(JSTreeContext *tc); |
522 |
|
|
|
523 |
|
|
/* |
524 |
siliconforks |
460 |
* Like js_PopStatement(cg), also patch breaks and continues unless the top |
525 |
|
|
* statement info record represents a try-catch-finally suite. May fail if a |
526 |
|
|
* jump offset overflows. |
527 |
siliconforks |
332 |
*/ |
528 |
|
|
extern JSBool |
529 |
|
|
js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg); |
530 |
|
|
|
531 |
|
|
/* |
532 |
|
|
* Define and lookup a primitive jsval associated with the const named by atom. |
533 |
|
|
* js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn |
534 |
|
|
* and saves the const's value in cg->constList, if it can be used at compile |
535 |
|
|
* time. It returns true unless an error occurred. |
536 |
|
|
* |
537 |
|
|
* If the initializer's value could not be saved, js_DefineCompileTimeConstant |
538 |
|
|
* calls will return the undefined value. js_DefineCompileTimeConstant tries |
539 |
|
|
* to find a const value memorized for atom, returning true with *vp set to a |
540 |
|
|
* value other than undefined if the constant was found, true with *vp set to |
541 |
|
|
* JSVAL_VOID if not found, and false on error. |
542 |
|
|
*/ |
543 |
|
|
extern JSBool |
544 |
|
|
js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, |
545 |
|
|
JSParseNode *pn); |
546 |
|
|
|
547 |
|
|
/* |
548 |
|
|
* Find a lexically scoped variable (one declared by let, catch, or an array |
549 |
|
|
* comprehension) named by atom, looking in tc's compile-time scopes. |
550 |
|
|
* |
551 |
|
|
* If a WITH statement is reached along the scope stack, return its statement |
552 |
|
|
* info record, so callers can tell that atom is ambiguous. If slotp is not |
553 |
|
|
* null, then if atom is found, set *slotp to its stack slot, otherwise to -1. |
554 |
|
|
* This means that if slotp is not null, all the block objects on the lexical |
555 |
|
|
* scope chain must have had their depth slots computed by the code generator, |
556 |
|
|
* so the caller must be under js_EmitTree. |
557 |
|
|
* |
558 |
|
|
* In any event, directly return the statement info record in which atom was |
559 |
|
|
* found. Otherwise return null. |
560 |
|
|
*/ |
561 |
|
|
extern JSStmtInfo * |
562 |
siliconforks |
460 |
js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, |
563 |
|
|
JSStmtInfo *stmt = NULL); |
564 |
siliconforks |
332 |
|
565 |
|
|
/* |
566 |
|
|
* Emit code into cg for the tree rooted at pn. |
567 |
|
|
*/ |
568 |
|
|
extern JSBool |
569 |
|
|
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn); |
570 |
|
|
|
571 |
|
|
/* |
572 |
|
|
* Emit function code using cg for the tree rooted at body. |
573 |
|
|
*/ |
574 |
|
|
extern JSBool |
575 |
|
|
js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body); |
576 |
|
|
|
577 |
|
|
/* |
578 |
|
|
* Source notes generated along with bytecode for decompiling and debugging. |
579 |
|
|
* A source note is a uint8 with 5 bits of type and 3 of offset from the pc of |
580 |
|
|
* the previous note. If 3 bits of offset aren't enough, extended delta notes |
581 |
|
|
* (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits |
582 |
|
|
* are emitted before the next note. Some notes have operand offsets encoded |
583 |
|
|
* immediately after them, in note bytes or byte-triples. |
584 |
|
|
* |
585 |
|
|
* Source Note Extended Delta |
586 |
|
|
* +7-6-5-4-3+2-1-0+ +7-6-5+4-3-2-1-0+ |
587 |
|
|
* |note-type|delta| |1 1| ext-delta | |
588 |
|
|
* +---------+-----+ +---+-----------+ |
589 |
|
|
* |
590 |
|
|
* At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE, |
591 |
|
|
* SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode. |
592 |
|
|
* |
593 |
|
|
* NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its |
594 |
|
|
* initializers need to match the order here. |
595 |
|
|
* |
596 |
|
|
* Note on adding new source notes: every pair of bytecodes (A, B) where A and |
597 |
|
|
* B have disjoint sets of source notes that could apply to each bytecode may |
598 |
|
|
* reuse the same note type value for two notes (snA, snB) that have the same |
599 |
|
|
* arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is |
600 |
|
|
* why SRC_IF and SRC_INITPROP have the same value below. For bad historical |
601 |
|
|
* reasons, some bytecodes below that could be overlayed have not been, but |
602 |
|
|
* before using SRC_EXTENDED, consider compressing the existing note types. |
603 |
|
|
* |
604 |
|
|
* Don't forget to update JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such |
605 |
|
|
* incompatible source note or other bytecode changes. |
606 |
|
|
*/ |
607 |
|
|
typedef enum JSSrcNoteType { |
608 |
|
|
SRC_NULL = 0, /* terminates a note vector */ |
609 |
|
|
SRC_IF = 1, /* JSOP_IFEQ bytecode is from an if-then */ |
610 |
|
|
SRC_BREAK = 1, /* JSOP_GOTO is a break */ |
611 |
|
|
SRC_INITPROP = 1, /* disjoint meaning applied to JSOP_INITELEM or |
612 |
|
|
to an index label in a regular (structuring) |
613 |
|
|
or a destructuring object initialiser */ |
614 |
siliconforks |
460 |
SRC_GENEXP = 1, /* JSOP_LAMBDA from generator expression */ |
615 |
siliconforks |
332 |
SRC_IF_ELSE = 2, /* JSOP_IFEQ bytecode is from an if-then-else */ |
616 |
siliconforks |
399 |
SRC_FOR_IN = 2, /* JSOP_GOTO to for-in loop condition from |
617 |
|
|
before loop (same arity as SRC_IF_ELSE) */ |
618 |
|
|
SRC_FOR = 3, /* JSOP_NOP or JSOP_POP in for(;;) loop head */ |
619 |
|
|
SRC_WHILE = 4, /* JSOP_GOTO to for or while loop condition |
620 |
|
|
from before loop, else JSOP_NOP at top of |
621 |
|
|
do-while loop */ |
622 |
siliconforks |
332 |
SRC_CONTINUE = 5, /* JSOP_GOTO is a continue, not a break; |
623 |
|
|
also used on JSOP_ENDINIT if extra comma |
624 |
siliconforks |
460 |
at end of array literal: [1,2,,]; |
625 |
|
|
JSOP_DUP continuing destructuring pattern */ |
626 |
siliconforks |
332 |
SRC_DECL = 6, /* type of a declaration (var, const, let*) */ |
627 |
|
|
SRC_DESTRUCT = 6, /* JSOP_DUP starting a destructuring assignment |
628 |
|
|
operation, with SRC_DECL_* offset operand */ |
629 |
|
|
SRC_PCDELTA = 7, /* distance forward from comma-operator to |
630 |
|
|
next POP, or from CONDSWITCH to first CASE |
631 |
|
|
opcode, etc. -- always a forward delta */ |
632 |
|
|
SRC_GROUPASSIGN = 7, /* SRC_DESTRUCT variant for [a, b] = [c, d] */ |
633 |
|
|
SRC_ASSIGNOP = 8, /* += or another assign-op follows */ |
634 |
|
|
SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */ |
635 |
|
|
SRC_BRACE = 10, /* mandatory brace, for scope or to avoid |
636 |
|
|
dangling else */ |
637 |
|
|
SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */ |
638 |
|
|
SRC_PCBASE = 12, /* distance back from annotated getprop or |
639 |
|
|
setprop op to left-most obj.prop.subprop |
640 |
|
|
bytecode -- always a backward delta */ |
641 |
|
|
SRC_LABEL = 13, /* JSOP_NOP for label: with atomid immediate */ |
642 |
|
|
SRC_LABELBRACE = 14, /* JSOP_NOP for label: {...} begin brace */ |
643 |
|
|
SRC_ENDBRACE = 15, /* JSOP_NOP for label: {...} end brace */ |
644 |
|
|
SRC_BREAK2LABEL = 16, /* JSOP_GOTO for 'break label' with atomid */ |
645 |
|
|
SRC_CONT2LABEL = 17, /* JSOP_GOTO for 'continue label' with atomid */ |
646 |
|
|
SRC_SWITCH = 18, /* JSOP_*SWITCH with offset to end of switch, |
647 |
|
|
2nd off to first JSOP_CASE if condswitch */ |
648 |
|
|
SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */ |
649 |
|
|
SRC_CATCH = 20, /* catch block has guard */ |
650 |
|
|
SRC_EXTENDED = 21, /* extended source note, 32-159, in next byte */ |
651 |
|
|
SRC_NEWLINE = 22, /* bytecode follows a source newline */ |
652 |
|
|
SRC_SETLINE = 23, /* a file-absolute source line number note */ |
653 |
|
|
SRC_XDELTA = 24 /* 24-31 are for extended delta notes */ |
654 |
|
|
} JSSrcNoteType; |
655 |
|
|
|
656 |
|
|
/* |
657 |
|
|
* Constants for the SRC_DECL source note. Note that span-dependent bytecode |
658 |
|
|
* selection means that any SRC_DECL offset greater than SRC_DECL_LET may need |
659 |
|
|
* to be adjusted, but these "offsets" are too small to span a span-dependent |
660 |
|
|
* instruction, so can be used to denote distinct declaration syntaxes to the |
661 |
|
|
* decompiler. |
662 |
|
|
* |
663 |
|
|
* NB: the var_prefix array in jsopcode.c depends on these dense indexes from |
664 |
|
|
* SRC_DECL_VAR through SRC_DECL_LET. |
665 |
|
|
*/ |
666 |
|
|
#define SRC_DECL_VAR 0 |
667 |
|
|
#define SRC_DECL_CONST 1 |
668 |
|
|
#define SRC_DECL_LET 2 |
669 |
|
|
#define SRC_DECL_NONE 3 |
670 |
|
|
|
671 |
|
|
#define SN_TYPE_BITS 5 |
672 |
|
|
#define SN_DELTA_BITS 3 |
673 |
|
|
#define SN_XDELTA_BITS 6 |
674 |
|
|
#define SN_TYPE_MASK (JS_BITMASK(SN_TYPE_BITS) << SN_DELTA_BITS) |
675 |
|
|
#define SN_DELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_DELTA_BITS)) |
676 |
|
|
#define SN_XDELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_XDELTA_BITS)) |
677 |
|
|
|
678 |
|
|
#define SN_MAKE_NOTE(sn,t,d) (*(sn) = (jssrcnote) \ |
679 |
|
|
(((t) << SN_DELTA_BITS) \ |
680 |
|
|
| ((d) & SN_DELTA_MASK))) |
681 |
|
|
#define SN_MAKE_XDELTA(sn,d) (*(sn) = (jssrcnote) \ |
682 |
|
|
((SRC_XDELTA << SN_DELTA_BITS) \ |
683 |
|
|
| ((d) & SN_XDELTA_MASK))) |
684 |
|
|
|
685 |
|
|
#define SN_IS_XDELTA(sn) ((*(sn) >> SN_DELTA_BITS) >= SRC_XDELTA) |
686 |
|
|
#define SN_TYPE(sn) ((JSSrcNoteType)(SN_IS_XDELTA(sn) \ |
687 |
|
|
? SRC_XDELTA \ |
688 |
|
|
: *(sn) >> SN_DELTA_BITS)) |
689 |
|
|
#define SN_SET_TYPE(sn,type) SN_MAKE_NOTE(sn, type, SN_DELTA(sn)) |
690 |
|
|
#define SN_IS_GETTABLE(sn) (SN_TYPE(sn) < SRC_NEWLINE) |
691 |
|
|
|
692 |
|
|
#define SN_DELTA(sn) ((ptrdiff_t)(SN_IS_XDELTA(sn) \ |
693 |
|
|
? *(sn) & SN_XDELTA_MASK \ |
694 |
|
|
: *(sn) & SN_DELTA_MASK)) |
695 |
|
|
#define SN_SET_DELTA(sn,delta) (SN_IS_XDELTA(sn) \ |
696 |
|
|
? SN_MAKE_XDELTA(sn, delta) \ |
697 |
|
|
: SN_MAKE_NOTE(sn, SN_TYPE(sn), delta)) |
698 |
|
|
|
699 |
|
|
#define SN_DELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_DELTA_BITS)) |
700 |
|
|
#define SN_XDELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_XDELTA_BITS)) |
701 |
|
|
|
702 |
|
|
/* |
703 |
|
|
* Offset fields follow certain notes and are frequency-encoded: an offset in |
704 |
|
|
* [0,0x7f] consumes one byte, an offset in [0x80,0x7fffff] takes three, and |
705 |
|
|
* the high bit of the first byte is set. |
706 |
|
|
*/ |
707 |
|
|
#define SN_3BYTE_OFFSET_FLAG 0x80 |
708 |
|
|
#define SN_3BYTE_OFFSET_MASK 0x7f |
709 |
|
|
|
710 |
|
|
typedef struct JSSrcNoteSpec { |
711 |
|
|
const char *name; /* name for disassembly/debugging output */ |
712 |
|
|
int8 arity; /* number of offset operands */ |
713 |
|
|
uint8 offsetBias; /* bias of offset(s) from annotated pc */ |
714 |
|
|
int8 isSpanDep; /* 1 or -1 if offsets could span extended ops, |
715 |
|
|
0 otherwise; sign tells span direction */ |
716 |
|
|
} JSSrcNoteSpec; |
717 |
|
|
|
718 |
|
|
extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[]; |
719 |
|
|
extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn); |
720 |
|
|
|
721 |
|
|
#define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \ |
722 |
|
|
: js_SrcNoteLength(sn)) |
723 |
|
|
#define SN_NEXT(sn) ((sn) + SN_LENGTH(sn)) |
724 |
|
|
|
725 |
|
|
/* A source note array is terminated by an all-zero element. */ |
726 |
|
|
#define SN_MAKE_TERMINATOR(sn) (*(sn) = SRC_NULL) |
727 |
|
|
#define SN_IS_TERMINATOR(sn) (*(sn) == SRC_NULL) |
728 |
|
|
|
729 |
|
|
/* |
730 |
|
|
* Append a new source note of the given type (and therefore size) to cg's |
731 |
|
|
* notes dynamic array, updating cg->noteCount. Return the new note's index |
732 |
|
|
* within the array pointed at by cg->current->notes. Return -1 if out of |
733 |
|
|
* memory. |
734 |
|
|
*/ |
735 |
|
|
extern intN |
736 |
|
|
js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type); |
737 |
|
|
|
738 |
|
|
extern intN |
739 |
|
|
js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, |
740 |
|
|
ptrdiff_t offset); |
741 |
|
|
|
742 |
|
|
extern intN |
743 |
|
|
js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, |
744 |
|
|
ptrdiff_t offset1, ptrdiff_t offset2); |
745 |
|
|
|
746 |
|
|
/* |
747 |
|
|
* NB: this function can add at most one extra extended delta note. |
748 |
|
|
*/ |
749 |
|
|
extern jssrcnote * |
750 |
|
|
js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn, |
751 |
|
|
ptrdiff_t delta); |
752 |
|
|
|
753 |
|
|
/* |
754 |
|
|
* Get and set the offset operand identified by which (0 for the first, etc.). |
755 |
|
|
*/ |
756 |
|
|
extern JS_FRIEND_API(ptrdiff_t) |
757 |
|
|
js_GetSrcNoteOffset(jssrcnote *sn, uintN which); |
758 |
|
|
|
759 |
|
|
extern JSBool |
760 |
|
|
js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, |
761 |
|
|
uintN which, ptrdiff_t offset); |
762 |
|
|
|
763 |
|
|
/* |
764 |
|
|
* Finish taking source notes in cx's notePool, copying final notes to the new |
765 |
|
|
* stable store allocated by the caller and passed in via notes. Return false |
766 |
|
|
* on malloc failure, which means this function reported an error. |
767 |
|
|
* |
768 |
|
|
* To compute the number of jssrcnotes to allocate and pass in via notes, use |
769 |
|
|
* the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of |
770 |
|
|
* js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes |
771 |
|
|
* FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES! |
772 |
|
|
*/ |
773 |
|
|
#define CG_COUNT_FINAL_SRCNOTES(cg, cnt) \ |
774 |
|
|
JS_BEGIN_MACRO \ |
775 |
|
|
ptrdiff_t diff_ = CG_PROLOG_OFFSET(cg) - (cg)->prolog.lastNoteOffset; \ |
776 |
|
|
cnt = (cg)->prolog.noteCount + (cg)->main.noteCount + 1; \ |
777 |
|
|
if ((cg)->prolog.noteCount && \ |
778 |
|
|
(cg)->prolog.currentLine != (cg)->firstLine) { \ |
779 |
|
|
if (diff_ > SN_DELTA_MASK) \ |
780 |
|
|
cnt += JS_HOWMANY(diff_ - SN_DELTA_MASK, SN_XDELTA_MASK); \ |
781 |
|
|
cnt += 2 + (((cg)->firstLine > SN_3BYTE_OFFSET_MASK) << 1); \ |
782 |
|
|
} else if (diff_ > 0) { \ |
783 |
|
|
if (cg->main.noteCount) { \ |
784 |
|
|
jssrcnote *sn_ = (cg)->main.notes; \ |
785 |
|
|
diff_ -= SN_IS_XDELTA(sn_) \ |
786 |
|
|
? SN_XDELTA_MASK - (*sn_ & SN_XDELTA_MASK) \ |
787 |
|
|
: SN_DELTA_MASK - (*sn_ & SN_DELTA_MASK); \ |
788 |
|
|
} \ |
789 |
|
|
if (diff_ > 0) \ |
790 |
|
|
cnt += JS_HOWMANY(diff_, SN_XDELTA_MASK); \ |
791 |
|
|
} \ |
792 |
|
|
JS_END_MACRO |
793 |
|
|
|
794 |
|
|
extern JSBool |
795 |
|
|
js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes); |
796 |
|
|
|
797 |
|
|
extern void |
798 |
|
|
js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array); |
799 |
|
|
|
800 |
|
|
JS_END_EXTERN_C |
801 |
|
|
|
802 |
|
|
#endif /* jsemit_h___ */ |