LCOV - code coverage report
Current view: top level - js/src - jsopcode.h (source / functions) Hit Total Coverage
Test: output.info Lines: 191 256 74.6 %
Date: 2017-07-14 16:53:18 Functions: 64 75 85.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13