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