1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef jsopcode_h
8 #define jsopcode_h
9 
10 /*
11  * JS bytecode definitions.
12  */
13 
14 #include "mozilla/UniquePtr.h"
15 
16 #include "jsbytecode.h"
17 #include "jstypes.h"
18 #include "NamespaceImports.h"
19 
20 #include "frontend/SourceNotes.h"
21 #include "vm/Opcodes.h"
22 #include "vm/Printer.h"
23 
24 /*
25  * JS operation bytecodes.
26  */
27 typedef enum JSOp {
28 #define ENUMERATE_OPCODE(op, val, ...) op = val,
29 FOR_EACH_OPCODE(ENUMERATE_OPCODE)
30 #undef ENUMERATE_OPCODE
31 
32     JSOP_LIMIT
33 } JSOp;
34 
35 /*
36  * JS bytecode formats.
37  */
38 enum {
39     JOF_BYTE            = 0,        /* single bytecode, no immediates */
40     JOF_JUMP            = 1,        /* signed 16-bit jump offset immediate */
41     JOF_ATOM            = 2,        /* unsigned 16-bit constant index */
42     JOF_UINT16          = 3,        /* unsigned 16-bit immediate operand */
43     JOF_TABLESWITCH     = 4,        /* table switch */
44     /* 5 is unused */
45     JOF_QARG            = 6,        /* quickened get/set function argument ops */
46     JOF_LOCAL           = 7,        /* var or block-local variable */
47     JOF_DOUBLE          = 8,        /* uint32_t index for double value */
48     JOF_UINT24          = 12,       /* extended unsigned 24-bit literal (index) */
49     JOF_UINT8           = 13,       /* uint8_t immediate, e.g. top 8 bits of 24-bit
50                                        atom index */
51     JOF_INT32           = 14,       /* int32_t immediate operand */
52     JOF_UINT32          = 15,       /* uint32_t immediate operand */
53     JOF_OBJECT          = 16,       /* unsigned 16-bit object index */
54     JOF_REGEXP          = 17,       /* unsigned 32-bit regexp index */
55     JOF_INT8            = 18,       /* int8_t immediate operand */
56     JOF_ATOMOBJECT      = 19,       /* uint16_t constant index + object index */
57     /* 20 is unused */
58     JOF_SCOPECOORD      = 21,       /* embedded ScopeCoordinate immediate */
59     JOF_TYPEMASK        = 0x001f,   /* mask for above immediate types */
60 
61     JOF_NAME            = 1 << 5,   /* name operation */
62     JOF_PROP            = 2 << 5,   /* obj.prop operation */
63     JOF_ELEM            = 3 << 5,   /* obj[index] operation */
64     JOF_MODEMASK        = 7 << 5,   /* mask for above addressing modes */
65     JOF_SET             = 1 << 8,   /* set (i.e., assignment) operation */
66     /* 1 << 9 is unused */
67     /* 1 << 10 is unused */
68     /* 1 << 11 is unused */
69     /* 1 << 12 is unused */
70     /* 1 << 13 is unused */
71     JOF_DETECTING       = 1 << 14,  /* object detection for warning-quelling */
72     /* 1 << 15 is unused */
73     JOF_LEFTASSOC       = 1 << 16,  /* left-associative operator */
74     /* 1 << 17 is unused */
75     /* 1 << 18 is unused */
76     JOF_CHECKSLOPPY     = 1 << 19,  /* Op can only be generated in sloppy mode */
77     JOF_CHECKSTRICT     = 1 << 20,  /* Op can only be generated in strict mode */
78     JOF_INVOKE          = 1 << 21,  /* JSOP_CALL, JSOP_FUNCALL, JSOP_FUNAPPLY,
79                                        JSOP_NEW, JSOP_EVAL, JSOP_CALLITER */
80     /* 1 << 22 is unused */
81     /* 1 << 23 is unused */
82     /* 1 << 24 is unused */
83     JOF_GNAME           = 1 << 25,  /* predicted global name */
84     JOF_TYPESET         = 1 << 26,  /* has an entry in a script's type sets */
85     JOF_ARITH           = 1 << 27   /* unary or binary arithmetic opcode */
86 };
87 
88 /* Shorthand for type from format. */
89 
90 static inline uint32_t
JOF_TYPE(uint32_t fmt)91 JOF_TYPE(uint32_t fmt)
92 {
93     return fmt & JOF_TYPEMASK;
94 }
95 
96 /* Shorthand for mode from format. */
97 
98 static inline uint32_t
JOF_MODE(uint32_t fmt)99 JOF_MODE(uint32_t fmt)
100 {
101     return fmt & JOF_MODEMASK;
102 }
103 
104 /*
105  * Immediate operand getters, setters, and bounds.
106  */
107 
108 static MOZ_ALWAYS_INLINE uint8_t
GET_UINT8(jsbytecode * pc)109 GET_UINT8(jsbytecode* pc)
110 {
111     return uint8_t(pc[1]);
112 }
113 
114 static MOZ_ALWAYS_INLINE void
SET_UINT8(jsbytecode * pc,uint8_t u)115 SET_UINT8(jsbytecode* pc, uint8_t u)
116 {
117     pc[1] = jsbytecode(u);
118 }
119 
120 /* Common uint16_t immediate format helpers. */
121 
122 static inline jsbytecode
UINT16_HI(uint16_t i)123 UINT16_HI(uint16_t i)
124 {
125     return jsbytecode(i >> 8);
126 }
127 
128 static inline jsbytecode
UINT16_LO(uint16_t i)129 UINT16_LO(uint16_t i)
130 {
131     return jsbytecode(i);
132 }
133 
134 static MOZ_ALWAYS_INLINE uint16_t
GET_UINT16(const jsbytecode * pc)135 GET_UINT16(const jsbytecode* pc)
136 {
137     return uint16_t((pc[1] << 8) | pc[2]);
138 }
139 
140 static MOZ_ALWAYS_INLINE void
SET_UINT16(jsbytecode * pc,uint16_t i)141 SET_UINT16(jsbytecode* pc, uint16_t i)
142 {
143     pc[1] = UINT16_HI(i);
144     pc[2] = UINT16_LO(i);
145 }
146 
147 static const unsigned UINT16_LEN        = 2;
148 static const unsigned UINT16_LIMIT      = 1 << 16;
149 
150 /* Helpers for accessing the offsets of jump opcodes. */
151 static const unsigned JUMP_OFFSET_LEN   = 4;
152 static const int32_t JUMP_OFFSET_MIN    = INT32_MIN;
153 static const int32_t JUMP_OFFSET_MAX    = INT32_MAX;
154 
155 static MOZ_ALWAYS_INLINE int32_t
GET_JUMP_OFFSET(jsbytecode * pc)156 GET_JUMP_OFFSET(jsbytecode* pc)
157 {
158     return (pc[1] << 24) | (pc[2] << 16) | (pc[3] << 8) | pc[4];
159 }
160 
161 static MOZ_ALWAYS_INLINE void
SET_JUMP_OFFSET(jsbytecode * pc,int32_t off)162 SET_JUMP_OFFSET(jsbytecode* pc, int32_t off)
163 {
164     pc[1] = jsbytecode(off >> 24);
165     pc[2] = jsbytecode(off >> 16);
166     pc[3] = jsbytecode(off >> 8);
167     pc[4] = jsbytecode(off);
168 }
169 
170 static const unsigned UINT32_INDEX_LEN  = 4;
171 
172 static MOZ_ALWAYS_INLINE uint32_t
GET_UINT32_INDEX(const jsbytecode * pc)173 GET_UINT32_INDEX(const jsbytecode* pc)
174 {
175     return (pc[1] << 24) | (pc[2] << 16) | (pc[3] << 8) | pc[4];
176 }
177 
178 static MOZ_ALWAYS_INLINE void
SET_UINT32_INDEX(jsbytecode * pc,uint32_t index)179 SET_UINT32_INDEX(jsbytecode* pc, uint32_t index)
180 {
181     pc[1] = jsbytecode(index >> 24);
182     pc[2] = jsbytecode(index >> 16);
183     pc[3] = jsbytecode(index >> 8);
184     pc[4] = jsbytecode(index);
185 }
186 
187 static inline jsbytecode
UINT24_HI(unsigned i)188 UINT24_HI(unsigned i)
189 {
190     return jsbytecode(i >> 16);
191 }
192 
193 static inline jsbytecode
UINT24_MID(unsigned i)194 UINT24_MID(unsigned i)
195 {
196     return jsbytecode(i >> 8);
197 }
198 
199 static inline jsbytecode
UINT24_LO(unsigned i)200 UINT24_LO(unsigned i)
201 {
202     return jsbytecode(i);
203 }
204 
205 static MOZ_ALWAYS_INLINE unsigned
GET_UINT24(const jsbytecode * pc)206 GET_UINT24(const jsbytecode* pc)
207 {
208     return unsigned((pc[1] << 16) | (pc[2] << 8) | pc[3]);
209 }
210 
211 static MOZ_ALWAYS_INLINE void
SET_UINT24(jsbytecode * pc,unsigned i)212 SET_UINT24(jsbytecode* pc, unsigned i)
213 {
214     MOZ_ASSERT(i < (1 << 24));
215     pc[1] = UINT24_HI(i);
216     pc[2] = UINT24_MID(i);
217     pc[3] = UINT24_LO(i);
218 }
219 
220 static MOZ_ALWAYS_INLINE int8_t
GET_INT8(const jsbytecode * pc)221 GET_INT8(const jsbytecode* pc)
222 {
223     return int8_t(pc[1]);
224 }
225 
226 static MOZ_ALWAYS_INLINE uint32_t
GET_UINT32(const jsbytecode * pc)227 GET_UINT32(const jsbytecode* pc)
228 {
229     return  (uint32_t(pc[1]) << 24) |
230             (uint32_t(pc[2]) << 16) |
231             (uint32_t(pc[3]) << 8)  |
232             uint32_t(pc[4]);
233 }
234 
235 static MOZ_ALWAYS_INLINE void
SET_UINT32(jsbytecode * pc,uint32_t u)236 SET_UINT32(jsbytecode* pc, uint32_t u)
237 {
238     pc[1] = jsbytecode(u >> 24);
239     pc[2] = jsbytecode(u >> 16);
240     pc[3] = jsbytecode(u >> 8);
241     pc[4] = jsbytecode(u);
242 }
243 
244 static MOZ_ALWAYS_INLINE int32_t
GET_INT32(const jsbytecode * pc)245 GET_INT32(const jsbytecode* pc)
246 {
247     return static_cast<int32_t>(GET_UINT32(pc));
248 }
249 
250 static MOZ_ALWAYS_INLINE void
SET_INT32(jsbytecode * pc,int32_t i)251 SET_INT32(jsbytecode* pc, int32_t i)
252 {
253     SET_UINT32(pc, static_cast<uint32_t>(i));
254 }
255 
256 /* Index limit is determined by SN_4BYTE_OFFSET_FLAG, see frontend/BytecodeEmitter.h. */
257 static const unsigned INDEX_LIMIT_LOG2  = 31;
258 static const uint32_t INDEX_LIMIT       = uint32_t(1) << INDEX_LIMIT_LOG2;
259 
260 static inline jsbytecode
ARGC_HI(uint16_t argc)261 ARGC_HI(uint16_t argc)
262 {
263     return UINT16_HI(argc);
264 }
265 
266 static inline jsbytecode
ARGC_LO(uint16_t argc)267 ARGC_LO(uint16_t argc)
268 {
269     return UINT16_LO(argc);
270 }
271 
272 static inline uint16_t
GET_ARGC(const jsbytecode * pc)273 GET_ARGC(const jsbytecode* pc)
274 {
275     return GET_UINT16(pc);
276 }
277 
278 static const unsigned ARGC_LIMIT        = UINT16_LIMIT;
279 
280 static inline uint16_t
GET_ARGNO(const jsbytecode * pc)281 GET_ARGNO(const jsbytecode* pc)
282 {
283     return GET_UINT16(pc);
284 }
285 
286 static inline void
SET_ARGNO(jsbytecode * pc,uint16_t argno)287 SET_ARGNO(jsbytecode* pc, uint16_t argno)
288 {
289     SET_UINT16(pc, argno);
290 }
291 
292 static const unsigned ARGNO_LEN         = 2;
293 static const unsigned ARGNO_LIMIT       = UINT16_LIMIT;
294 
295 static inline uint32_t
GET_LOCALNO(const jsbytecode * pc)296 GET_LOCALNO(const jsbytecode* pc)
297 {
298     return GET_UINT24(pc);
299 }
300 
301 static inline void
SET_LOCALNO(jsbytecode * pc,uint32_t varno)302 SET_LOCALNO(jsbytecode* pc, uint32_t varno)
303 {
304     SET_UINT24(pc, varno);
305 }
306 
307 static const unsigned LOCALNO_LEN       = 3;
308 static const unsigned LOCALNO_BITS      = 24;
309 static const uint32_t LOCALNO_LIMIT     = 1 << LOCALNO_BITS;
310 
311 static inline unsigned
LoopEntryDepthHint(jsbytecode * pc)312 LoopEntryDepthHint(jsbytecode* pc)
313 {
314     MOZ_ASSERT(*pc == JSOP_LOOPENTRY);
315     return GET_UINT8(pc) & 0x7f;
316 }
317 
318 static inline bool
LoopEntryCanIonOsr(jsbytecode * pc)319 LoopEntryCanIonOsr(jsbytecode* pc)
320 {
321     MOZ_ASSERT(*pc == JSOP_LOOPENTRY);
322     return GET_UINT8(pc) & 0x80;
323 }
324 
325 static inline uint8_t
PackLoopEntryDepthHintAndFlags(unsigned loopDepth,bool canIonOsr)326 PackLoopEntryDepthHintAndFlags(unsigned loopDepth, bool canIonOsr)
327 {
328     return (loopDepth < 0x80 ? uint8_t(loopDepth) : 0x7f) | (canIonOsr ? 0x80 : 0);
329 }
330 
331 /*
332  * Describes the 'hops' component of a JOF_SCOPECOORD opcode.
333  *
334  * Note: this component is only 8 bits wide, limiting the maximum number of
335  * scopes between a use and def to roughly 255. This is a pretty small limit but
336  * note that SpiderMonkey's recursive descent parser can only parse about this
337  * many functions before hitting the C-stack recursion limit so this shouldn't
338  * be a significant limitation in practice.
339  */
340 
341 static inline uint8_t
GET_SCOPECOORD_HOPS(jsbytecode * pc)342 GET_SCOPECOORD_HOPS(jsbytecode* pc)
343 {
344     return GET_UINT8(pc);
345 }
346 
347 static inline void
SET_SCOPECOORD_HOPS(jsbytecode * pc,uint8_t hops)348 SET_SCOPECOORD_HOPS(jsbytecode* pc, uint8_t hops)
349 {
350     SET_UINT8(pc, hops);
351 }
352 
353 static const unsigned SCOPECOORD_HOPS_LEN   = 1;
354 static const unsigned SCOPECOORD_HOPS_BITS  = 8;
355 static const unsigned SCOPECOORD_HOPS_LIMIT = 1 << SCOPECOORD_HOPS_BITS;
356 
357 /* Describes the 'slot' component of a JOF_SCOPECOORD opcode. */
358 static inline uint32_t
GET_SCOPECOORD_SLOT(const jsbytecode * pc)359 GET_SCOPECOORD_SLOT(const jsbytecode* pc)
360 {
361     return GET_UINT24(pc);
362 }
363 
364 static inline void
SET_SCOPECOORD_SLOT(jsbytecode * pc,uint32_t slot)365 SET_SCOPECOORD_SLOT(jsbytecode* pc, uint32_t slot)
366 {
367     SET_UINT24(pc, slot);
368 }
369 
370 static const unsigned SCOPECOORD_SLOT_LEN   = 3;
371 static const unsigned SCOPECOORD_SLOT_BITS  = 24;
372 static const uint32_t SCOPECOORD_SLOT_LIMIT = 1 << SCOPECOORD_SLOT_BITS;
373 
374 struct JSCodeSpec {
375     int8_t              length;         /* length including opcode byte */
376     int8_t              nuses;          /* arity, -1 if variadic */
377     int8_t              ndefs;          /* number of stack results */
378     uint32_t            format;         /* immediate operand format */
379 
typeJSCodeSpec380     uint32_t type() const { return JOF_TYPE(format); }
381 };
382 
383 /* Silence unreferenced formal parameter warnings */
384 #ifdef _MSC_VER
385 #pragma warning(push)
386 #pragma warning(disable:4100)
387 #endif
388 
389 namespace js {
390 
391 extern const JSCodeSpec CodeSpec[];
392 extern const unsigned   NumCodeSpecs;
393 extern const char       * const CodeName[];
394 
395 /* Shorthand for type from opcode. */
396 
397 static inline uint32_t
JOF_OPTYPE(JSOp op)398 JOF_OPTYPE(JSOp op)
399 {
400     return JOF_TYPE(CodeSpec[op].format);
401 }
402 
403 static inline bool
IsJumpOpcode(JSOp op)404 IsJumpOpcode(JSOp op)
405 {
406     uint32_t type = JOF_TYPE(CodeSpec[op].format);
407 
408     /*
409      * LABEL opcodes have type JOF_JUMP but are no-ops, don't treat them as
410      * jumps to avoid degrading precision.
411      */
412     return type == JOF_JUMP && op != JSOP_LABEL;
413 }
414 
415 static inline bool
BytecodeFallsThrough(JSOp op)416 BytecodeFallsThrough(JSOp op)
417 {
418     switch (op) {
419       case JSOP_GOTO:
420       case JSOP_DEFAULT:
421       case JSOP_RETURN:
422       case JSOP_RETRVAL:
423       case JSOP_FINALYIELDRVAL:
424       case JSOP_THROW:
425       case JSOP_TABLESWITCH:
426         return false;
427       case JSOP_GOSUB:
428         /* These fall through indirectly, after executing a 'finally'. */
429         return true;
430       default:
431         return true;
432     }
433 }
434 
435 class SrcNoteLineScanner
436 {
437     /* offset of the current JSOp in the bytecode */
438     ptrdiff_t offset;
439 
440     /* next src note to process */
441     jssrcnote* sn;
442 
443     /* line number of the current JSOp */
444     uint32_t lineno;
445 
446     /*
447      * Is the current op the first one after a line change directive? Note that
448      * multiple ops may be "first" if a line directive is used to return to a
449      * previous line (eg, with a for loop increment expression.)
450      */
451     bool lineHeader;
452 
453   public:
SrcNoteLineScanner(jssrcnote * sn,uint32_t lineno)454     SrcNoteLineScanner(jssrcnote* sn, uint32_t lineno)
455         : offset(0), sn(sn), lineno(lineno)
456     {
457     }
458 
459     /*
460      * This is called repeatedly with always-advancing relpc values. The src
461      * notes are tuples of <PC offset from prev src note, type, args>. Scan
462      * through, updating the lineno, until the next src note is for a later
463      * bytecode.
464      *
465      * When looking at the desired PC offset ('relpc'), the op is first in that
466      * line iff there is a SRC_SETLINE or SRC_NEWLINE src note for that exact
467      * bytecode.
468      *
469      * Note that a single bytecode may have multiple line-modifying notes (even
470      * though only one should ever be needed.)
471      */
advanceTo(ptrdiff_t relpc)472     void advanceTo(ptrdiff_t relpc) {
473         // Must always advance! If the same or an earlier PC is erroneously
474         // passed in, we will already be past the relevant src notes
475         MOZ_ASSERT_IF(offset > 0, relpc > offset);
476 
477         // Next src note should be for after the current offset
478         MOZ_ASSERT_IF(offset > 0, SN_IS_TERMINATOR(sn) || SN_DELTA(sn) > 0);
479 
480         // The first PC requested is always considered to be a line header
481         lineHeader = (offset == 0);
482 
483         if (SN_IS_TERMINATOR(sn))
484             return;
485 
486         ptrdiff_t nextOffset;
487         while ((nextOffset = offset + SN_DELTA(sn)) <= relpc && !SN_IS_TERMINATOR(sn)) {
488             offset = nextOffset;
489             SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
490             if (type == SRC_SETLINE || type == SRC_NEWLINE) {
491                 if (type == SRC_SETLINE)
492                     lineno = GetSrcNoteOffset(sn, 0);
493                 else
494                     lineno++;
495 
496                 if (offset == relpc)
497                     lineHeader = true;
498             }
499 
500             sn = SN_NEXT(sn);
501         }
502     }
503 
isLineHeader()504     bool isLineHeader() const {
505         return lineHeader;
506     }
507 
getLine()508     uint32_t getLine() const { return lineno; }
509 };
510 
511 extern unsigned
512 StackUses(JSScript* script, jsbytecode* pc);
513 
514 extern unsigned
515 StackDefs(JSScript* script, jsbytecode* pc);
516 
517 #ifdef DEBUG
518 /*
519  * Given bytecode address pc in script's main program code, compute the operand
520  * stack depth just before (JSOp) *pc executes.  If *pc is not reachable, return
521  * false.
522  */
523 extern bool
524 ReconstructStackDepth(JSContext* cx, JSScript* script, jsbytecode* pc, uint32_t* depth, bool* reachablePC);
525 #endif
526 
527 }  /* namespace js */
528 
529 #ifdef _MSC_VER
530 #pragma warning(pop)
531 #endif
532 
533 #define JSDVG_IGNORE_STACK      0
534 #define JSDVG_SEARCH_STACK      1
535 
536 namespace js {
537 
538 /*
539  * Get the length of variable-length bytecode like JSOP_TABLESWITCH.
540  */
541 extern size_t
542 GetVariableBytecodeLength(jsbytecode* pc);
543 
544 /*
545  * Find the source expression that resulted in v, and return a newly allocated
546  * C-string containing it.  Fall back on v's string conversion (fallback) if we
547  * can't find the bytecode that generated and pushed v on the operand stack.
548  *
549  * Search the current stack frame if spindex is JSDVG_SEARCH_STACK.  Don't
550  * look for v on the stack if spindex is JSDVG_IGNORE_STACK.  Otherwise,
551  * spindex is the negative index of v, measured from cx->fp->sp, or from a
552  * lower frame's sp if cx->fp is native.
553  *
554  * The optional argument skipStackHits can be used to skip a hit in the stack
555  * frame. This can be useful in self-hosted code that wants to report value
556  * errors containing decompiled values that are useful for the user, instead of
557  * values used internally by the self-hosted code.
558  *
559  * The caller must call JS_free on the result after a successful call.
560  */
561 mozilla::UniquePtr<char[], JS::FreePolicy>
562 DecompileValueGenerator(JSContext* cx, int spindex, HandleValue v,
563                         HandleString fallback, int skipStackHits = 0);
564 
565 /*
566  * Decompile the formal argument at formalIndex in the nearest non-builtin
567  * stack frame, falling back with converting v to source.
568  */
569 char*
570 DecompileArgument(JSContext* cx, int formalIndex, HandleValue v);
571 
572 extern bool
573 CallResultEscapes(jsbytecode* pc);
574 
575 static inline unsigned
GetDecomposeLength(jsbytecode * pc,size_t len)576 GetDecomposeLength(jsbytecode* pc, size_t len)
577 {
578     /*
579      * The last byte of a DECOMPOSE op stores the decomposed length.  This is a
580      * constant: perhaps we should just hardcode values instead?
581      */
582     MOZ_ASSERT(size_t(CodeSpec[*pc].length) == len);
583     return (unsigned) pc[len - 1];
584 }
585 
586 static inline unsigned
GetBytecodeLength(jsbytecode * pc)587 GetBytecodeLength(jsbytecode* pc)
588 {
589     JSOp op = (JSOp)*pc;
590     MOZ_ASSERT(op < JSOP_LIMIT);
591 
592     if (CodeSpec[op].length != -1)
593         return CodeSpec[op].length;
594     return GetVariableBytecodeLength(pc);
595 }
596 
597 static inline bool
BytecodeIsPopped(jsbytecode * pc)598 BytecodeIsPopped(jsbytecode* pc)
599 {
600     jsbytecode* next = pc + GetBytecodeLength(pc);
601     return JSOp(*next) == JSOP_POP;
602 }
603 
604 static inline bool
BytecodeFlowsToBitop(jsbytecode * pc)605 BytecodeFlowsToBitop(jsbytecode* pc)
606 {
607     // Look for simple bytecode for integer conversions like (x | 0) or (x & -1).
608     jsbytecode* next = pc + GetBytecodeLength(pc);
609     if (*next == JSOP_BITOR || *next == JSOP_BITAND)
610         return true;
611     if (*next == JSOP_INT8 && GET_INT8(next) == -1) {
612         next += GetBytecodeLength(next);
613         if (*next == JSOP_BITAND)
614             return true;
615         return false;
616     }
617     if (*next == JSOP_ONE) {
618         next += GetBytecodeLength(next);
619         if (*next == JSOP_NEG) {
620             next += GetBytecodeLength(next);
621             if (*next == JSOP_BITAND)
622                 return true;
623         }
624         return false;
625     }
626     if (*next == JSOP_ZERO) {
627         next += GetBytecodeLength(next);
628         if (*next == JSOP_BITOR)
629             return true;
630         return false;
631     }
632     return false;
633 }
634 
635 extern bool
636 IsValidBytecodeOffset(JSContext* cx, JSScript* script, size_t offset);
637 
638 inline bool
FlowsIntoNext(JSOp op)639 FlowsIntoNext(JSOp op)
640 {
641     /* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
642     switch (op) {
643       case JSOP_RETRVAL:
644       case JSOP_RETURN:
645       case JSOP_THROW:
646       case JSOP_GOTO:
647       case JSOP_RETSUB:
648       case JSOP_FINALYIELDRVAL:
649         return false;
650       default:
651         return true;
652     }
653 }
654 
655 inline bool
IsArgOp(JSOp op)656 IsArgOp(JSOp op)
657 {
658     return JOF_OPTYPE(op) == JOF_QARG;
659 }
660 
661 inline bool
IsLocalOp(JSOp op)662 IsLocalOp(JSOp op)
663 {
664     return JOF_OPTYPE(op) == JOF_LOCAL;
665 }
666 
667 inline bool
IsAliasedVarOp(JSOp op)668 IsAliasedVarOp(JSOp op)
669 {
670     return JOF_OPTYPE(op) == JOF_SCOPECOORD;
671 }
672 
673 inline bool
IsGlobalOp(JSOp op)674 IsGlobalOp(JSOp op)
675 {
676     return CodeSpec[op].format & JOF_GNAME;
677 }
678 
679 inline bool
IsEqualityOp(JSOp op)680 IsEqualityOp(JSOp op)
681 {
682     return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
683 }
684 
685 inline bool
IsCheckStrictOp(JSOp op)686 IsCheckStrictOp(JSOp op)
687 {
688     return CodeSpec[op].format & JOF_CHECKSTRICT;
689 }
690 
691 #ifdef DEBUG
692 inline bool
IsCheckSloppyOp(JSOp op)693 IsCheckSloppyOp(JSOp op)
694 {
695     return CodeSpec[op].format & JOF_CHECKSLOPPY;
696 }
697 #endif
698 
699 inline bool
IsAtomOp(JSOp op)700 IsAtomOp(JSOp op)
701 {
702     return JOF_OPTYPE(op) == JOF_ATOM;
703 }
704 
705 inline bool
IsGetPropPC(jsbytecode * pc)706 IsGetPropPC(jsbytecode* pc)
707 {
708     JSOp op = JSOp(*pc);
709     return op == JSOP_LENGTH  || op == JSOP_GETPROP || op == JSOP_CALLPROP;
710 }
711 
712 inline bool
IsHiddenInitOp(JSOp op)713 IsHiddenInitOp(JSOp op)
714 {
715     return op == JSOP_INITHIDDENPROP || op == JSOP_INITHIDDENELEM ||
716            op == JSOP_INITHIDDENPROP_GETTER || op == JSOP_INITHIDDENELEM_GETTER ||
717            op == JSOP_INITHIDDENPROP_SETTER || op == JSOP_INITHIDDENELEM_SETTER;
718 }
719 
720 inline bool
IsStrictSetPC(jsbytecode * pc)721 IsStrictSetPC(jsbytecode* pc)
722 {
723     JSOp op = JSOp(*pc);
724     return op == JSOP_STRICTSETPROP ||
725            op == JSOP_STRICTSETNAME ||
726            op == JSOP_STRICTSETGNAME ||
727            op == JSOP_STRICTSETELEM;
728 }
729 
730 inline bool
IsSetPropPC(jsbytecode * pc)731 IsSetPropPC(jsbytecode* pc)
732 {
733     JSOp op = JSOp(*pc);
734     return op == JSOP_SETPROP || op == JSOP_STRICTSETPROP ||
735            op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
736            op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME;
737 }
738 
739 inline bool
IsGetElemPC(jsbytecode * pc)740 IsGetElemPC(jsbytecode* pc)
741 {
742     JSOp op = JSOp(*pc);
743     return op == JSOP_GETELEM || op == JSOP_CALLELEM;
744 }
745 
746 inline bool
IsSetElemPC(jsbytecode * pc)747 IsSetElemPC(jsbytecode* pc)
748 {
749     JSOp op = JSOp(*pc);
750     return op == JSOP_SETELEM ||
751            op == JSOP_STRICTSETELEM;
752 }
753 
754 inline bool
IsCallPC(jsbytecode * pc)755 IsCallPC(jsbytecode* pc)
756 {
757     return CodeSpec[*pc].format & JOF_INVOKE;
758 }
759 
760 inline bool
IsStrictEvalPC(jsbytecode * pc)761 IsStrictEvalPC(jsbytecode* pc)
762 {
763     JSOp op = JSOp(*pc);
764     return op == JSOP_STRICTEVAL || op == JSOP_STRICTSPREADEVAL;
765 }
766 
767 static inline int32_t
GetBytecodeInteger(jsbytecode * pc)768 GetBytecodeInteger(jsbytecode* pc)
769 {
770     switch (JSOp(*pc)) {
771       case JSOP_ZERO:   return 0;
772       case JSOP_ONE:    return 1;
773       case JSOP_UINT16: return GET_UINT16(pc);
774       case JSOP_UINT24: return GET_UINT24(pc);
775       case JSOP_INT8:   return GET_INT8(pc);
776       case JSOP_INT32:  return GET_INT32(pc);
777       default:
778         MOZ_CRASH("Bad op");
779     }
780 }
781 
782 /*
783  * Counts accumulated for a single opcode in a script. The counts tracked vary
784  * between opcodes, and this structure ensures that counts are accessed in a
785  * coherent fashion.
786  */
787 class PCCounts
788 {
789     /*
790      * Offset of the pc inside the script. This fields is used to lookup opcode
791      * which have annotations.
792      */
793     size_t pcOffset_;
794 
795     /*
796      * Record the number of execution of one instruction, or the number of
797      * throws executed.
798      */
799     uint64_t numExec_;
800 
801  public:
PCCounts(size_t off)802     explicit PCCounts(size_t off)
803       : pcOffset_(off),
804         numExec_(0)
805     {}
806 
pcOffset()807     size_t pcOffset() const {
808         return pcOffset_;
809     }
810 
811     // Used for sorting and searching.
812     bool operator<(const PCCounts& rhs) const {
813         return pcOffset_ < rhs.pcOffset_;
814     }
815 
numExec()816     uint64_t& numExec() {
817         return numExec_;
818     }
numExec()819     uint64_t numExec() const {
820         return numExec_;
821     }
822 
823     static const char* numExecName;
824 };
825 
826 static inline jsbytecode*
GetNextPc(jsbytecode * pc)827 GetNextPc(jsbytecode* pc)
828 {
829     return pc + GetBytecodeLength(pc);
830 }
831 
832 #if defined(DEBUG)
833 /*
834  * Disassemblers, for debugging only.
835  */
836 bool
837 Disassemble(JSContext* cx, JS::Handle<JSScript*> script, bool lines, Sprinter* sp);
838 
839 unsigned
840 Disassemble1(JSContext* cx, JS::Handle<JSScript*> script, jsbytecode* pc, unsigned loc,
841              bool lines, Sprinter* sp);
842 
843 #endif
844 
845 void
846 DumpPCCounts(JSContext* cx, JS::Handle<JSScript*> script, Sprinter* sp);
847 
848 namespace jit { struct IonScriptCounts; }
849 void
850 DumpIonScriptCounts(js::Sprinter* sp, jit::IonScriptCounts* ionCounts);
851 
852 void
853 DumpCompartmentPCCounts(JSContext* cx);
854 } // namespace js
855 
856 #endif /* jsopcode_h */
857