LCOV - code coverage report
Current view: directory - js/src - jsscript.h (source / functions) Found Hit Coverage
Test: app.info Lines: 135 122 90.4 %
Date: 2012-04-07 Functions: 70 64 91.4 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=79 ft=cpp:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Communicator client code, released
      18                 :  * March 31, 1998.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  * Netscape Communications Corporation.
      22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #ifndef jsscript_h___
      42                 : #define jsscript_h___
      43                 : /*
      44                 :  * JS script descriptor.
      45                 :  */
      46                 : #include "jsatom.h"
      47                 : #include "jsprvtd.h"
      48                 : #include "jsdbgapi.h"
      49                 : #include "jsclist.h"
      50                 : #include "jsinfer.h"
      51                 : #include "jsopcode.h"
      52                 : #include "jsscope.h"
      53                 : 
      54                 : #include "gc/Barrier.h"
      55                 : 
      56                 : /*
      57                 :  * Type of try note associated with each catch or finally block, and also with
      58                 :  * for-in loops.
      59                 :  */
      60                 : typedef enum JSTryNoteKind {
      61                 :     JSTRY_CATCH,
      62                 :     JSTRY_FINALLY,
      63                 :     JSTRY_ITER
      64                 : } JSTryNoteKind;
      65                 : 
      66                 : /*
      67                 :  * Exception handling record.
      68                 :  */
      69                 : struct JSTryNote {
      70                 :     uint8_t         kind;       /* one of JSTryNoteKind */
      71                 :     uint8_t         padding;    /* explicit padding on uint16_t boundary */
      72                 :     uint16_t        stackDepth; /* stack depth upon exception handler entry */
      73                 :     uint32_t        start;      /* start of the try statement or for-in loop
      74                 :                                    relative to script->main */
      75                 :     uint32_t        length;     /* length of the try statement or for-in loop */
      76                 : };
      77                 : 
      78                 : typedef struct JSTryNoteArray {
      79                 :     JSTryNote       *vector;    /* array of indexed try notes */
      80                 :     uint32_t        length;     /* count of indexed try notes */
      81                 : } JSTryNoteArray;
      82                 : 
      83                 : typedef struct JSObjectArray {
      84                 :     js::HeapPtrObject *vector;  /* array of indexed objects */
      85                 :     uint32_t        length;     /* count of indexed objects */
      86                 : } JSObjectArray;
      87                 : 
      88                 : typedef struct JSConstArray {
      89                 :     js::HeapValue   *vector;    /* array of indexed constant values */
      90                 :     uint32_t        length;
      91                 : } JSConstArray;
      92                 : 
      93                 : namespace js {
      94                 : 
      95                 : struct GlobalSlotArray {
      96           31065 :     struct Entry {
      97                 :         uint32_t    atomIndex;  /* index into atom table */
      98                 :         uint32_t    slot;       /* global obj slot number */
      99                 :     };
     100                 :     Entry           *vector;
     101                 :     uint32_t        length;
     102                 : };
     103                 : 
     104                 : struct ClosedSlotArray {
     105                 :     uint32_t        *vector;    /* array of closed slots */
     106                 :     uint32_t        length;     /* count of closed slots */
     107                 : };
     108                 : 
     109                 : struct Shape;
     110                 : 
     111                 : enum BindingKind { NONE, ARGUMENT, VARIABLE, CONSTANT };
     112                 : 
     113                 : /*
     114                 :  * Formal parameters and local variables are stored in a shape tree
     115                 :  * path encapsulated within this class.  This class represents bindings for
     116                 :  * both function and top-level scripts (the latter is needed to track names in
     117                 :  * strict mode eval code, to give such code its own lexical environment).
     118                 :  */
     119                 : class Bindings
     120         1018770 : {
     121                 :     HeapPtr<Shape> lastBinding;
     122                 :     uint16_t nargs;
     123                 :     uint16_t nvars;
     124                 :     bool     hasDup_:1;     // true if there are duplicate argument names
     125                 : 
     126                 :     inline Shape *initialShape(JSContext *cx) const;
     127                 :   public:
     128                 :     inline Bindings(JSContext *cx);
     129                 : 
     130                 :     /*
     131                 :      * Transfers ownership of bindings data from bindings into this fresh
     132                 :      * Bindings instance. Once such a transfer occurs, the old bindings must
     133                 :      * not be used again.
     134                 :      */
     135                 :     inline void transfer(JSContext *cx, Bindings *bindings);
     136                 : 
     137                 :     /*
     138                 :      * Clones bindings data from bindings, which must be immutable, into this
     139                 :      * fresh Bindings instance. A Bindings instance may be cloned multiple
     140                 :      * times.
     141                 :      */
     142                 :     inline void clone(JSContext *cx, Bindings *bindings);
     143                 : 
     144         1099847 :     uint16_t countArgs() const { return nargs; }
     145         2302618 :     uint16_t countVars() const { return nvars; }
     146                 : 
     147          834845 :     unsigned countLocalNames() const { return nargs + nvars; }
     148                 : 
     149           24825 :     bool hasLocalNames() const { return countLocalNames() > 0; }
     150                 : 
     151                 :     /* Ensure these bindings have a shape lineage. */
     152                 :     inline bool ensureShape(JSContext *cx);
     153                 : 
     154                 :     /* Return the shape lineage generated for these bindings. */
     155                 :     inline Shape *lastShape() const;
     156                 : 
     157                 :     /*
     158                 :      * Return the shape to use to create a call object for these bindings.
     159                 :      * The result is guaranteed not to have duplicate property names.
     160                 :      */
     161                 :     Shape *callObjectShape(JSContext *cx) const;
     162                 : 
     163                 :     /* See Scope::extensibleParents */
     164                 :     inline bool extensibleParents();
     165                 :     bool setExtensibleParents(JSContext *cx);
     166                 : 
     167                 :     bool setParent(JSContext *cx, JSObject *obj);
     168                 : 
     169                 :     enum {
     170                 :         /* A script may have no more than this many arguments or variables. */
     171                 :         BINDING_COUNT_LIMIT = 0xFFFF
     172                 :     };
     173                 : 
     174                 :     /*
     175                 :      * Add a local binding for the given name, of the given type, for the code
     176                 :      * being compiled.  If fun is non-null, this binding set is being created
     177                 :      * for that function, so adjust corresponding metadata in that function
     178                 :      * while adding.  Otherwise this set must correspond to a top-level script.
     179                 :      *
     180                 :      * A binding may be added twice with different kinds; the last one for a
     181                 :      * given name prevails.  (We preserve both bindings for the decompiler,
     182                 :      * which must deal with such cases.)  Pass null for name when indicating a
     183                 :      * destructuring argument.  Return true on success.
     184                 :      *
     185                 :      * The parser builds shape paths for functions, usable by Call objects at
     186                 :      * runtime, by calling an "add" method. All ARGUMENT bindings must be added
     187                 :      * before before any VARIABLE or CONSTANT bindings.
     188                 :      */
     189                 :     bool add(JSContext *cx, JSAtom *name, BindingKind kind);
     190                 : 
     191                 :     /* Convenience specializations. */
     192            3771 :     bool addVariable(JSContext *cx, JSAtom *name) {
     193            3771 :         return add(cx, name, VARIABLE);
     194                 :     }
     195                 :     bool addConstant(JSContext *cx, JSAtom *name) {
     196                 :         return add(cx, name, CONSTANT);
     197                 :     }
     198          226887 :     bool addArgument(JSContext *cx, JSAtom *name, uint16_t *slotp) {
     199          226887 :         JS_ASSERT(name != NULL); /* not destructuring */
     200          226887 :         *slotp = nargs;
     201          226887 :         return add(cx, name, ARGUMENT);
     202                 :     }
     203              81 :     bool addDestructuring(JSContext *cx, uint16_t *slotp) {
     204              81 :         *slotp = nargs;
     205              81 :         return add(cx, NULL, ARGUMENT);
     206                 :     }
     207                 : 
     208              18 :     void noteDup() { hasDup_ = true; }
     209          745077 :     bool hasDup() const { return hasDup_; }
     210                 : 
     211                 :     /*
     212                 :      * Look up an argument or variable name, returning its kind when found or
     213                 :      * NONE when no such name exists. When indexp is not null and the name
     214                 :      * exists, *indexp will receive the index of the corresponding argument or
     215                 :      * variable.
     216                 :      */
     217                 :     BindingKind lookup(JSContext *cx, JSAtom *name, unsigned *indexp) const;
     218                 : 
     219                 :     /* Convenience method to check for any binding for a name. */
     220          489783 :     bool hasBinding(JSContext *cx, JSAtom *name) const {
     221          489783 :         return lookup(cx, name, NULL) != NONE;
     222                 :     }
     223                 : 
     224                 :     /*
     225                 :      * This method returns the local variable, argument, etc. names used by a
     226                 :      * script.  This function must be called only when hasLocalNames().
     227                 :      *
     228                 :      * The elements of the vector with index less than nargs correspond to the
     229                 :      * the names of arguments. An index >= nargs addresses a var binding.
     230                 :      * The name at an element will be null when the element is for an argument
     231                 :      * corresponding to a destructuring pattern.
     232                 :      */
     233                 :     bool getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp);
     234                 : 
     235                 :     /*
     236                 :      * Protect stored bindings from mutation.  Subsequent attempts to add
     237                 :      * bindings will copy the existing bindings before adding to them, allowing
     238                 :      * the original bindings to be safely shared.
     239                 :      */
     240                 :     void makeImmutable();
     241                 : 
     242                 :     /*
     243                 :      * These methods provide direct access to the shape path normally
     244                 :      * encapsulated by js::Bindings. These methods may be used to make a
     245                 :      * Shape::Range for iterating over the relevant shapes from youngest to
     246                 :      * oldest (i.e., last or right-most to first or left-most in source order).
     247                 :      *
     248                 :      * Sometimes iteration order must be from oldest to youngest, however. For
     249                 :      * such cases, use js::Bindings::getLocalNameArray.
     250                 :      */
     251                 :     const js::Shape *lastArgument() const;
     252                 :     const js::Shape *lastVariable() const;
     253                 : 
     254                 :     void trace(JSTracer *trc);
     255                 : 
     256                 :     /* Rooter for stack allocated Bindings. */
     257          420122 :     struct StackRoot {
     258                 :         RootShape root;
     259          420122 :         StackRoot(JSContext *cx, Bindings *bindings)
     260          420122 :             : root(cx, (Shape **) &bindings->lastBinding)
     261          420122 :         {}
     262                 :     };
     263                 : };
     264                 : 
     265                 : } /* namespace js */
     266                 : 
     267                 : #define JS_OBJECT_ARRAY_SIZE(length)                                          \
     268                 :     (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length))
     269                 : 
     270                 : #ifdef JS_METHODJIT
     271                 : namespace JSC {
     272                 :     class ExecutablePool;
     273                 : }
     274                 : 
     275                 : namespace js {
     276                 : namespace mjit {
     277                 :     struct JITScript;
     278                 :     class CallCompiler;
     279                 : }
     280                 : }
     281                 : 
     282                 : #endif
     283                 : 
     284                 : namespace js {
     285                 : 
     286                 : namespace analyze { class ScriptAnalysis; }
     287                 : 
     288                 : class ScriptCounts
     289                 : {
     290                 :     friend struct ::JSScript;
     291                 :     friend struct ScriptAndCounts;
     292                 :     /*
     293                 :      * This points to a single block that holds an array of PCCounts followed
     294                 :      * by an array of doubles.  Each element in the PCCounts array has a
     295                 :      * pointer into the array of doubles.
     296                 :      */
     297                 :     PCCounts *pcCountsVector;
     298                 : 
     299                 :  public:
     300                 : 
     301               0 :     ScriptCounts() : pcCountsVector(NULL) {
     302               0 :     }
     303                 : 
     304                 :     inline void destroy(JSContext *cx);
     305                 : 
     306               0 :     void steal(ScriptCounts &other) {
     307               0 :         *this = other;
     308               0 :         js::PodZero(&other);
     309               0 :     }
     310                 : 
     311                 :     // Boolean conversion, for 'if (scriptCounts) ...'
     312     -2016551605 :     operator void*() const {
     313     -2016551605 :         return pcCountsVector;
     314                 :     }
     315                 : };
     316                 : 
     317                 : class DebugScript
     318                 : {
     319                 :     friend struct ::JSScript;
     320                 : 
     321                 :     /*
     322                 :      * When non-zero, compile script in single-step mode. The top bit is set and
     323                 :      * cleared by setStepMode, as used by JSD. The lower bits are a count,
     324                 :      * adjusted by changeStepModeCount, used by the Debugger object. Only
     325                 :      * when the bit is clear and the count is zero may we compile the script
     326                 :      * without single-step support.
     327                 :      */
     328                 :     uint32_t        stepMode;
     329                 : 
     330                 :     /* Number of breakpoint sites at opcodes in the script. */
     331                 :     uint32_t        numSites;
     332                 : 
     333                 :     /*
     334                 :      * Array with all breakpoints installed at opcodes in the script, indexed
     335                 :      * by the offset of the opcode into the script.
     336                 :      */
     337                 :     BreakpointSite  *breakpoints[1];
     338                 : };
     339                 : 
     340                 : } /* namespace js */
     341                 : 
     342                 : static const uint32_t JS_SCRIPT_COOKIE = 0xc00cee;
     343                 : 
     344                 : struct JSScript : public js::gc::Cell
     345                 : {
     346                 :   private:
     347                 :     static const uint32_t stepFlagMask = 0x80000000U;
     348                 :     static const uint32_t stepCountMask = 0x7fffffffU;
     349                 : 
     350                 :   public:
     351                 :     // This type wraps JITScript.  It has three possible states.
     352                 :     // - "Empty": no compilation has been attempted and there is no JITScript.
     353                 :     // - "Unjittable": compilation failed and there is no JITScript.
     354                 :     // - "Valid": compilation succeeded and there is a JITScript.
     355                 :     class JITScriptHandle
     356                 :     {
     357                 :         // CallCompiler must be a friend because it generates code that uses
     358                 :         // UNJITTABLE.
     359                 :         friend class js::mjit::CallCompiler;
     360                 : 
     361                 :         // The exact representation:
     362                 :         // - NULL means "empty".
     363                 :         // - UNJITTABLE means "unjittable".
     364                 :         // - Any other value means "valid".
     365                 :         // UNJITTABLE = 1 so that we can check that a JITScript is valid
     366                 :         // with a single |> 1| test.  It's defined outside the class because
     367                 :         // non-integral static const fields can't be defined in the class.
     368                 :         static const js::mjit::JITScript *UNJITTABLE;   // = (JITScript *)1;
     369                 :         js::mjit::JITScript *value;
     370                 : 
     371                 :       public:
     372                 :         JITScriptHandle()       { value = NULL; }
     373                 : 
     374        12505470 :         bool isEmpty()          { return value == NULL; }
     375        13978427 :         bool isUnjittable()     { return value == UNJITTABLE; }
     376        47333215 :         bool isValid()          { return value  > UNJITTABLE; }
     377                 : 
     378        28486721 :         js::mjit::JITScript *getValid() {
     379        28486721 :             JS_ASSERT(isValid());
     380        28486721 :             return value;
     381                 :         }
     382                 : 
     383           75536 :         void setEmpty()         { value = NULL; }
     384            2131 :         void setUnjittable()    { value = const_cast<js::mjit::JITScript *>(UNJITTABLE); }
     385           75536 :         void setValid(js::mjit::JITScript *jit) {
     386           75536 :             value = jit;
     387           75536 :             JS_ASSERT(isValid());
     388           75536 :         }
     389                 : 
     390                 :         static void staticAsserts();
     391                 :     };
     392                 : 
     393                 :     //
     394                 :     // We order fields according to their size in order to avoid wasting space
     395                 :     // for alignment.
     396                 :     //
     397                 : 
     398                 :     // Larger-than-word-sized fields.
     399                 : 
     400                 :   public:
     401                 :     js::Bindings    bindings;   /* names of top-level variables in this script
     402                 :                                    (and arguments if this is a function script) */
     403                 : 
     404                 :     // Word-sized fields.
     405                 : 
     406                 :   public:
     407                 :     jsbytecode      *code;      /* bytecodes and their immediate operands */
     408                 :     uint8_t         *data;      /* pointer to variable-length data array (see 
     409                 :                                    comment above NewScript() for details) */
     410                 : 
     411                 :     const char      *filename;  /* source filename or null */
     412                 :     JSAtom          **atoms;    /* maps immediate index to literal struct */
     413                 : 
     414                 :     JSPrincipals    *principals;/* principals for this script */
     415                 :     JSPrincipals    *originPrincipals; /* see jsapi.h 'originPrincipals' comment */
     416                 : 
     417                 :     jschar          *sourceMap; /* source map file or null */
     418                 : 
     419                 :     /*
     420                 :      * A global object for the script.
     421                 :      * - All scripts returned by JSAPI functions (JS_CompileScript,
     422                 :      *   JS_CompileUTF8File, etc.) have a non-null globalObject.
     423                 :      * - A function script has a globalObject if the function comes from a
     424                 :      *   compile-and-go script.
     425                 :      * - Temporary scripts created by obj_eval, JS_EvaluateScript, and
     426                 :      *   similar functions never have the globalObject field set; for such
     427                 :      *   scripts the global should be extracted from the JS frame that
     428                 :      *   execute scripts.
     429                 :      */
     430                 :     js::HeapPtr<js::GlobalObject, JSScript*> globalObject;
     431                 : 
     432                 :     /* Execution and profiling information for JIT code in the script. */
     433                 :     js::ScriptCounts scriptCounts;
     434                 : 
     435                 :     /* Persistent type information retained across GCs. */
     436                 :     js::types::TypeScript *types;
     437                 : 
     438                 :   public:
     439                 : #ifdef JS_METHODJIT
     440                 :     JITScriptHandle jitHandleNormal; // extra JIT info for normal scripts
     441                 :     JITScriptHandle jitHandleCtor;   // extra JIT info for constructors
     442                 : #endif
     443                 : 
     444                 :   private:
     445                 :     js::DebugScript     *debug;
     446                 :     js::HeapPtrFunction function_;
     447                 : 
     448                 :     size_t          useCount;   /* Number of times the script has been called
     449                 :                                  * or has had backedges taken. Reset if the
     450                 :                                  * script's JIT code is forcibly discarded. */
     451                 : #if JS_BITS_PER_WORD == 32
     452                 :     void *padding_;
     453                 : #endif
     454                 : 
     455                 :     // 32-bit fields.
     456                 : 
     457                 :   public:
     458                 :     uint32_t        length;     /* length of code vector */
     459                 : 
     460                 :     uint32_t        lineno;     /* base line number of script */
     461                 : 
     462                 :     uint32_t        mainOffset; /* offset of main entry point from code, after
     463                 :                                    predef'ing prolog */
     464                 : 
     465                 :     uint32_t        natoms;     /* length of atoms array */
     466                 : 
     467                 : #ifdef DEBUG
     468                 :     // Unique identifier within the compartment for this script, used for
     469                 :     // printing analysis information.
     470                 :     uint32_t        id_;
     471                 :   private:
     472                 :     uint32_t        idpad;
     473                 :   public:
     474                 : #endif
     475                 : 
     476                 :     // 16-bit fields.
     477                 : 
     478                 :   private:
     479                 :     uint16_t        version;    /* JS version under which script was compiled */
     480                 : 
     481                 :   public:
     482                 :     uint16_t        nfixed;     /* number of slots besides stack operands in
     483                 :                                    slot array */
     484                 : 
     485                 :     uint16_t        nTypeSets;  /* number of type sets used in this script for
     486                 :                                    dynamic type monitoring */
     487                 : 
     488                 :     uint16_t        nslots;     /* vars plus maximum stack depth */
     489                 :     uint16_t        staticLevel;/* static level for display maintenance */
     490                 : 
     491                 :     // 8-bit fields.
     492                 : 
     493                 :   public:
     494                 :     // Offsets to various array structures from the end of this script, or
     495                 :     // JSScript::INVALID_OFFSET if the array has length 0.
     496                 :     uint8_t         constsOffset;   /* offset to the array of constants */
     497                 :     uint8_t         objectsOffset;  /* offset to the array of nested function,
     498                 :                                        block, scope, xml and one-time regexps
     499                 :                                        objects */
     500                 :     uint8_t         regexpsOffset;  /* offset to the array of to-be-cloned
     501                 :                                        regexps  */
     502                 :     uint8_t         trynotesOffset; /* offset to the array of try notes */
     503                 :     uint8_t         globalsOffset;  /* offset to the array of global slots */
     504                 :     uint8_t         closedArgsOffset; /* offset to the array of closed args */
     505                 :     uint8_t         closedVarsOffset; /* offset to the array of closed vars */
     506                 : 
     507                 :     // 1-bit fields.
     508                 : 
     509                 :   public:
     510                 :     bool            noScriptRval:1; /* no need for result value of last
     511                 :                                        expression statement */
     512                 :     bool            savedCallerFun:1; /* can call getCallerFunction() */
     513                 :     bool            strictModeCode:1; /* code is in strict mode */
     514                 :     bool            compileAndGo:1;   /* script was compiled with TCF_COMPILE_N_GO */
     515                 :     bool            usesEval:1;       /* script uses eval() */
     516                 :     bool            warnedAboutTwoArgumentEval:1; /* have warned about use of
     517                 :                                                      obsolete eval(s, o) in
     518                 :                                                      this script */
     519                 :     bool            warnedAboutUndefinedProp:1; /* have warned about uses of
     520                 :                                                    undefined properties in this
     521                 :                                                    script */
     522                 :     bool            hasSingletons:1;  /* script has singleton objects */
     523                 :     bool            isOuterFunction:1; /* function is heavyweight, with inner functions */
     524                 :     bool            isInnerFunction:1; /* function is directly nested in a heavyweight
     525                 :                                         * outer function */
     526                 :     bool            isActiveEval:1;   /* script came from eval(), and is still active */
     527                 :     bool            isCachedEval:1;   /* script came from eval(), and is in eval cache */
     528                 :     bool            uninlineable:1;   /* script is considered uninlineable by analysis */
     529                 :     bool            reentrantOuterFunction:1; /* outer function marked reentrant */
     530                 :     bool            typesPurged:1;    /* TypeScript has been purged at some point */
     531                 : #ifdef JS_METHODJIT
     532                 :     bool            debugMode:1;      /* script was compiled in debug mode */
     533                 :     bool            failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
     534                 : #endif
     535                 :     bool            callDestroyHook:1;/* need to call destroy hook */
     536                 : 
     537                 :     /*
     538                 :      * An arguments object is created for a function script (when the function
     539                 :      * is first called) iff script->needsArgsObj(). There are several cases
     540                 :      * where the 'arguments' keyword is technically used but which don't really
     541                 :      * need an object (e.g., 'arguments[i]', 'f.apply(null, arguments')'). This
     542                 :      * determination is made during script analysis which occurs lazily (right
     543                 :      * before a script is run). Thus, the output of the front-end is a
     544                 :      * conservative 'mayNeedArgsObj' which leads to further analysis in
     545                 :      * analyzeBytecode and analyzeSSA. To avoid the complexity of spurious
     546                 :      * argument objects creation, we maintain the invariant that needsArgsObj()
     547                 :      * is only queried after this analysis has occurred (analyzedArgsUsage()).
     548                 :      */
     549                 :   private:
     550                 :     bool            mayNeedArgsObj_:1;
     551                 :     bool            analyzedArgsUsage_:1;
     552                 :     bool            needsArgsObj_:1;
     553                 : 
     554                 :     //
     555                 :     // End of fields.  Start methods.
     556                 :     //
     557                 : 
     558                 :     /*
     559                 :      * Two successively less primitive ways to make a new JSScript.  The first
     560                 :      * does *not* call a non-null cx->runtime->newScriptHook -- only the second,
     561                 :      * NewScriptFromEmitter, calls this optional debugger hook.
     562                 :      *
     563                 :      * The NewScript function can't know whether the script it creates belongs
     564                 :      * to a function, or is top-level or eval code, but the debugger wants access
     565                 :      * to the newly made script's function, if any -- so callers of NewScript
     566                 :      * are responsible for notifying the debugger after successfully creating any
     567                 :      * kind (function or other) of new JSScript.
     568                 :      */
     569                 :   public:
     570                 :     static JSScript *NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
     571                 :                                uint32_t nobjects, uint32_t nregexps,
     572                 :                                uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals,
     573                 :                                uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets,
     574                 :                                JSVersion version);
     575                 :     static JSScript *NewScriptFromEmitter(JSContext *cx, js::BytecodeEmitter *bce);
     576                 : 
     577          513260 :     bool mayNeedArgsObj() const { return mayNeedArgsObj_; }
     578        23643842 :     bool analyzedArgsUsage() const { return analyzedArgsUsage_; }
     579        23286546 :     bool needsArgsObj() const { JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; }
     580                 :     void setNeedsArgsObj(bool needsArgsObj);
     581                 :     bool applySpeculationFailed(JSContext *cx);
     582                 : 
     583            7129 :     void setMayNeedArgsObj() {
     584            7129 :         mayNeedArgsObj_ = true;
     585            7129 :     }
     586                 : 
     587                 :     /* Hash table chaining for JSCompartment::evalCache. */
     588          292610 :     JSScript *&evalHashLink() { return *globalObject.unsafeGetUnioned(); }
     589                 : 
     590                 :     /*
     591                 :      * Original compiled function for the script, if it has a function.
     592                 :      * NULL for global and eval scripts.
     593                 :      */
     594       102611085 :     JSFunction *function() const { return function_; }
     595                 :     void setFunction(JSFunction *fun);
     596                 : 
     597                 : #ifdef DEBUG
     598                 :     unsigned id();
     599                 : #else
     600                 :     unsigned id() { return 0; }
     601                 : #endif
     602                 : 
     603                 :     /* Ensure the script has a TypeScript. */
     604                 :     inline bool ensureHasTypes(JSContext *cx);
     605                 : 
     606                 :     /*
     607                 :      * Ensure the script has scope and bytecode analysis information.
     608                 :      * Performed when the script first runs, or first runs after a TypeScript
     609                 :      * GC purge. If scope is NULL then the script must already have types with
     610                 :      * scope information.
     611                 :      */
     612                 :     inline bool ensureRanAnalysis(JSContext *cx, JSObject *scope);
     613                 : 
     614                 :     /* Ensure the script has type inference analysis information. */
     615                 :     inline bool ensureRanInference(JSContext *cx);
     616                 : 
     617                 :     inline bool hasAnalysis();
     618                 :     inline void clearAnalysis();
     619                 :     inline js::analyze::ScriptAnalysis *analysis();
     620                 : 
     621                 :     /*
     622                 :      * Associates this script with a specific function, constructing a new type
     623                 :      * object for the function if necessary.
     624                 :      */
     625                 :     bool typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton = false);
     626                 : 
     627                 :     inline bool hasGlobal() const;
     628                 :     inline bool hasClearedGlobal() const;
     629                 : 
     630                 :     inline js::GlobalObject *global() const;
     631                 :     inline js::types::TypeScriptNesting *nesting() const;
     632                 : 
     633                 :     inline void clearNesting();
     634                 : 
     635                 :     /* Return creation time global or null. */
     636            8235 :     js::GlobalObject *getGlobalObjectOrNull() const {
     637            8235 :         return isCachedEval ? NULL : globalObject.get();
     638                 :     }
     639                 : 
     640                 :   private:
     641                 :     bool makeTypes(JSContext *cx);
     642                 :     bool makeAnalysis(JSContext *cx);
     643                 : 
     644                 : #ifdef JS_METHODJIT
     645                 :   private:
     646                 :     // CallCompiler must be a friend because it generates code that directly
     647                 :     // accesses jitHandleNormal/jitHandleCtor, via jitHandleOffset().
     648                 :     friend class js::mjit::CallCompiler;
     649                 : 
     650            1278 :     static size_t jitHandleOffset(bool constructing) {
     651                 :         return constructing ? offsetof(JSScript, jitHandleCtor)
     652            1278 :                             : offsetof(JSScript, jitHandleNormal);
     653                 :     }
     654                 : 
     655                 :   public:
     656           37764 :     bool hasJITCode()   { return jitHandleNormal.isValid() || jitHandleCtor.isValid(); }
     657                 : 
     658        29864898 :     JITScriptHandle *jitHandle(bool constructing) {
     659        29864898 :         return constructing ? &jitHandleCtor : &jitHandleNormal;
     660                 :     }
     661                 : 
     662        15884340 :     js::mjit::JITScript *getJIT(bool constructing) {
     663        15884340 :         JITScriptHandle *jith = jitHandle(constructing);
     664        15884340 :         return jith->isValid() ? jith->getValid() : NULL;
     665                 :     }
     666                 : 
     667                 :     static void ReleaseCode(js::FreeOp *fop, JITScriptHandle *jith);
     668                 : 
     669                 :     // These methods are implemented in MethodJIT.h.
     670                 :     inline void **nativeMap(bool constructing);
     671                 :     inline void *nativeCodeForPC(bool constructing, jsbytecode *pc);
     672                 : 
     673           26401 :     size_t getUseCount() const  { return useCount; }
     674         4449664 :     size_t incUseCount() { return ++useCount; }
     675            2748 :     size_t *addressOfUseCount() { return &useCount; }
     676          455315 :     void resetUseCount() { useCount = 0; }
     677                 : 
     678                 :     /*
     679                 :      * Size of the JITScript and all sections.  If |mallocSizeOf| is NULL, the
     680                 :      * size is computed analytically.  (This method is implemented in
     681                 :      * MethodJIT.cpp.)
     682                 :      */
     683                 :     size_t sizeOfJitScripts(JSMallocSizeOfFun mallocSizeOf);
     684                 : #endif
     685                 : 
     686                 :   public:
     687               0 :     js::PCCounts getPCCounts(jsbytecode *pc) {
     688               0 :         JS_ASSERT(size_t(pc - code) < length);
     689               0 :         return scriptCounts.pcCountsVector[pc - code];
     690                 :     }
     691                 : 
     692                 :     bool initScriptCounts(JSContext *cx);
     693                 :     void destroyScriptCounts(js::FreeOp *fop);
     694                 : 
     695         2487622 :     jsbytecode *main() {
     696         2487622 :         return code + mainOffset;
     697                 :     }
     698                 : 
     699                 :     /*
     700                 :      * computedSizeOfData() is the in-use size of all the data sections.
     701                 :      * sizeOfData() is the size of the block allocated to hold all the data sections
     702                 :      * (which can be larger than the in-use size).
     703                 :      */
     704                 :     size_t computedSizeOfData();
     705                 :     size_t sizeOfData(JSMallocSizeOfFun mallocSizeOf);
     706                 : 
     707                 :     uint32_t numNotes();  /* Number of srcnote slots in the srcnotes section */
     708                 : 
     709                 :     /* Script notes are allocated right after the code. */
     710        39707087 :     jssrcnote *notes() { return (jssrcnote *)(code + length); }
     711                 : 
     712                 :     static const uint8_t INVALID_OFFSET = 0xFF;
     713        10713250 :     static bool isValidOffset(uint8_t offset) { return offset != INVALID_OFFSET; }
     714                 : 
     715         1401394 :     JSConstArray *consts() {
     716         1401394 :         JS_ASSERT(isValidOffset(constsOffset));
     717         1401394 :         return reinterpret_cast<JSConstArray *>(data + constsOffset);
     718                 :     }
     719                 : 
     720         2349936 :     JSObjectArray *objects() {
     721         2349936 :         JS_ASSERT(isValidOffset(objectsOffset));
     722         2349936 :         return reinterpret_cast<JSObjectArray *>(data + objectsOffset);
     723                 :     }
     724                 : 
     725          100392 :     JSObjectArray *regexps() {
     726          100392 :         JS_ASSERT(isValidOffset(regexpsOffset));
     727          100392 :         return reinterpret_cast<JSObjectArray *>(data + regexpsOffset);
     728                 :     }
     729                 : 
     730          276821 :     JSTryNoteArray *trynotes() {
     731          276821 :         JS_ASSERT(isValidOffset(trynotesOffset));
     732          276821 :         return reinterpret_cast<JSTryNoteArray *>(data + trynotesOffset);
     733                 :     }
     734                 : 
     735           50672 :     js::GlobalSlotArray *globals() {
     736           50672 :         JS_ASSERT(isValidOffset(globalsOffset));
     737           50672 :         return reinterpret_cast<js::GlobalSlotArray *>(data + globalsOffset);
     738                 :     }
     739                 : 
     740          245631 :     js::ClosedSlotArray *closedArgs() {
     741          245631 :         JS_ASSERT(isValidOffset(closedArgsOffset));
     742          245631 :         return reinterpret_cast<js::ClosedSlotArray *>(data + closedArgsOffset);
     743                 :     }
     744                 : 
     745          598441 :     js::ClosedSlotArray *closedVars() {
     746          598441 :         JS_ASSERT(isValidOffset(closedVarsOffset));
     747          598441 :         return reinterpret_cast<js::ClosedSlotArray *>(data + closedVarsOffset);
     748                 :     }
     749                 : 
     750          748766 :     uint32_t nClosedArgs() {
     751          748766 :         return isValidOffset(closedArgsOffset) ? closedArgs()->length : 0;
     752                 :     }
     753                 : 
     754          585886 :     uint32_t nClosedVars() {
     755          585886 :         return isValidOffset(closedVarsOffset) ? closedVars()->length : 0;
     756                 :     }
     757                 : 
     758         7566515 :     JSAtom *getAtom(size_t index) {
     759         7566515 :         JS_ASSERT(index < natoms);
     760         7566515 :         return atoms[index];
     761                 :     }
     762                 : 
     763         1558423 :     js::PropertyName *getName(size_t index) {
     764         1558423 :         return getAtom(index)->asPropertyName();
     765                 :     }
     766                 : 
     767         1843836 :     JSObject *getObject(size_t index) {
     768         1843836 :         JSObjectArray *arr = objects();
     769         1843836 :         JS_ASSERT(index < arr->length);
     770         1843836 :         return arr->vector[index];
     771                 :     }
     772                 : 
     773          567282 :     JSVersion getVersion() const {
     774          567282 :         return JSVersion(version);
     775                 :     }
     776                 : 
     777                 :     inline JSFunction *getFunction(size_t index);
     778                 :     inline JSFunction *getCallerFunction();
     779                 : 
     780                 :     inline JSObject *getRegExp(size_t index);
     781                 : 
     782         1392819 :     const js::Value &getConst(size_t index) {
     783         1392819 :         JSConstArray *arr = consts();
     784         1392819 :         JS_ASSERT(index < arr->length);
     785         1392819 :         return arr->vector[index];
     786                 :     }
     787                 : 
     788                 :     /*
     789                 :      * The isEmpty method tells whether this script has code that computes any
     790                 :      * result (not return value, result AKA normal completion value) other than
     791                 :      * JSVAL_VOID, or any other effects.
     792                 :      */
     793                 :     inline bool isEmpty() const;
     794                 : 
     795          170950 :     uint32_t getClosedArg(uint32_t index) {
     796          170950 :         js::ClosedSlotArray *arr = closedArgs();
     797          170950 :         JS_ASSERT(index < arr->length);
     798          170950 :         return arr->vector[index];
     799                 :     }
     800                 : 
     801          328963 :     uint32_t getClosedVar(uint32_t index) {
     802          328963 :         js::ClosedSlotArray *arr = closedVars();
     803          328963 :         JS_ASSERT(index < arr->length);
     804          328963 :         return arr->vector[index];
     805                 :     }
     806                 : 
     807                 :   private:
     808                 :     /*
     809                 :      * Recompile with or without single-stepping support, as directed
     810                 :      * by stepModeEnabled().
     811                 :      */
     812                 :     void recompileForStepMode(js::FreeOp *fop);
     813                 : 
     814                 :     /* Attempt to change this->stepMode to |newValue|. */
     815                 :     bool tryNewStepMode(JSContext *cx, uint32_t newValue);
     816                 : 
     817                 :     bool ensureHasDebug(JSContext *cx);
     818                 : 
     819                 :   public:
     820        13346928 :     bool hasBreakpointsAt(jsbytecode *pc) { return !!getBreakpointSite(pc); }
     821        20845917 :     bool hasAnyBreakpointsOrStepMode() { return !!debug; }
     822                 : 
     823        22262768 :     js::BreakpointSite *getBreakpointSite(jsbytecode *pc)
     824                 :     {
     825        22262768 :         JS_ASSERT(size_t(pc - code) < length);
     826        22262768 :         return debug ? debug->breakpoints[pc - code] : NULL;
     827                 :     }
     828                 : 
     829                 :     js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
     830                 :                                                   js::GlobalObject *scriptGlobal);
     831                 : 
     832                 :     void destroyBreakpointSite(js::FreeOp *fop, jsbytecode *pc);
     833                 : 
     834                 :     void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler);
     835                 :     void clearTraps(js::FreeOp *fop);
     836                 : 
     837                 :     void markTrapClosures(JSTracer *trc);
     838                 : 
     839                 :     /*
     840                 :      * Set or clear the single-step flag. If the flag is set or the count
     841                 :      * (adjusted by changeStepModeCount) is non-zero, then the script is in
     842                 :      * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
     843                 :      * count-style interface.)
     844                 :      */
     845                 :     bool setStepModeFlag(JSContext *cx, bool step);
     846                 : 
     847                 :     /*
     848                 :      * Increment or decrement the single-step count. If the count is non-zero or
     849                 :      * the flag (set by setStepModeFlag) is set, then the script is in
     850                 :      * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
     851                 :      * count-style interface.)
     852                 :      */
     853                 :     bool changeStepModeCount(JSContext *cx, int delta);
     854                 : 
     855         4143639 :     bool stepModeEnabled() { return debug && !!debug->stepMode; }
     856                 : 
     857                 : #ifdef DEBUG
     858            5813 :     uint32_t stepModeCount() { return debug ? (debug->stepMode & stepCountMask) : 0; }
     859                 : #endif
     860                 : 
     861                 :     void finalize(js::FreeOp *fop);
     862                 : 
     863                 :     static inline void writeBarrierPre(JSScript *script);
     864                 :     static inline void writeBarrierPost(JSScript *script, void *addr);
     865                 : 
     866                 :     static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SCRIPT; }
     867                 : 
     868          116491 :     static JSPrincipals *normalizeOriginPrincipals(JSPrincipals *principals,
     869                 :                                                    JSPrincipals *originPrincipals) {
     870          116491 :         return originPrincipals ? originPrincipals : principals;
     871                 :     }
     872                 : 
     873                 :     void markChildren(JSTracer *trc);
     874                 : };
     875                 : 
     876                 : /* If this fails, padding_ can be removed. */
     877                 : JS_STATIC_ASSERT(sizeof(JSScript) % js::gc::Cell::CellSize == 0);
     878                 : 
     879                 : static JS_INLINE unsigned
     880        76709546 : StackDepth(JSScript *script)
     881                 : {
     882        76709546 :     return script->nslots - script->nfixed;
     883                 : }
     884                 : 
     885                 : /*
     886                 :  * New-script-hook calling is factored from NewScriptFromEmitter so that it
     887                 :  * and callers of XDRScript can share this code.  In the case of callers
     888                 :  * of XDRScript, the hook should be invoked only after successful decode
     889                 :  * of any owning function (the fun parameter) or script object (null fun).
     890                 :  */
     891                 : extern JS_FRIEND_API(void)
     892                 : js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun);
     893                 : 
     894                 : namespace js {
     895                 : 
     896                 : extern void
     897                 : CallDestroyScriptHook(FreeOp *fop, JSScript *script);
     898                 : 
     899                 : extern const char *
     900                 : SaveScriptFilename(JSContext *cx, const char *filename);
     901                 : 
     902                 : extern void
     903                 : MarkScriptFilename(const char *filename);
     904                 : 
     905                 : extern void
     906                 : SweepScriptFilenames(JSCompartment *comp);
     907                 : 
     908                 : extern void
     909                 : FreeScriptFilenames(JSCompartment *comp);
     910                 : 
     911                 : struct ScriptAndCounts
     912               0 : {
     913                 :     JSScript *script;
     914                 :     ScriptCounts scriptCounts;
     915                 : 
     916               0 :     PCCounts &getPCCounts(jsbytecode *pc) const {
     917               0 :         JS_ASSERT(unsigned(pc - script->code) < script->length);
     918               0 :         return scriptCounts.pcCountsVector[pc - script->code];
     919                 :     }
     920                 : };
     921                 : 
     922                 : } /* namespace js */
     923                 : 
     924                 : /*
     925                 :  * To perturb as little code as possible, we introduce a js_GetSrcNote lookup
     926                 :  * cache without adding an explicit cx parameter.  Thus js_GetSrcNote becomes
     927                 :  * a macro that uses cx from its calls' lexical environments.
     928                 :  */
     929                 : #define js_GetSrcNote(script,pc) js_GetSrcNoteCached(cx, script, pc)
     930                 : 
     931                 : extern jssrcnote *
     932                 : js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc);
     933                 : 
     934                 : extern jsbytecode *
     935                 : js_LineNumberToPC(JSScript *script, unsigned lineno);
     936                 : 
     937                 : extern JS_FRIEND_API(unsigned)
     938                 : js_GetScriptLineExtent(JSScript *script);
     939                 : 
     940                 : namespace js {
     941                 : 
     942                 : extern unsigned
     943                 : PCToLineNumber(JSScript *script, jsbytecode *pc);
     944                 : 
     945                 : extern unsigned
     946                 : PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc);
     947                 : 
     948                 : extern unsigned
     949                 : CurrentLine(JSContext *cx);
     950                 : 
     951                 : /*
     952                 :  * This function returns the file and line number of the script currently
     953                 :  * executing on cx. If there is no current script executing on cx (e.g., a
     954                 :  * native called directly through JSAPI (e.g., by setTimeout)), NULL and 0 are
     955                 :  * returned as the file and line. Additionally, this function avoids the full
     956                 :  * linear scan to compute line number when the caller guarnatees that the
     957                 :  * script compilation occurs at a JSOP_EVAL.
     958                 :  */
     959                 : 
     960                 : enum LineOption {
     961                 :     CALLED_FROM_JSOP_EVAL,
     962                 :     NOT_CALLED_FROM_JSOP_EVAL
     963                 : };
     964                 : 
     965                 : inline void
     966                 : CurrentScriptFileLineOrigin(JSContext *cx, unsigned *linenop, LineOption = NOT_CALLED_FROM_JSOP_EVAL);
     967                 : 
     968                 : extern JSScript *
     969                 : CloneScript(JSContext *cx, JSScript *script);
     970                 : 
     971                 : /*
     972                 :  * NB: after a successful XDR_DECODE, XDRScript callers must do any required
     973                 :  * subsequent set-up of owning function or script object and then call
     974                 :  * js_CallNewScriptHook.
     975                 :  */
     976                 : template<XDRMode mode>
     977                 : bool
     978                 : XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript);
     979                 : 
     980                 : } /* namespace js */
     981                 : 
     982                 : #endif /* jsscript_h___ */

Generated by: LCOV version 1.7