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 : /*
44 : * JS bytecode definitions.
45 : */
46 : #include <stddef.h>
47 : #include "jsprvtd.h"
48 : #include "jspubtd.h"
49 : #include "jsutil.h"
50 :
51 : JS_BEGIN_EXTERN_C
52 :
53 : /*
54 : * JS operation bytecodes.
55 : */
56 : typedef enum JSOp {
57 : #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
58 : op = val,
59 : #include "jsopcode.tbl"
60 : #undef OPDEF
61 : JSOP_LIMIT,
62 :
63 : /*
64 : * These pseudo-ops help js_DecompileValueGenerator decompile JSOP_SETPROP,
65 : * JSOP_SETELEM, and comprehension-tails, respectively. They are never
66 : * stored in bytecode, so they don't preempt valid opcodes.
67 : */
68 : JSOP_GETPROP2 = JSOP_LIMIT,
69 : JSOP_GETELEM2 = JSOP_LIMIT + 1,
70 : JSOP_FORLOCAL = JSOP_LIMIT + 2,
71 : JSOP_FAKE_LIMIT = JSOP_FORLOCAL
72 : } JSOp;
73 :
74 : /*
75 : * JS bytecode formats.
76 : */
77 : #define JOF_BYTE 0 /* single bytecode, no immediates */
78 : #define JOF_JUMP 1 /* signed 16-bit jump offset immediate */
79 : #define JOF_ATOM 2 /* unsigned 16-bit constant index */
80 : #define JOF_UINT16 3 /* unsigned 16-bit immediate operand */
81 : #define JOF_TABLESWITCH 4 /* table switch */
82 : #define JOF_LOOKUPSWITCH 5 /* lookup switch */
83 : #define JOF_QARG 6 /* quickened get/set function argument ops */
84 : #define JOF_LOCAL 7 /* var or block-local variable */
85 : #define JOF_DOUBLE 8 /* uint32_t index for double value */
86 : #define JOF_UINT24 12 /* extended unsigned 24-bit literal (index) */
87 : #define JOF_UINT8 13 /* uint8_t immediate, e.g. top 8 bits of 24-bit
88 : atom index */
89 : #define JOF_INT32 14 /* int32_t immediate operand */
90 : #define JOF_OBJECT 15 /* unsigned 16-bit object index */
91 : #define JOF_SLOTOBJECT 16 /* uint16_t slot index + object index */
92 : #define JOF_REGEXP 17 /* unsigned 32-bit regexp index */
93 : #define JOF_INT8 18 /* int8_t immediate operand */
94 : #define JOF_ATOMOBJECT 19 /* uint16_t constant index + object index */
95 : #define JOF_UINT16PAIR 20 /* pair of uint16_t immediates */
96 : #define JOF_TYPEMASK 0x001f /* mask for above immediate types */
97 :
98 : #define JOF_NAME (1U<<5) /* name operation */
99 : #define JOF_PROP (2U<<5) /* obj.prop operation */
100 : #define JOF_ELEM (3U<<5) /* obj[index] operation */
101 : #define JOF_XMLNAME (4U<<5) /* XML name: *, a::b, @a, @a::b, etc. */
102 : #define JOF_VARPROP (5U<<5) /* x.prop for this, arg, var, or local x */
103 : #define JOF_MODEMASK (7U<<5) /* mask for above addressing modes */
104 : #define JOF_SET (1U<<8) /* set (i.e., assignment) operation */
105 : #define JOF_DEL (1U<<9) /* delete operation */
106 : #define JOF_DEC (1U<<10) /* decrement (--, not ++) opcode */
107 : #define JOF_INC (2U<<10) /* increment (++, not --) opcode */
108 : #define JOF_INCDEC (3U<<10) /* increment or decrement opcode */
109 : #define JOF_POST (1U<<12) /* postorder increment or decrement */
110 : #define JOF_ASSIGNING JOF_SET /* hint for Class.resolve, used for ops
111 : that do simplex assignment */
112 : #define JOF_DETECTING (1U<<14) /* object detection for JSNewResolveOp */
113 : #define JOF_BACKPATCH (1U<<15) /* backpatch placeholder during codegen */
114 : #define JOF_LEFTASSOC (1U<<16) /* left-associative operator */
115 : #define JOF_DECLARING (1U<<17) /* var, const, or function declaration op */
116 : /* (1U<<18) is unused */
117 : #define JOF_PARENHEAD (1U<<20) /* opcode consumes value of expression in
118 : parenthesized statement head */
119 : #define JOF_INVOKE (1U<<21) /* JSOP_CALL, JSOP_NEW, JSOP_EVAL */
120 : #define JOF_TMPSLOT (1U<<22) /* interpreter uses extra temporary slot
121 : to root intermediate objects besides
122 : the slots opcode uses */
123 : #define JOF_TMPSLOT2 (2U<<22) /* interpreter uses extra 2 temporary slot
124 : besides the slots opcode uses */
125 : #define JOF_TMPSLOT3 (3U<<22) /* interpreter uses extra 3 temporary slot
126 : besides the slots opcode uses */
127 : #define JOF_TMPSLOT_SHIFT 22
128 : #define JOF_TMPSLOT_MASK (JS_BITMASK(2) << JOF_TMPSLOT_SHIFT)
129 :
130 : /* (1U<<24) is unused */
131 : #define JOF_GNAME (1U<<25) /* predicted global name */
132 : #define JOF_TYPESET (1U<<26) /* has an entry in a script's type sets */
133 : #define JOF_DECOMPOSE (1U<<27) /* followed by an equivalent decomposed
134 : * version of the opcode */
135 : #define JOF_ARITH (1U<<28) /* unary or binary arithmetic opcode */
136 :
137 : /* Shorthands for type from format and type from opcode. */
138 : #define JOF_TYPE(fmt) ((fmt) & JOF_TYPEMASK)
139 : #define JOF_OPTYPE(op) JOF_TYPE(js_CodeSpec[op].format)
140 :
141 : /* Shorthands for mode from format and mode from opcode. */
142 : #define JOF_MODE(fmt) ((fmt) & JOF_MODEMASK)
143 : #define JOF_OPMODE(op) JOF_MODE(js_CodeSpec[op].format)
144 :
145 : #define JOF_TYPE_IS_EXTENDED_JUMP(t) \
146 : ((unsigned)((t) - JOF_JUMP) <= (unsigned)(JOF_LOOKUPSWITCH - JOF_JUMP))
147 :
148 : /*
149 : * Immediate operand getters, setters, and bounds.
150 : */
151 :
152 : static JS_ALWAYS_INLINE uint8_t
153 195983721 : GET_UINT8(jsbytecode *pc)
154 : {
155 195983721 : return (uint8_t) pc[1];
156 : }
157 :
158 : static JS_ALWAYS_INLINE void
159 : SET_UINT8(jsbytecode *pc, uint8_t u)
160 : {
161 : pc[1] = (jsbytecode) u;
162 : }
163 :
164 : /* Common uint16_t immediate format helpers. */
165 : #define UINT16_LEN 2
166 : #define UINT16_HI(i) ((jsbytecode)((i) >> 8))
167 : #define UINT16_LO(i) ((jsbytecode)(i))
168 : #define GET_UINT16(pc) ((unsigned)(((pc)[1] << 8) | (pc)[2]))
169 : #define SET_UINT16(pc,i) ((pc)[1] = UINT16_HI(i), (pc)[2] = UINT16_LO(i))
170 : #define UINT16_LIMIT ((unsigned)1 << 16)
171 :
172 : /* Helpers for accessing the offsets of jump opcodes. */
173 : #define JUMP_OFFSET_LEN 4
174 : #define JUMP_OFFSET_MIN INT32_MIN
175 : #define JUMP_OFFSET_MAX INT32_MAX
176 :
177 : static JS_ALWAYS_INLINE int32_t
178 190066876 : GET_JUMP_OFFSET(jsbytecode *pc)
179 : {
180 190066876 : return (pc[1] << 24) | (pc[2] << 16) | (pc[3] << 8) | pc[4];
181 : }
182 :
183 : static JS_ALWAYS_INLINE void
184 4911268 : SET_JUMP_OFFSET(jsbytecode *pc, int32_t off)
185 : {
186 4911268 : pc[1] = (jsbytecode)(off >> 24);
187 4911268 : pc[2] = (jsbytecode)(off >> 16);
188 4911268 : pc[3] = (jsbytecode)(off >> 8);
189 4911268 : pc[4] = (jsbytecode)off;
190 4911268 : }
191 :
192 : #define UINT32_INDEX_LEN 4
193 :
194 : static JS_ALWAYS_INLINE uint32_t
195 78203260 : GET_UINT32_INDEX(const jsbytecode *pc)
196 : {
197 78203260 : return (pc[1] << 24) | (pc[2] << 16) | (pc[3] << 8) | pc[4];
198 : }
199 :
200 : static JS_ALWAYS_INLINE void
201 29083502 : SET_UINT32_INDEX(jsbytecode *pc, uint32_t index)
202 : {
203 29083502 : pc[1] = (jsbytecode)(index >> 24);
204 29083502 : pc[2] = (jsbytecode)(index >> 16);
205 29083502 : pc[3] = (jsbytecode)(index >> 8);
206 29083502 : pc[4] = (jsbytecode)index;
207 29083502 : }
208 :
209 : #define UINT24_HI(i) ((jsbytecode)((i) >> 16))
210 : #define UINT24_MID(i) ((jsbytecode)((i) >> 8))
211 : #define UINT24_LO(i) ((jsbytecode)(i))
212 : #define GET_UINT24(pc) ((jsatomid)(((pc)[1] << 16) | \
213 : ((pc)[2] << 8) | \
214 : (pc)[3]))
215 : #define SET_UINT24(pc,i) ((pc)[1] = UINT24_HI(i), \
216 : (pc)[2] = UINT24_MID(i), \
217 : (pc)[3] = UINT24_LO(i))
218 :
219 : #define GET_INT8(pc) (int8_t((pc)[1]))
220 :
221 : #define GET_INT32(pc) (((uint32_t((pc)[1]) << 24) | \
222 : (uint32_t((pc)[2]) << 16) | \
223 : (uint32_t((pc)[3]) << 8) | \
224 : uint32_t((pc)[4])))
225 : #define SET_INT32(pc,i) ((pc)[1] = (jsbytecode)(uint32_t(i) >> 24), \
226 : (pc)[2] = (jsbytecode)(uint32_t(i) >> 16), \
227 : (pc)[3] = (jsbytecode)(uint32_t(i) >> 8), \
228 : (pc)[4] = (jsbytecode)uint32_t(i))
229 :
230 : /* Index limit is determined by SN_3BYTE_OFFSET_FLAG, see frontend/BytecodeEmitter.h. */
231 : #define INDEX_LIMIT_LOG2 23
232 : #define INDEX_LIMIT (uint32_t(1) << INDEX_LIMIT_LOG2)
233 :
234 : /* Actual argument count operand format helpers. */
235 : #define ARGC_HI(argc) UINT16_HI(argc)
236 : #define ARGC_LO(argc) UINT16_LO(argc)
237 : #define GET_ARGC(pc) GET_UINT16(pc)
238 : #define ARGC_LIMIT UINT16_LIMIT
239 :
240 : /* Synonyms for quick JOF_QARG and JOF_LOCAL bytecodes. */
241 : #define GET_ARGNO(pc) GET_UINT16(pc)
242 : #define SET_ARGNO(pc,argno) SET_UINT16(pc,argno)
243 : #define ARGNO_LEN 2
244 : #define ARGNO_LIMIT UINT16_LIMIT
245 :
246 : #define GET_SLOTNO(pc) GET_UINT16(pc)
247 : #define SET_SLOTNO(pc,varno) SET_UINT16(pc,varno)
248 : #define SLOTNO_LEN 2
249 : #define SLOTNO_LIMIT UINT16_LIMIT
250 :
251 : struct JSCodeSpec {
252 : int8_t length; /* length including opcode byte */
253 : int8_t nuses; /* arity, -1 if variadic */
254 : int8_t ndefs; /* number of stack results */
255 : uint8_t prec; /* operator precedence */
256 : uint32_t format; /* immediate operand format */
257 :
258 2969977 : uint32_t type() const { return JOF_TYPE(format); }
259 : };
260 :
261 : extern const JSCodeSpec js_CodeSpec[];
262 : extern unsigned js_NumCodeSpecs;
263 : extern const char *js_CodeName[];
264 : extern const char js_EscapeMap[];
265 :
266 : /* Silence unreferenced formal parameter warnings */
267 : #ifdef _MSC_VER
268 : #pragma warning(push)
269 : #pragma warning(disable:4100)
270 : #endif
271 :
272 : /*
273 : * Return a GC'ed string containing the chars in str, with any non-printing
274 : * chars or quotes (' or " as specified by the quote argument) escaped, and
275 : * with the quote character at the beginning and end of the result string.
276 : */
277 : extern JSString *
278 : js_QuoteString(JSContext *cx, JSString *str, jschar quote);
279 :
280 : /*
281 : * JSPrinter operations, for printf style message formatting. The return
282 : * value from js_GetPrinterOutput() is the printer's cumulative output, in
283 : * a GC'ed string.
284 : *
285 : * strict is true if the context in which the output will appear has
286 : * already been marked as strict, thus indicating that nested
287 : * functions need not be re-marked with a strict directive. It should
288 : * be false in the outermost printer.
289 : */
290 :
291 : extern JSPrinter *
292 : js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun,
293 : unsigned indent, JSBool pretty, JSBool grouped, JSBool strict);
294 :
295 : extern void
296 : js_DestroyPrinter(JSPrinter *jp);
297 :
298 : extern JSString *
299 : js_GetPrinterOutput(JSPrinter *jp);
300 :
301 : extern int
302 : js_printf(JSPrinter *jp, const char *format, ...);
303 :
304 : extern JSBool
305 : js_puts(JSPrinter *jp, const char *s);
306 :
307 : #define GET_ATOM_FROM_BYTECODE(script, pc, pcoff, atom) \
308 : JS_BEGIN_MACRO \
309 : JS_ASSERT(js_CodeSpec[*(pc)].format & JOF_ATOM); \
310 : (atom) = (script)->getAtom(GET_UINT32_INDEX((pc) + (pcoff))); \
311 : JS_END_MACRO
312 :
313 : #define GET_NAME_FROM_BYTECODE(script, pc, pcoff, name) \
314 : JS_BEGIN_MACRO \
315 : JSAtom *atom_; \
316 : GET_ATOM_FROM_BYTECODE(script, pc, pcoff, atom_); \
317 : JS_ASSERT(js_CodeSpec[*(pc)].format & (JOF_NAME | JOF_PROP)); \
318 : (name) = atom_->asPropertyName(); \
319 : JS_END_MACRO
320 :
321 : namespace js {
322 :
323 : extern unsigned
324 : StackUses(JSScript *script, jsbytecode *pc);
325 :
326 : extern unsigned
327 : StackDefs(JSScript *script, jsbytecode *pc);
328 :
329 : } /* namespace js */
330 :
331 : /*
332 : * Decompilers, for script, function, and expression pretty-printing.
333 : */
334 : extern JSBool
335 : js_DecompileScript(JSPrinter *jp, JSScript *script);
336 :
337 : extern JSBool
338 : js_DecompileFunctionBody(JSPrinter *jp);
339 :
340 : extern JSBool
341 : js_DecompileFunction(JSPrinter *jp);
342 :
343 : /*
344 : * Some C++ compilers treat the language linkage (extern "C" vs.
345 : * extern "C++") as part of function (and thus pointer-to-function)
346 : * types. The use of this typedef (defined in "C") ensures that
347 : * js_DecompileToString's definition (in "C++") gets matched up with
348 : * this declaration.
349 : */
350 : typedef JSBool (* JSDecompilerPtr)(JSPrinter *);
351 :
352 : extern JSString *
353 : js_DecompileToString(JSContext *cx, const char *name, JSFunction *fun,
354 : unsigned indent, JSBool pretty, JSBool grouped, JSBool strict,
355 : JSDecompilerPtr decompiler);
356 :
357 : /*
358 : * Find the source expression that resulted in v, and return a newly allocated
359 : * C-string containing it. Fall back on v's string conversion (fallback) if we
360 : * can't find the bytecode that generated and pushed v on the operand stack.
361 : *
362 : * Search the current stack frame if spindex is JSDVG_SEARCH_STACK. Don't
363 : * look for v on the stack if spindex is JSDVG_IGNORE_STACK. Otherwise,
364 : * spindex is the negative index of v, measured from cx->fp->sp, or from a
365 : * lower frame's sp if cx->fp is native.
366 : *
367 : * The caller must call JS_free on the result after a succsesful call.
368 : */
369 : extern char *
370 : js_DecompileValueGenerator(JSContext *cx, int spindex, jsval v,
371 : JSString *fallback);
372 :
373 : /*
374 : * Given bytecode address pc in script's main program code, return the operand
375 : * stack depth just before (JSOp) *pc executes.
376 : */
377 : extern unsigned
378 : js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc);
379 :
380 : #ifdef _MSC_VER
381 : #pragma warning(pop)
382 : #endif
383 :
384 : JS_END_EXTERN_C
385 :
386 : #define JSDVG_IGNORE_STACK 0
387 : #define JSDVG_SEARCH_STACK 1
388 :
389 : /*
390 : * Get the length of variable-length bytecode like JSOP_TABLESWITCH.
391 : */
392 : extern size_t
393 : js_GetVariableBytecodeLength(jsbytecode *pc);
394 :
395 : namespace js {
396 :
397 : static inline char *
398 4794 : DecompileValueGenerator(JSContext *cx, int spindex, const Value &v,
399 : JSString *fallback)
400 : {
401 4794 : return js_DecompileValueGenerator(cx, spindex, v, fallback);
402 : }
403 :
404 : /*
405 : * Sprintf, but with unlimited and automatically allocated buffering.
406 : */
407 : class Sprinter
408 : {
409 : public:
410 : struct InvariantChecker
411 : {
412 : const Sprinter *parent;
413 :
414 2429979 : explicit InvariantChecker(const Sprinter *p) : parent(p) {
415 2429979 : parent->checkInvariants();
416 2429979 : }
417 :
418 2429979 : ~InvariantChecker() {
419 2429979 : parent->checkInvariants();
420 2429979 : }
421 : };
422 :
423 : JSContext *context; /* context executing the decompiler */
424 :
425 : private:
426 : static const size_t DefaultSize;
427 : #ifdef DEBUG
428 : bool initialized; /* true if this is initialized, use for debug builds */
429 : #endif
430 : char *base; /* malloc'd buffer address */
431 : size_t size; /* size of buffer allocated at base */
432 : ptrdiff_t offset; /* offset of next free char in buffer */
433 :
434 : bool realloc_(size_t newSize);
435 :
436 : public:
437 : explicit Sprinter(JSContext *cx);
438 : ~Sprinter();
439 :
440 : /* Initialize this sprinter, returns false on error */
441 : bool init();
442 :
443 : void checkInvariants() const;
444 :
445 : const char *string() const;
446 : const char *stringEnd() const;
447 : /* Returns the string at offset |off| */
448 : char *stringAt(ptrdiff_t off) const;
449 : /* Returns the char at offset |off| */
450 : char &operator[](size_t off);
451 : /* Test if this Sprinter is empty */
452 : bool empty() const;
453 :
454 : /*
455 : * Attempt to reserve len + 1 space (for a trailing NULL byte). If the
456 : * attempt succeeds, return a pointer to the start of that space and adjust the
457 : * internal content. The caller *must* completely fill this space on success.
458 : */
459 : char *reserve(size_t len);
460 : /* Like reserve, but memory is initialized to 0 */
461 : char *reserveAndClear(size_t len);
462 :
463 : /*
464 : * Puts |len| characters from |s| at the current position and return an offset to
465 : * the beginning of this new data
466 : */
467 : ptrdiff_t put(const char *s, size_t len);
468 : ptrdiff_t put(const char *s);
469 : ptrdiff_t putString(JSString *str);
470 :
471 : /* Prints a formatted string into the buffer */
472 : int printf(const char *fmt, ...);
473 :
474 : /* Change the offset */
475 : void setOffset(const char *end);
476 : void setOffset(ptrdiff_t off);
477 :
478 : /* Get the offset */
479 : ptrdiff_t getOffset() const;
480 : ptrdiff_t getOffsetOf(const char *string) const;
481 : };
482 :
483 : extern ptrdiff_t
484 : Sprint(Sprinter *sp, const char *format, ...);
485 :
486 : extern bool
487 : CallResultEscapes(jsbytecode *pc);
488 :
489 : static inline unsigned
490 132 : GetDecomposeLength(jsbytecode *pc, size_t len)
491 : {
492 : /*
493 : * The last byte of a DECOMPOSE op stores the decomposed length. This is a
494 : * constant: perhaps we should just hardcode values instead?
495 : */
496 132 : JS_ASSERT(size_t(js_CodeSpec[*pc].length) == len);
497 132 : return (unsigned) pc[len - 1];
498 : }
499 :
500 : static inline unsigned
501 1033028625 : GetBytecodeLength(jsbytecode *pc)
502 : {
503 1033028625 : JSOp op = (JSOp)*pc;
504 1033028625 : JS_ASSERT(op < JSOP_LIMIT);
505 :
506 1033028625 : if (js_CodeSpec[op].length != -1)
507 1033017460 : return js_CodeSpec[op].length;
508 11165 : return js_GetVariableBytecodeLength(pc);
509 : }
510 :
511 : extern bool
512 : IsValidBytecodeOffset(JSContext *cx, JSScript *script, size_t offset);
513 :
514 : inline bool
515 2969977 : FlowsIntoNext(JSOp op)
516 : {
517 : /* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
518 : return op != JSOP_STOP && op != JSOP_RETURN && op != JSOP_RETRVAL && op != JSOP_THROW &&
519 2969977 : op != JSOP_GOTO && op != JSOP_RETSUB;
520 : }
521 :
522 : /*
523 : * Counts accumulated for a single opcode in a script. The counts tracked vary
524 : * between opcodes, and this structure ensures that counts are accessed in
525 : * a coherent fashion.
526 : */
527 : class OpcodeCounts
528 : {
529 : friend struct ::JSScript;
530 : double *counts;
531 : #ifdef DEBUG
532 : size_t capacity;
533 : #endif
534 :
535 : public:
536 :
537 : enum BaseCounts {
538 : BASE_INTERP = 0,
539 : BASE_METHODJIT,
540 :
541 : BASE_METHODJIT_STUBS,
542 : BASE_METHODJIT_CODE,
543 : BASE_METHODJIT_PICS,
544 :
545 : BASE_COUNT
546 : };
547 :
548 : enum AccessCounts {
549 : ACCESS_MONOMORPHIC = BASE_COUNT,
550 : ACCESS_DIMORPHIC,
551 : ACCESS_POLYMORPHIC,
552 :
553 : ACCESS_BARRIER,
554 : ACCESS_NOBARRIER,
555 :
556 : ACCESS_UNDEFINED,
557 : ACCESS_NULL,
558 : ACCESS_BOOLEAN,
559 : ACCESS_INT32,
560 : ACCESS_DOUBLE,
561 : ACCESS_STRING,
562 : ACCESS_OBJECT,
563 :
564 : ACCESS_COUNT
565 : };
566 :
567 0 : static bool accessOp(JSOp op) {
568 : /*
569 : * Access ops include all name, element and property reads, as well as
570 : * SETELEM and SETPROP (for ElementCounts/PropertyCounts alignment).
571 : */
572 0 : if (op == JSOP_SETELEM || op == JSOP_SETPROP || op == JSOP_SETMETHOD)
573 0 : return true;
574 0 : int format = js_CodeSpec[op].format;
575 0 : return !!(format & (JOF_NAME | JOF_GNAME | JOF_ELEM | JOF_PROP))
576 0 : && !(format & (JOF_SET | JOF_INCDEC));
577 : }
578 :
579 : enum ElementCounts {
580 : ELEM_ID_INT = ACCESS_COUNT,
581 : ELEM_ID_DOUBLE,
582 : ELEM_ID_OTHER,
583 : ELEM_ID_UNKNOWN,
584 :
585 : ELEM_OBJECT_TYPED,
586 : ELEM_OBJECT_PACKED,
587 : ELEM_OBJECT_DENSE,
588 : ELEM_OBJECT_OTHER,
589 :
590 : ELEM_COUNT
591 : };
592 :
593 0 : static bool elementOp(JSOp op) {
594 0 : return accessOp(op) && (JOF_MODE(js_CodeSpec[op].format) == JOF_ELEM);
595 : }
596 :
597 : enum PropertyCounts {
598 : PROP_STATIC = ACCESS_COUNT,
599 : PROP_DEFINITE,
600 : PROP_OTHER,
601 :
602 : PROP_COUNT
603 : };
604 :
605 0 : static bool propertyOp(JSOp op) {
606 0 : return accessOp(op) && (JOF_MODE(js_CodeSpec[op].format) == JOF_PROP);
607 : }
608 :
609 : enum ArithCounts {
610 : ARITH_INT = BASE_COUNT,
611 : ARITH_DOUBLE,
612 : ARITH_OTHER,
613 : ARITH_UNKNOWN,
614 :
615 : ARITH_COUNT
616 : };
617 :
618 0 : static bool arithOp(JSOp op) {
619 0 : return !!(js_CodeSpec[op].format & (JOF_INCDEC | JOF_ARITH));
620 : }
621 :
622 0 : static size_t numCounts(JSOp op)
623 : {
624 0 : if (accessOp(op)) {
625 0 : if (elementOp(op))
626 0 : return ELEM_COUNT;
627 0 : if (propertyOp(op))
628 0 : return PROP_COUNT;
629 0 : return ACCESS_COUNT;
630 : }
631 0 : if (arithOp(op))
632 0 : return ARITH_COUNT;
633 0 : return BASE_COUNT;
634 : }
635 :
636 : static const char *countName(JSOp op, size_t which);
637 :
638 0 : double *rawCounts() { return counts; }
639 :
640 0 : double& get(size_t which) {
641 0 : JS_ASSERT(which < capacity);
642 0 : return counts[which];
643 : }
644 :
645 : /* Boolean conversion, for 'if (counters) ...' */
646 0 : operator void*() const {
647 0 : return counts;
648 : }
649 : };
650 :
651 : } /* namespace js */
652 :
653 : #if defined(DEBUG)
654 : /*
655 : * Disassemblers, for debugging only.
656 : */
657 : extern JS_FRIEND_API(JSBool)
658 : js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, js::Sprinter *sp);
659 :
660 : extern JS_FRIEND_API(unsigned)
661 : js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, unsigned loc,
662 : JSBool lines, js::Sprinter *sp);
663 :
664 : extern JS_FRIEND_API(void)
665 : js_DumpPCCounts(JSContext *cx, JSScript *script, js::Sprinter *sp);
666 : #endif
667 :
668 : #endif /* jsopcode_h___ */
|