summaryrefslogtreecommitdiffstats
path: root/js/src/jsopcode.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsopcode.h')
-rw-r--r--js/src/jsopcode.h866
1 files changed, 866 insertions, 0 deletions
diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h
new file mode 100644
index 000000000..4f7859665
--- /dev/null
+++ b/js/src/jsopcode.h
@@ -0,0 +1,866 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jsopcode_h
+#define jsopcode_h
+
+/*
+ * JS bytecode definitions.
+ */
+
+#include "mozilla/Attributes.h"
+
+#include "jsbytecode.h"
+#include "jstypes.h"
+#include "NamespaceImports.h"
+
+#include "frontend/SourceNotes.h"
+#include "js/UniquePtr.h"
+#include "vm/Opcodes.h"
+#include "vm/Printer.h"
+
+/*
+ * JS operation bytecodes.
+ */
+typedef enum JSOp {
+#define ENUMERATE_OPCODE(op, val, ...) op = val,
+FOR_EACH_OPCODE(ENUMERATE_OPCODE)
+#undef ENUMERATE_OPCODE
+
+ JSOP_LIMIT
+} JSOp;
+
+/*
+ * JS bytecode formats.
+ */
+enum {
+ JOF_BYTE = 0, /* single bytecode, no immediates */
+ JOF_JUMP = 1, /* signed 16-bit jump offset immediate */
+ JOF_ATOM = 2, /* unsigned 16-bit constant index */
+ JOF_UINT16 = 3, /* unsigned 16-bit immediate operand */
+ JOF_TABLESWITCH = 4, /* table switch */
+ /* 5 is unused */
+ JOF_QARG = 6, /* quickened get/set function argument ops */
+ JOF_LOCAL = 7, /* var or block-local variable */
+ JOF_DOUBLE = 8, /* uint32_t index for double value */
+ JOF_UINT24 = 12, /* extended unsigned 24-bit literal (index) */
+ JOF_UINT8 = 13, /* uint8_t immediate, e.g. top 8 bits of 24-bit
+ atom index */
+ JOF_INT32 = 14, /* int32_t immediate operand */
+ JOF_UINT32 = 15, /* uint32_t immediate operand */
+ JOF_OBJECT = 16, /* unsigned 32-bit object index */
+ JOF_REGEXP = 17, /* unsigned 32-bit regexp index */
+ JOF_INT8 = 18, /* int8_t immediate operand */
+ JOF_ATOMOBJECT = 19, /* uint16_t constant index + object index */
+ JOF_SCOPE = 20, /* unsigned 32-bit scope index */
+ JOF_ENVCOORD = 21, /* embedded ScopeCoordinate immediate */
+ JOF_TYPEMASK = 0x001f, /* mask for above immediate types */
+
+ JOF_NAME = 1 << 5, /* name operation */
+ JOF_PROP = 2 << 5, /* obj.prop operation */
+ JOF_ELEM = 3 << 5, /* obj[index] operation */
+ JOF_MODEMASK = 7 << 5, /* mask for above addressing modes */
+ JOF_SET = 1 << 8, /* set (i.e., assignment) operation */
+ /* 1 << 9 is unused */
+ /* 1 << 10 is unused */
+ /* 1 << 11 is unused */
+ /* 1 << 12 is unused */
+ /* 1 << 13 is unused */
+ JOF_DETECTING = 1 << 14, /* object detection for warning-quelling */
+ /* 1 << 15 is unused */
+ JOF_LEFTASSOC = 1 << 16, /* left-associative operator */
+ /* 1 << 17 is unused */
+ /* 1 << 18 is unused */
+ JOF_CHECKSLOPPY = 1 << 19, /* Op can only be generated in sloppy mode */
+ JOF_CHECKSTRICT = 1 << 20, /* Op can only be generated in strict mode */
+ JOF_INVOKE = 1 << 21, /* JSOP_CALL, JSOP_FUNCALL, JSOP_FUNAPPLY,
+ JSOP_NEW, JSOP_EVAL, JSOP_CALLITER */
+ /* 1 << 22 is unused */
+ /* 1 << 23 is unused */
+ /* 1 << 24 is unused */
+ JOF_GNAME = 1 << 25, /* predicted global name */
+ JOF_TYPESET = 1 << 26, /* has an entry in a script's type sets */
+ JOF_ARITH = 1 << 27 /* unary or binary arithmetic opcode */
+};
+
+/* Shorthand for type from format. */
+
+static inline uint32_t
+JOF_TYPE(uint32_t fmt)
+{
+ return fmt & JOF_TYPEMASK;
+}
+
+/* Shorthand for mode from format. */
+
+static inline uint32_t
+JOF_MODE(uint32_t fmt)
+{
+ return fmt & JOF_MODEMASK;
+}
+
+/*
+ * Immediate operand getters, setters, and bounds.
+ */
+
+static MOZ_ALWAYS_INLINE uint8_t
+GET_UINT8(jsbytecode* pc)
+{
+ return uint8_t(pc[1]);
+}
+
+static MOZ_ALWAYS_INLINE void
+SET_UINT8(jsbytecode* pc, uint8_t u)
+{
+ pc[1] = jsbytecode(u);
+}
+
+/* Common uint16_t immediate format helpers. */
+
+static inline jsbytecode
+UINT16_HI(uint16_t i)
+{
+ return jsbytecode(i >> 8);
+}
+
+static inline jsbytecode
+UINT16_LO(uint16_t i)
+{
+ return jsbytecode(i);
+}
+
+static MOZ_ALWAYS_INLINE uint16_t
+GET_UINT16(const jsbytecode* pc)
+{
+ return uint16_t((pc[1] << 8) | pc[2]);
+}
+
+static MOZ_ALWAYS_INLINE void
+SET_UINT16(jsbytecode* pc, uint16_t i)
+{
+ pc[1] = UINT16_HI(i);
+ pc[2] = UINT16_LO(i);
+}
+
+static const unsigned UINT16_LEN = 2;
+static const unsigned UINT16_LIMIT = 1 << 16;
+
+/* Helpers for accessing the offsets of jump opcodes. */
+static const unsigned JUMP_OFFSET_LEN = 4;
+static const int32_t JUMP_OFFSET_MIN = INT32_MIN;
+static const int32_t JUMP_OFFSET_MAX = INT32_MAX;
+
+static MOZ_ALWAYS_INLINE int32_t
+GET_JUMP_OFFSET(jsbytecode* pc)
+{
+ return (pc[1] << 24) | (pc[2] << 16) | (pc[3] << 8) | pc[4];
+}
+
+static MOZ_ALWAYS_INLINE void
+SET_JUMP_OFFSET(jsbytecode* pc, int32_t off)
+{
+ pc[1] = jsbytecode(off >> 24);
+ pc[2] = jsbytecode(off >> 16);
+ pc[3] = jsbytecode(off >> 8);
+ pc[4] = jsbytecode(off);
+}
+
+static const unsigned UINT32_INDEX_LEN = 4;
+
+static MOZ_ALWAYS_INLINE uint32_t
+GET_UINT32_INDEX(const jsbytecode* pc)
+{
+ return (pc[1] << 24) | (pc[2] << 16) | (pc[3] << 8) | pc[4];
+}
+
+static MOZ_ALWAYS_INLINE void
+SET_UINT32_INDEX(jsbytecode* pc, uint32_t index)
+{
+ pc[1] = jsbytecode(index >> 24);
+ pc[2] = jsbytecode(index >> 16);
+ pc[3] = jsbytecode(index >> 8);
+ pc[4] = jsbytecode(index);
+}
+
+static inline jsbytecode
+UINT24_HI(unsigned i)
+{
+ return jsbytecode(i >> 16);
+}
+
+static inline jsbytecode
+UINT24_MID(unsigned i)
+{
+ return jsbytecode(i >> 8);
+}
+
+static inline jsbytecode
+UINT24_LO(unsigned i)
+{
+ return jsbytecode(i);
+}
+
+static MOZ_ALWAYS_INLINE unsigned
+GET_UINT24(const jsbytecode* pc)
+{
+ return unsigned((pc[1] << 16) | (pc[2] << 8) | pc[3]);
+}
+
+static MOZ_ALWAYS_INLINE void
+SET_UINT24(jsbytecode* pc, unsigned i)
+{
+ MOZ_ASSERT(i < (1 << 24));
+ pc[1] = UINT24_HI(i);
+ pc[2] = UINT24_MID(i);
+ pc[3] = UINT24_LO(i);
+}
+
+static MOZ_ALWAYS_INLINE int8_t
+GET_INT8(const jsbytecode* pc)
+{
+ return int8_t(pc[1]);
+}
+
+static MOZ_ALWAYS_INLINE uint32_t
+GET_UINT32(const jsbytecode* pc)
+{
+ return (uint32_t(pc[1]) << 24) |
+ (uint32_t(pc[2]) << 16) |
+ (uint32_t(pc[3]) << 8) |
+ uint32_t(pc[4]);
+}
+
+static MOZ_ALWAYS_INLINE void
+SET_UINT32(jsbytecode* pc, uint32_t u)
+{
+ pc[1] = jsbytecode(u >> 24);
+ pc[2] = jsbytecode(u >> 16);
+ pc[3] = jsbytecode(u >> 8);
+ pc[4] = jsbytecode(u);
+}
+
+static MOZ_ALWAYS_INLINE int32_t
+GET_INT32(const jsbytecode* pc)
+{
+ return static_cast<int32_t>(GET_UINT32(pc));
+}
+
+static MOZ_ALWAYS_INLINE void
+SET_INT32(jsbytecode* pc, int32_t i)
+{
+ SET_UINT32(pc, static_cast<uint32_t>(i));
+}
+
+/* Index limit is determined by SN_4BYTE_OFFSET_FLAG, see frontend/BytecodeEmitter.h. */
+static const unsigned INDEX_LIMIT_LOG2 = 31;
+static const uint32_t INDEX_LIMIT = uint32_t(1) << INDEX_LIMIT_LOG2;
+
+static inline jsbytecode
+ARGC_HI(uint16_t argc)
+{
+ return UINT16_HI(argc);
+}
+
+static inline jsbytecode
+ARGC_LO(uint16_t argc)
+{
+ return UINT16_LO(argc);
+}
+
+static inline uint16_t
+GET_ARGC(const jsbytecode* pc)
+{
+ return GET_UINT16(pc);
+}
+
+static const unsigned ARGC_LIMIT = UINT16_LIMIT;
+
+static inline uint16_t
+GET_ARGNO(const jsbytecode* pc)
+{
+ return GET_UINT16(pc);
+}
+
+static inline void
+SET_ARGNO(jsbytecode* pc, uint16_t argno)
+{
+ SET_UINT16(pc, argno);
+}
+
+static const unsigned ARGNO_LEN = 2;
+static const unsigned ARGNO_LIMIT = UINT16_LIMIT;
+
+static inline uint32_t
+GET_LOCALNO(const jsbytecode* pc)
+{
+ return GET_UINT24(pc);
+}
+
+static inline void
+SET_LOCALNO(jsbytecode* pc, uint32_t varno)
+{
+ SET_UINT24(pc, varno);
+}
+
+static const unsigned LOCALNO_LEN = 3;
+static const unsigned LOCALNO_BITS = 24;
+static const uint32_t LOCALNO_LIMIT = 1 << LOCALNO_BITS;
+
+static inline unsigned
+LoopEntryDepthHint(jsbytecode* pc)
+{
+ MOZ_ASSERT(*pc == JSOP_LOOPENTRY);
+ return GET_UINT8(pc) & 0x7f;
+}
+
+static inline bool
+LoopEntryCanIonOsr(jsbytecode* pc)
+{
+ MOZ_ASSERT(*pc == JSOP_LOOPENTRY);
+ return GET_UINT8(pc) & 0x80;
+}
+
+static inline uint8_t
+PackLoopEntryDepthHintAndFlags(unsigned loopDepth, bool canIonOsr)
+{
+ return (loopDepth < 0x80 ? uint8_t(loopDepth) : 0x7f) | (canIonOsr ? 0x80 : 0);
+}
+
+/*
+ * Describes the 'hops' component of a JOF_ENVCOORD opcode.
+ *
+ * Note: this component is only 8 bits wide, limiting the maximum number of
+ * scopes between a use and def to roughly 255. This is a pretty small limit but
+ * note that SpiderMonkey's recursive descent parser can only parse about this
+ * many functions before hitting the C-stack recursion limit so this shouldn't
+ * be a significant limitation in practice.
+ */
+
+static inline uint8_t
+GET_ENVCOORD_HOPS(jsbytecode* pc)
+{
+ return GET_UINT8(pc);
+}
+
+static inline void
+SET_ENVCOORD_HOPS(jsbytecode* pc, uint8_t hops)
+{
+ SET_UINT8(pc, hops);
+}
+
+static const unsigned ENVCOORD_HOPS_LEN = 1;
+static const unsigned ENVCOORD_HOPS_BITS = 8;
+static const unsigned ENVCOORD_HOPS_LIMIT = 1 << ENVCOORD_HOPS_BITS;
+
+/* Describes the 'slot' component of a JOF_ENVCOORD opcode. */
+static inline uint32_t
+GET_ENVCOORD_SLOT(const jsbytecode* pc)
+{
+ return GET_UINT24(pc);
+}
+
+static inline void
+SET_ENVCOORD_SLOT(jsbytecode* pc, uint32_t slot)
+{
+ SET_UINT24(pc, slot);
+}
+
+static const unsigned ENVCOORD_SLOT_LEN = 3;
+static const unsigned ENVCOORD_SLOT_BITS = 24;
+static const uint32_t ENVCOORD_SLOT_LIMIT = 1 << ENVCOORD_SLOT_BITS;
+
+struct JSCodeSpec {
+ int8_t length; /* length including opcode byte */
+ int8_t nuses; /* arity, -1 if variadic */
+ int8_t ndefs; /* number of stack results */
+ uint32_t format; /* immediate operand format */
+
+ uint32_t type() const { return JOF_TYPE(format); }
+};
+
+/* Silence unreferenced formal parameter warnings */
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4100)
+#endif
+
+namespace js {
+
+extern const JSCodeSpec CodeSpec[];
+extern const unsigned NumCodeSpecs;
+extern const char * const CodeName[];
+
+/* Shorthand for type from opcode. */
+
+static inline uint32_t
+JOF_OPTYPE(JSOp op)
+{
+ return JOF_TYPE(CodeSpec[op].format);
+}
+
+static inline bool
+IsJumpOpcode(JSOp op)
+{
+ uint32_t type = JOF_TYPE(CodeSpec[op].format);
+
+ /*
+ * LABEL opcodes have type JOF_JUMP but are no-ops, don't treat them as
+ * jumps to avoid degrading precision.
+ */
+ return type == JOF_JUMP && op != JSOP_LABEL;
+}
+
+static inline bool
+BytecodeFallsThrough(JSOp op)
+{
+ switch (op) {
+ case JSOP_GOTO:
+ case JSOP_DEFAULT:
+ case JSOP_RETURN:
+ case JSOP_RETRVAL:
+ case JSOP_FINALYIELDRVAL:
+ case JSOP_THROW:
+ case JSOP_TABLESWITCH:
+ return false;
+ case JSOP_GOSUB:
+ /* These fall through indirectly, after executing a 'finally'. */
+ return true;
+ default:
+ return true;
+ }
+}
+
+static inline bool
+BytecodeIsJumpTarget(JSOp op)
+{
+ switch (op) {
+ case JSOP_JUMPTARGET:
+ case JSOP_LOOPHEAD:
+ case JSOP_LOOPENTRY:
+ case JSOP_ENDITER:
+ case JSOP_TRY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+class SrcNoteLineScanner
+{
+ /* offset of the current JSOp in the bytecode */
+ ptrdiff_t offset;
+
+ /* next src note to process */
+ jssrcnote* sn;
+
+ /* line number of the current JSOp */
+ uint32_t lineno;
+
+ /*
+ * Is the current op the first one after a line change directive? Note that
+ * multiple ops may be "first" if a line directive is used to return to a
+ * previous line (eg, with a for loop increment expression.)
+ */
+ bool lineHeader;
+
+ public:
+ SrcNoteLineScanner(jssrcnote* sn, uint32_t lineno)
+ : offset(0), sn(sn), lineno(lineno)
+ {
+ }
+
+ /*
+ * This is called repeatedly with always-advancing relpc values. The src
+ * notes are tuples of <PC offset from prev src note, type, args>. Scan
+ * through, updating the lineno, until the next src note is for a later
+ * bytecode.
+ *
+ * When looking at the desired PC offset ('relpc'), the op is first in that
+ * line iff there is a SRC_SETLINE or SRC_NEWLINE src note for that exact
+ * bytecode.
+ *
+ * Note that a single bytecode may have multiple line-modifying notes (even
+ * though only one should ever be needed.)
+ */
+ void advanceTo(ptrdiff_t relpc) {
+ // Must always advance! If the same or an earlier PC is erroneously
+ // passed in, we will already be past the relevant src notes
+ MOZ_ASSERT_IF(offset > 0, relpc > offset);
+
+ // Next src note should be for after the current offset
+ MOZ_ASSERT_IF(offset > 0, SN_IS_TERMINATOR(sn) || SN_DELTA(sn) > 0);
+
+ // The first PC requested is always considered to be a line header
+ lineHeader = (offset == 0);
+
+ if (SN_IS_TERMINATOR(sn))
+ return;
+
+ ptrdiff_t nextOffset;
+ while ((nextOffset = offset + SN_DELTA(sn)) <= relpc && !SN_IS_TERMINATOR(sn)) {
+ offset = nextOffset;
+ SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
+ if (type == SRC_SETLINE || type == SRC_NEWLINE) {
+ if (type == SRC_SETLINE)
+ lineno = GetSrcNoteOffset(sn, 0);
+ else
+ lineno++;
+
+ if (offset == relpc)
+ lineHeader = true;
+ }
+
+ sn = SN_NEXT(sn);
+ }
+ }
+
+ bool isLineHeader() const {
+ return lineHeader;
+ }
+
+ uint32_t getLine() const { return lineno; }
+};
+
+extern unsigned
+StackUses(JSScript* script, jsbytecode* pc);
+
+extern unsigned
+StackDefs(JSScript* script, jsbytecode* pc);
+
+#ifdef DEBUG
+/*
+ * Given bytecode address pc in script's main program code, compute the operand
+ * stack depth just before (JSOp) *pc executes. If *pc is not reachable, return
+ * false.
+ */
+extern bool
+ReconstructStackDepth(JSContext* cx, JSScript* script, jsbytecode* pc, uint32_t* depth, bool* reachablePC);
+#endif
+
+} /* namespace js */
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#define JSDVG_IGNORE_STACK 0
+#define JSDVG_SEARCH_STACK 1
+
+namespace js {
+
+/*
+ * Get the length of variable-length bytecode like JSOP_TABLESWITCH.
+ */
+extern size_t
+GetVariableBytecodeLength(jsbytecode* pc);
+
+/*
+ * Find the source expression that resulted in v, and return a newly allocated
+ * C-string containing it. Fall back on v's string conversion (fallback) if we
+ * can't find the bytecode that generated and pushed v on the operand stack.
+ *
+ * Search the current stack frame if spindex is JSDVG_SEARCH_STACK. Don't
+ * look for v on the stack if spindex is JSDVG_IGNORE_STACK. Otherwise,
+ * spindex is the negative index of v, measured from cx->fp->sp, or from a
+ * lower frame's sp if cx->fp is native.
+ *
+ * The optional argument skipStackHits can be used to skip a hit in the stack
+ * frame. This can be useful in self-hosted code that wants to report value
+ * errors containing decompiled values that are useful for the user, instead of
+ * values used internally by the self-hosted code.
+ *
+ * The caller must call JS_free on the result after a successful call.
+ */
+UniqueChars
+DecompileValueGenerator(JSContext* cx, int spindex, HandleValue v,
+ HandleString fallback, int skipStackHits = 0);
+
+/*
+ * Decompile the formal argument at formalIndex in the nearest non-builtin
+ * stack frame, falling back with converting v to source.
+ */
+char*
+DecompileArgument(JSContext* cx, int formalIndex, HandleValue v);
+
+extern bool
+CallResultEscapes(jsbytecode* pc);
+
+static inline unsigned
+GetDecomposeLength(jsbytecode* pc, size_t len)
+{
+ /*
+ * The last byte of a DECOMPOSE op stores the decomposed length. This is a
+ * constant: perhaps we should just hardcode values instead?
+ */
+ MOZ_ASSERT(size_t(CodeSpec[*pc].length) == len);
+ return (unsigned) pc[len - 1];
+}
+
+static inline unsigned
+GetBytecodeLength(jsbytecode* pc)
+{
+ JSOp op = (JSOp)*pc;
+ MOZ_ASSERT(op < JSOP_LIMIT);
+
+ if (CodeSpec[op].length != -1)
+ return CodeSpec[op].length;
+ return GetVariableBytecodeLength(pc);
+}
+
+static inline bool
+BytecodeIsPopped(jsbytecode* pc)
+{
+ jsbytecode* next = pc + GetBytecodeLength(pc);
+ return JSOp(*next) == JSOP_POP;
+}
+
+static inline bool
+BytecodeFlowsToBitop(jsbytecode* pc)
+{
+ // Look for simple bytecode for integer conversions like (x | 0) or (x & -1).
+ jsbytecode* next = pc + GetBytecodeLength(pc);
+ if (*next == JSOP_BITOR || *next == JSOP_BITAND)
+ return true;
+ if (*next == JSOP_INT8 && GET_INT8(next) == -1) {
+ next += GetBytecodeLength(next);
+ if (*next == JSOP_BITAND)
+ return true;
+ return false;
+ }
+ if (*next == JSOP_ONE) {
+ next += GetBytecodeLength(next);
+ if (*next == JSOP_NEG) {
+ next += GetBytecodeLength(next);
+ if (*next == JSOP_BITAND)
+ return true;
+ }
+ return false;
+ }
+ if (*next == JSOP_ZERO) {
+ next += GetBytecodeLength(next);
+ if (*next == JSOP_BITOR)
+ return true;
+ return false;
+ }
+ return false;
+}
+
+extern bool
+IsValidBytecodeOffset(JSContext* cx, JSScript* script, size_t offset);
+
+inline bool
+FlowsIntoNext(JSOp op)
+{
+ /* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
+ switch (op) {
+ case JSOP_RETRVAL:
+ case JSOP_RETURN:
+ case JSOP_THROW:
+ case JSOP_GOTO:
+ case JSOP_RETSUB:
+ case JSOP_FINALYIELDRVAL:
+ return false;
+ default:
+ return true;
+ }
+}
+
+inline bool
+IsArgOp(JSOp op)
+{
+ return JOF_OPTYPE(op) == JOF_QARG;
+}
+
+inline bool
+IsLocalOp(JSOp op)
+{
+ return JOF_OPTYPE(op) == JOF_LOCAL;
+}
+
+inline bool
+IsAliasedVarOp(JSOp op)
+{
+ return JOF_OPTYPE(op) == JOF_ENVCOORD;
+}
+
+inline bool
+IsGlobalOp(JSOp op)
+{
+ return CodeSpec[op].format & JOF_GNAME;
+}
+
+inline bool
+IsEqualityOp(JSOp op)
+{
+ return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
+}
+
+inline bool
+IsCheckStrictOp(JSOp op)
+{
+ return CodeSpec[op].format & JOF_CHECKSTRICT;
+}
+
+#ifdef DEBUG
+inline bool
+IsCheckSloppyOp(JSOp op)
+{
+ return CodeSpec[op].format & JOF_CHECKSLOPPY;
+}
+#endif
+
+inline bool
+IsAtomOp(JSOp op)
+{
+ return JOF_OPTYPE(op) == JOF_ATOM;
+}
+
+inline bool
+IsGetPropPC(jsbytecode* pc)
+{
+ JSOp op = JSOp(*pc);
+ return op == JSOP_LENGTH || op == JSOP_GETPROP || op == JSOP_CALLPROP;
+}
+
+inline bool
+IsHiddenInitOp(JSOp op)
+{
+ return op == JSOP_INITHIDDENPROP || op == JSOP_INITHIDDENELEM ||
+ op == JSOP_INITHIDDENPROP_GETTER || op == JSOP_INITHIDDENELEM_GETTER ||
+ op == JSOP_INITHIDDENPROP_SETTER || op == JSOP_INITHIDDENELEM_SETTER;
+}
+
+inline bool
+IsStrictSetPC(jsbytecode* pc)
+{
+ JSOp op = JSOp(*pc);
+ return op == JSOP_STRICTSETPROP ||
+ op == JSOP_STRICTSETNAME ||
+ op == JSOP_STRICTSETGNAME ||
+ op == JSOP_STRICTSETELEM;
+}
+
+inline bool
+IsSetPropPC(jsbytecode* pc)
+{
+ JSOp op = JSOp(*pc);
+ return op == JSOP_SETPROP || op == JSOP_STRICTSETPROP ||
+ op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
+ op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME;
+}
+
+inline bool
+IsGetElemPC(jsbytecode* pc)
+{
+ JSOp op = JSOp(*pc);
+ return op == JSOP_GETELEM || op == JSOP_CALLELEM;
+}
+
+inline bool
+IsSetElemPC(jsbytecode* pc)
+{
+ JSOp op = JSOp(*pc);
+ return op == JSOP_SETELEM ||
+ op == JSOP_STRICTSETELEM;
+}
+
+inline bool
+IsCallPC(jsbytecode* pc)
+{
+ return CodeSpec[*pc].format & JOF_INVOKE;
+}
+
+inline bool
+IsStrictEvalPC(jsbytecode* pc)
+{
+ JSOp op = JSOp(*pc);
+ return op == JSOP_STRICTEVAL || op == JSOP_STRICTSPREADEVAL;
+}
+
+static inline int32_t
+GetBytecodeInteger(jsbytecode* pc)
+{
+ switch (JSOp(*pc)) {
+ case JSOP_ZERO: return 0;
+ case JSOP_ONE: return 1;
+ case JSOP_UINT16: return GET_UINT16(pc);
+ case JSOP_UINT24: return GET_UINT24(pc);
+ case JSOP_INT8: return GET_INT8(pc);
+ case JSOP_INT32: return GET_INT32(pc);
+ default:
+ MOZ_CRASH("Bad op");
+ }
+}
+
+/*
+ * Counts accumulated for a single opcode in a script. The counts tracked vary
+ * between opcodes, and this structure ensures that counts are accessed in a
+ * coherent fashion.
+ */
+class PCCounts
+{
+ /*
+ * Offset of the pc inside the script. This fields is used to lookup opcode
+ * which have annotations.
+ */
+ size_t pcOffset_;
+
+ /*
+ * Record the number of execution of one instruction, or the number of
+ * throws executed.
+ */
+ uint64_t numExec_;
+
+ public:
+ explicit PCCounts(size_t off)
+ : pcOffset_(off),
+ numExec_(0)
+ {}
+
+ size_t pcOffset() const {
+ return pcOffset_;
+ }
+
+ // Used for sorting and searching.
+ bool operator<(const PCCounts& rhs) const {
+ return pcOffset_ < rhs.pcOffset_;
+ }
+
+ uint64_t& numExec() {
+ return numExec_;
+ }
+ uint64_t numExec() const {
+ return numExec_;
+ }
+
+ static const char* numExecName;
+};
+
+static inline jsbytecode*
+GetNextPc(jsbytecode* pc)
+{
+ return pc + GetBytecodeLength(pc);
+}
+
+#if defined(DEBUG)
+/*
+ * Disassemblers, for debugging only.
+ */
+extern MOZ_MUST_USE bool
+Disassemble(JSContext* cx, JS::Handle<JSScript*> script, bool lines, Sprinter* sp);
+
+unsigned
+Disassemble1(JSContext* cx, JS::Handle<JSScript*> script, jsbytecode* pc, unsigned loc,
+ bool lines, Sprinter* sp);
+
+#endif
+
+extern MOZ_MUST_USE bool
+DumpCompartmentPCCounts(JSContext* cx);
+
+} // namespace js
+
+#endif /* jsopcode_h */