1 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
* |
3 |
* ***** BEGIN LICENSE BLOCK ***** |
4 |
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
5 |
* |
6 |
* The contents of this file are subject to the Mozilla Public License Version |
7 |
* 1.1 (the "License"); you may not use this file except in compliance with |
8 |
* the License. You may obtain a copy of the License at |
9 |
* http://www.mozilla.org/MPL/ |
10 |
* |
11 |
* Software distributed under the License is distributed on an "AS IS" basis, |
12 |
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 |
* for the specific language governing rights and limitations under the |
14 |
* License. |
15 |
* |
16 |
* The Original Code is Mozilla Communicator client code, released |
17 |
* March 31, 1998. |
18 |
* |
19 |
* The Initial Developer of the Original Code is |
20 |
* Netscape Communications Corporation. |
21 |
* Portions created by the Initial Developer are Copyright (C) 1998 |
22 |
* the Initial Developer. All Rights Reserved. |
23 |
* |
24 |
* Contributor(s): |
25 |
* |
26 |
* Alternatively, the contents of this file may be used under the terms of |
27 |
* either of the GNU General Public License Version 2 or later (the "GPL"), |
28 |
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
29 |
* in which case the provisions of the GPL or the LGPL are applicable instead |
30 |
* of those above. If you wish to allow use of your version of this file only |
31 |
* under the terms of either the GPL or the LGPL, and not to allow others to |
32 |
* use your version of this file under the terms of the MPL, indicate your |
33 |
* decision by deleting the provisions above and replace them with the notice |
34 |
* and other provisions required by the GPL or the LGPL. If you do not delete |
35 |
* the provisions above, a recipient may use your version of this file under |
36 |
* the terms of any one of the MPL, the GPL or the LGPL. |
37 |
* |
38 |
* ***** END LICENSE BLOCK ***** */ |
39 |
|
40 |
#ifndef jsopcode_h___ |
41 |
#define jsopcode_h___ |
42 |
/* |
43 |
* JS bytecode definitions. |
44 |
*/ |
45 |
#include <stddef.h> |
46 |
#include "jsprvtd.h" |
47 |
#include "jspubtd.h" |
48 |
#include "jsutil.h" |
49 |
|
50 |
JS_BEGIN_EXTERN_C |
51 |
|
52 |
/* |
53 |
* JS operation bytecodes. |
54 |
*/ |
55 |
typedef enum JSOp { |
56 |
#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ |
57 |
op = val, |
58 |
#include "jsopcode.tbl" |
59 |
#undef OPDEF |
60 |
JSOP_LIMIT |
61 |
} JSOp; |
62 |
|
63 |
/* |
64 |
* JS bytecode formats. |
65 |
*/ |
66 |
#define JOF_BYTE 0 /* single bytecode, no immediates */ |
67 |
#define JOF_JUMP 1 /* signed 16-bit jump offset immediate */ |
68 |
#define JOF_ATOM 2 /* unsigned 16-bit constant pool index */ |
69 |
#define JOF_UINT16 3 /* unsigned 16-bit immediate operand */ |
70 |
#define JOF_TABLESWITCH 4 /* table switch */ |
71 |
#define JOF_LOOKUPSWITCH 5 /* lookup switch */ |
72 |
#define JOF_QARG 6 /* quickened get/set function argument ops */ |
73 |
#define JOF_LOCAL 7 /* var or block-local variable */ |
74 |
#define JOF_SLOTATOM 8 /* uint16 slot index + constant pool index */ |
75 |
#define JOF_JUMPX 9 /* signed 32-bit jump offset immediate */ |
76 |
#define JOF_TABLESWITCHX 10 /* extended (32-bit offset) table switch */ |
77 |
#define JOF_LOOKUPSWITCHX 11 /* extended (32-bit offset) lookup switch */ |
78 |
#define JOF_UINT24 12 /* extended unsigned 24-bit literal (index) */ |
79 |
#define JOF_UINT8 13 /* uint8 immediate, e.g. top 8 bits of 24-bit |
80 |
atom index */ |
81 |
#define JOF_INT32 14 /* int32 immediate operand */ |
82 |
#define JOF_OBJECT 15 /* unsigned 16-bit object pool index */ |
83 |
#define JOF_SLOTOBJECT 16 /* uint16 slot index + object pool index */ |
84 |
#define JOF_REGEXP 17 /* unsigned 16-bit regexp pool index */ |
85 |
#define JOF_INT8 18 /* int8 immediate operand */ |
86 |
#define JOF_TYPEMASK 0x001f /* mask for above immediate types */ |
87 |
|
88 |
#define JOF_NAME (1U<<5) /* name operation */ |
89 |
#define JOF_PROP (2U<<5) /* obj.prop operation */ |
90 |
#define JOF_ELEM (3U<<5) /* obj[index] operation */ |
91 |
#define JOF_XMLNAME (4U<<5) /* XML name: *, a::b, @a, @a::b, etc. */ |
92 |
#define JOF_VARPROP (5U<<5) /* x.prop for this, arg, var, or local x */ |
93 |
#define JOF_MODEMASK (7U<<5) /* mask for above addressing modes */ |
94 |
#define JOF_SET (1U<<8) /* set (i.e., assignment) operation */ |
95 |
#define JOF_DEL (1U<<9) /* delete operation */ |
96 |
#define JOF_DEC (1U<<10) /* decrement (--, not ++) opcode */ |
97 |
#define JOF_INC (2U<<10) /* increment (++, not --) opcode */ |
98 |
#define JOF_INCDEC (3U<<10) /* increment or decrement opcode */ |
99 |
#define JOF_POST (1U<<12) /* postorder increment or decrement */ |
100 |
#define JOF_FOR (1U<<13) /* for-in property op (akin to JOF_SET) */ |
101 |
#define JOF_ASSIGNING JOF_SET /* hint for JSClass.resolve, used for ops |
102 |
that do simplex assignment */ |
103 |
#define JOF_DETECTING (1U<<14) /* object detection for JSNewResolveOp */ |
104 |
#define JOF_BACKPATCH (1U<<15) /* backpatch placeholder during codegen */ |
105 |
#define JOF_LEFTASSOC (1U<<16) /* left-associative operator */ |
106 |
#define JOF_DECLARING (1U<<17) /* var, const, or function declaration op */ |
107 |
#define JOF_INDEXBASE (1U<<18) /* atom segment base setting prefix op */ |
108 |
#define JOF_CALLOP (1U<<19) /* call operation that pushes function and |
109 |
this */ |
110 |
#define JOF_PARENHEAD (1U<<20) /* opcode consumes value of expression in |
111 |
parenthesized statement head */ |
112 |
#define JOF_INVOKE (1U<<21) /* JSOP_CALL, JSOP_NEW, JSOP_EVAL */ |
113 |
#define JOF_TMPSLOT (1U<<22) /* interpreter uses extra temporary slot |
114 |
to root intermediate objects besides |
115 |
the slots opcode uses */ |
116 |
#define JOF_TMPSLOT2 (2U<<22) /* interpreter uses extra 2 temporary slot |
117 |
besides the slots opcode uses */ |
118 |
#define JOF_TMPSLOT_SHIFT 22 |
119 |
#define JOF_TMPSLOT_MASK (JS_BITMASK(2) << JOF_TMPSLOT_SHIFT) |
120 |
|
121 |
/* Shorthands for type from format and type from opcode. */ |
122 |
#define JOF_TYPE(fmt) ((fmt) & JOF_TYPEMASK) |
123 |
#define JOF_OPTYPE(op) JOF_TYPE(js_CodeSpec[op].format) |
124 |
|
125 |
/* Shorthands for mode from format and mode from opcode. */ |
126 |
#define JOF_MODE(fmt) ((fmt) & JOF_MODEMASK) |
127 |
#define JOF_OPMODE(op) JOF_MODE(js_CodeSpec[op].format) |
128 |
|
129 |
#define JOF_TYPE_IS_EXTENDED_JUMP(t) \ |
130 |
((unsigned)((t) - JOF_JUMPX) <= (unsigned)(JOF_LOOKUPSWITCHX - JOF_JUMPX)) |
131 |
|
132 |
/* |
133 |
* Immediate operand getters, setters, and bounds. |
134 |
*/ |
135 |
|
136 |
/* Common uint16 immediate format helpers. */ |
137 |
#define UINT16_LEN 2 |
138 |
#define UINT16_HI(i) ((jsbytecode)((i) >> 8)) |
139 |
#define UINT16_LO(i) ((jsbytecode)(i)) |
140 |
#define GET_UINT16(pc) ((uintN)(((pc)[1] << 8) | (pc)[2])) |
141 |
#define SET_UINT16(pc,i) ((pc)[1] = UINT16_HI(i), (pc)[2] = UINT16_LO(i)) |
142 |
#define UINT16_LIMIT ((uintN)1 << 16) |
143 |
|
144 |
/* Short (2-byte signed offset) relative jump macros. */ |
145 |
#define JUMP_OFFSET_LEN 2 |
146 |
#define JUMP_OFFSET_HI(off) ((jsbytecode)((off) >> 8)) |
147 |
#define JUMP_OFFSET_LO(off) ((jsbytecode)(off)) |
148 |
#define GET_JUMP_OFFSET(pc) ((int16)GET_UINT16(pc)) |
149 |
#define SET_JUMP_OFFSET(pc,off) ((pc)[1] = JUMP_OFFSET_HI(off), \ |
150 |
(pc)[2] = JUMP_OFFSET_LO(off)) |
151 |
#define JUMP_OFFSET_MIN ((int16)0x8000) |
152 |
#define JUMP_OFFSET_MAX ((int16)0x7fff) |
153 |
|
154 |
/* |
155 |
* When a short jump won't hold a relative offset, its 2-byte immediate offset |
156 |
* operand is an unsigned index of a span-dependency record, maintained until |
157 |
* code generation finishes -- after which some (but we hope not nearly all) |
158 |
* span-dependent jumps must be extended (see OptimizeSpanDeps in jsemit.c). |
159 |
* |
160 |
* If the span-dependency record index overflows SPANDEP_INDEX_MAX, the jump |
161 |
* offset will contain SPANDEP_INDEX_HUGE, indicating that the record must be |
162 |
* found (via binary search) by its "before span-dependency optimization" pc |
163 |
* offset (from script main entry point). |
164 |
*/ |
165 |
#define GET_SPANDEP_INDEX(pc) ((uint16)GET_UINT16(pc)) |
166 |
#define SET_SPANDEP_INDEX(pc,i) ((pc)[1] = JUMP_OFFSET_HI(i), \ |
167 |
(pc)[2] = JUMP_OFFSET_LO(i)) |
168 |
#define SPANDEP_INDEX_MAX ((uint16)0xfffe) |
169 |
#define SPANDEP_INDEX_HUGE ((uint16)0xffff) |
170 |
|
171 |
/* Ultimately, if short jumps won't do, emit long (4-byte signed) offsets. */ |
172 |
#define JUMPX_OFFSET_LEN 4 |
173 |
#define JUMPX_OFFSET_B3(off) ((jsbytecode)((off) >> 24)) |
174 |
#define JUMPX_OFFSET_B2(off) ((jsbytecode)((off) >> 16)) |
175 |
#define JUMPX_OFFSET_B1(off) ((jsbytecode)((off) >> 8)) |
176 |
#define JUMPX_OFFSET_B0(off) ((jsbytecode)(off)) |
177 |
#define GET_JUMPX_OFFSET(pc) ((int32)(((pc)[1] << 24) | ((pc)[2] << 16) \ |
178 |
| ((pc)[3] << 8) | (pc)[4])) |
179 |
#define SET_JUMPX_OFFSET(pc,off)((pc)[1] = JUMPX_OFFSET_B3(off), \ |
180 |
(pc)[2] = JUMPX_OFFSET_B2(off), \ |
181 |
(pc)[3] = JUMPX_OFFSET_B1(off), \ |
182 |
(pc)[4] = JUMPX_OFFSET_B0(off)) |
183 |
#define JUMPX_OFFSET_MIN ((int32)0x80000000) |
184 |
#define JUMPX_OFFSET_MAX ((int32)0x7fffffff) |
185 |
|
186 |
/* |
187 |
* A literal is indexed by a per-script atom or object maps. Most scripts |
188 |
* have relatively few literals, so the standard JOF_ATOM, JOF_OBJECT and |
189 |
* JOF_REGEXP formats specifies a fixed 16 bits of immediate operand index. |
190 |
* A script with more than 64K literals must wrap the bytecode into |
191 |
* JSOP_INDEXBASE and JSOP_RESETBASE pair. |
192 |
*/ |
193 |
#define INDEX_LEN 2 |
194 |
#define INDEX_HI(i) ((jsbytecode)((i) >> 8)) |
195 |
#define INDEX_LO(i) ((jsbytecode)(i)) |
196 |
#define GET_INDEX(pc) GET_UINT16(pc) |
197 |
#define SET_INDEX(pc,i) ((pc)[1] = INDEX_HI(i), (pc)[2] = INDEX_LO(i)) |
198 |
|
199 |
#define GET_INDEXBASE(pc) (JS_ASSERT(*(pc) == JSOP_INDEXBASE), \ |
200 |
((uintN)((pc)[1])) << 16) |
201 |
#define INDEXBASE_LEN 1 |
202 |
|
203 |
#define UINT24_HI(i) ((jsbytecode)((i) >> 16)) |
204 |
#define UINT24_MID(i) ((jsbytecode)((i) >> 8)) |
205 |
#define UINT24_LO(i) ((jsbytecode)(i)) |
206 |
#define GET_UINT24(pc) ((jsatomid)(((pc)[1] << 16) | \ |
207 |
((pc)[2] << 8) | \ |
208 |
(pc)[3])) |
209 |
#define SET_UINT24(pc,i) ((pc)[1] = UINT24_HI(i), \ |
210 |
(pc)[2] = UINT24_MID(i), \ |
211 |
(pc)[3] = UINT24_LO(i)) |
212 |
|
213 |
#define GET_INT8(pc) ((jsint)(int8)(pc)[1]) |
214 |
|
215 |
#define GET_INT32(pc) ((jsint)(((uint32)((pc)[1]) << 24) | \ |
216 |
((uint32)((pc)[2]) << 16) | \ |
217 |
((uint32)((pc)[3]) << 8) | \ |
218 |
(uint32)(pc)[4])) |
219 |
#define SET_INT32(pc,i) ((pc)[1] = (jsbytecode)((uint32)(i) >> 24), \ |
220 |
(pc)[2] = (jsbytecode)((uint32)(i) >> 16), \ |
221 |
(pc)[3] = (jsbytecode)((uint32)(i) >> 8), \ |
222 |
(pc)[4] = (jsbytecode)(uint32)(i)) |
223 |
|
224 |
/* Index limit is determined by SN_3BYTE_OFFSET_FLAG, see jsemit.h. */ |
225 |
#define INDEX_LIMIT_LOG2 23 |
226 |
#define INDEX_LIMIT ((uint32)1 << INDEX_LIMIT_LOG2) |
227 |
|
228 |
JS_STATIC_ASSERT(sizeof(uint32) * JS_BITS_PER_BYTE >= INDEX_LIMIT_LOG2 + 1); |
229 |
|
230 |
/* Actual argument count operand format helpers. */ |
231 |
#define ARGC_HI(argc) UINT16_HI(argc) |
232 |
#define ARGC_LO(argc) UINT16_LO(argc) |
233 |
#define GET_ARGC(pc) GET_UINT16(pc) |
234 |
#define ARGC_LIMIT UINT16_LIMIT |
235 |
|
236 |
/* Synonyms for quick JOF_QARG and JOF_LOCAL bytecodes. */ |
237 |
#define GET_ARGNO(pc) GET_UINT16(pc) |
238 |
#define SET_ARGNO(pc,argno) SET_UINT16(pc,argno) |
239 |
#define ARGNO_LEN 2 |
240 |
#define ARGNO_LIMIT UINT16_LIMIT |
241 |
|
242 |
#define GET_SLOTNO(pc) GET_UINT16(pc) |
243 |
#define SET_SLOTNO(pc,varno) SET_UINT16(pc,varno) |
244 |
#define SLOTNO_LEN 2 |
245 |
#define SLOTNO_LIMIT UINT16_LIMIT |
246 |
|
247 |
struct JSCodeSpec { |
248 |
int8 length; /* length including opcode byte */ |
249 |
int8 nuses; /* arity, -1 if variadic */ |
250 |
int8 ndefs; /* number of stack results */ |
251 |
uint8 prec; /* operator precedence */ |
252 |
uint32 format; /* immediate operand format */ |
253 |
}; |
254 |
|
255 |
extern const JSCodeSpec js_CodeSpec[]; |
256 |
extern uintN js_NumCodeSpecs; |
257 |
extern const char *js_CodeName[]; |
258 |
extern const char js_EscapeMap[]; |
259 |
|
260 |
/* |
261 |
* Return a GC'ed string containing the chars in str, with any non-printing |
262 |
* chars or quotes (' or " as specified by the quote argument) escaped, and |
263 |
* with the quote character at the beginning and end of the result string. |
264 |
*/ |
265 |
extern JSString * |
266 |
js_QuoteString(JSContext *cx, JSString *str, jschar quote); |
267 |
|
268 |
/* |
269 |
* JSPrinter operations, for printf style message formatting. The return |
270 |
* value from js_GetPrinterOutput() is the printer's cumulative output, in |
271 |
* a GC'ed string. |
272 |
*/ |
273 |
|
274 |
#ifdef JS_ARENAMETER |
275 |
# define JS_NEW_PRINTER(cx, name, fun, indent, pretty) \ |
276 |
js_NewPrinter(cx, name, fun, indent, pretty) |
277 |
#else |
278 |
# define JS_NEW_PRINTER(cx, name, fun, indent, pretty) \ |
279 |
js_NewPrinter(cx, fun, indent, pretty) |
280 |
#endif |
281 |
|
282 |
extern JSPrinter * |
283 |
JS_NEW_PRINTER(JSContext *cx, const char *name, JSFunction *fun, |
284 |
uintN indent, JSBool pretty); |
285 |
|
286 |
extern void |
287 |
js_DestroyPrinter(JSPrinter *jp); |
288 |
|
289 |
extern JSString * |
290 |
js_GetPrinterOutput(JSPrinter *jp); |
291 |
|
292 |
extern int |
293 |
js_printf(JSPrinter *jp, const char *format, ...); |
294 |
|
295 |
extern JSBool |
296 |
js_puts(JSPrinter *jp, const char *s); |
297 |
|
298 |
/* |
299 |
* Get index operand from the bytecode using a bytecode analysis to deduce the |
300 |
* the index register. This function is infallible, in spite of taking cx as |
301 |
* its first parameter; it uses only cx->runtime when calling JS_GetTrapOpcode. |
302 |
* The GET_*_FROM_BYTECODE macros that call it pick up cx from their caller's |
303 |
* lexical environments. |
304 |
*/ |
305 |
uintN |
306 |
js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, |
307 |
ptrdiff_t pcoff); |
308 |
|
309 |
/* |
310 |
* A slower version of GET_ATOM when the caller does not want to maintain |
311 |
* the index segment register itself. |
312 |
*/ |
313 |
#define GET_ATOM_FROM_BYTECODE(script, pc, pcoff, atom) \ |
314 |
JS_BEGIN_MACRO \ |
315 |
uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ |
316 |
JS_GET_SCRIPT_ATOM((script), index_, atom); \ |
317 |
JS_END_MACRO |
318 |
|
319 |
#define GET_OBJECT_FROM_BYTECODE(script, pc, pcoff, obj) \ |
320 |
JS_BEGIN_MACRO \ |
321 |
uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ |
322 |
JS_GET_SCRIPT_OBJECT((script), index_, obj); \ |
323 |
JS_END_MACRO |
324 |
|
325 |
#define GET_FUNCTION_FROM_BYTECODE(script, pc, pcoff, fun) \ |
326 |
JS_BEGIN_MACRO \ |
327 |
uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ |
328 |
JS_GET_SCRIPT_FUNCTION((script), index_, fun); \ |
329 |
JS_END_MACRO |
330 |
|
331 |
#define GET_REGEXP_FROM_BYTECODE(script, pc, pcoff, obj) \ |
332 |
JS_BEGIN_MACRO \ |
333 |
uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ |
334 |
JS_GET_SCRIPT_REGEXP((script), index_, obj); \ |
335 |
JS_END_MACRO |
336 |
|
337 |
/* |
338 |
* Get the length of variable-length bytecode like JSOP_TABLESWITCH. |
339 |
*/ |
340 |
extern uintN |
341 |
js_GetVariableBytecodeLength(jsbytecode *pc); |
342 |
|
343 |
/* |
344 |
* Find the number of stack slots used by a variadic opcode such as JSOP_CALL |
345 |
* or JSOP_NEWARRAY (for such ops, JSCodeSpec.nuses is -1). |
346 |
*/ |
347 |
extern uintN |
348 |
js_GetVariableStackUseLength(JSOp op, jsbytecode *pc); |
349 |
|
350 |
#ifdef DEBUG |
351 |
/* |
352 |
* Disassemblers, for debugging only. |
353 |
*/ |
354 |
#include <stdio.h> |
355 |
|
356 |
extern JS_FRIEND_API(JSBool) |
357 |
js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp); |
358 |
|
359 |
extern JS_FRIEND_API(uintN) |
360 |
js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, |
361 |
JSBool lines, FILE *fp); |
362 |
#endif /* DEBUG */ |
363 |
|
364 |
/* |
365 |
* Decompilers, for script, function, and expression pretty-printing. |
366 |
*/ |
367 |
extern JSBool |
368 |
js_DecompileScript(JSPrinter *jp, JSScript *script); |
369 |
|
370 |
extern JSBool |
371 |
js_DecompileFunctionBody(JSPrinter *jp); |
372 |
|
373 |
extern JSBool |
374 |
js_DecompileFunction(JSPrinter *jp); |
375 |
|
376 |
/* |
377 |
* Find the source expression that resulted in v, and return a newly allocated |
378 |
* C-string containing it. Fall back on v's string conversion (fallback) if we |
379 |
* can't find the bytecode that generated and pushed v on the operand stack. |
380 |
* |
381 |
* Search the current stack frame if spindex is JSDVG_SEARCH_STACK. Don't |
382 |
* look for v on the stack if spindex is JSDVG_IGNORE_STACK. Otherwise, |
383 |
* spindex is the negative index of v, measured from cx->fp->sp, or from a |
384 |
* lower frame's sp if cx->fp is native. |
385 |
* |
386 |
* The caller must call JS_free on the result after a succsesful call. |
387 |
*/ |
388 |
extern char * |
389 |
js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, |
390 |
JSString *fallback); |
391 |
|
392 |
#define JSDVG_IGNORE_STACK 0 |
393 |
#define JSDVG_SEARCH_STACK 1 |
394 |
|
395 |
/* |
396 |
* Given bytecode address pc in script's main program code, return the operand |
397 |
* stack depth just before (JSOp) *pc executes. |
398 |
*/ |
399 |
extern uintN |
400 |
js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc); |
401 |
|
402 |
JS_END_EXTERN_C |
403 |
|
404 |
#endif /* jsopcode_h___ */ |