js/src/jsscript.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jsscript.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1998 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* JS script descriptor. */
    1.11 +
    1.12 +#ifndef jsscript_h
    1.13 +#define jsscript_h
    1.14 +
    1.15 +#include "mozilla/MemoryReporting.h"
    1.16 +#include "mozilla/PodOperations.h"
    1.17 +
    1.18 +#include "jsatom.h"
    1.19 +#ifdef JS_THREADSAFE
    1.20 +#include "jslock.h"
    1.21 +#endif
    1.22 +#include "jsobj.h"
    1.23 +#include "jsopcode.h"
    1.24 +#include "jstypes.h"
    1.25 +
    1.26 +#include "gc/Barrier.h"
    1.27 +#include "gc/Rooting.h"
    1.28 +#include "jit/IonCode.h"
    1.29 +#include "vm/Shape.h"
    1.30 +
    1.31 +namespace JS {
    1.32 +struct ScriptSourceInfo;
    1.33 +}
    1.34 +
    1.35 +namespace js {
    1.36 +
    1.37 +namespace jit {
    1.38 +    struct BaselineScript;
    1.39 +    struct IonScriptCounts;
    1.40 +}
    1.41 +
    1.42 +# define ION_DISABLED_SCRIPT ((js::jit::IonScript *)0x1)
    1.43 +# define ION_COMPILING_SCRIPT ((js::jit::IonScript *)0x2)
    1.44 +
    1.45 +# define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript *)0x1)
    1.46 +
    1.47 +class BreakpointSite;
    1.48 +class BindingIter;
    1.49 +class LazyScript;
    1.50 +class RegExpObject;
    1.51 +struct SourceCompressionTask;
    1.52 +class Shape;
    1.53 +class WatchpointMap;
    1.54 +class NestedScopeObject;
    1.55 +
    1.56 +namespace frontend {
    1.57 +    class BytecodeEmitter;
    1.58 +}
    1.59 +
    1.60 +}
    1.61 +
    1.62 +/*
    1.63 + * Type of try note associated with each catch or finally block, and also with
    1.64 + * for-in and other kinds of loops. Non-for-in loops do not need these notes
    1.65 + * for exception unwinding, but storing their boundaries here is helpful for
    1.66 + * heuristics that need to know whether a given op is inside a loop.
    1.67 + */
    1.68 +typedef enum JSTryNoteKind {
    1.69 +    JSTRY_CATCH,
    1.70 +    JSTRY_FINALLY,
    1.71 +    JSTRY_ITER,
    1.72 +    JSTRY_LOOP
    1.73 +} JSTryNoteKind;
    1.74 +
    1.75 +/*
    1.76 + * Exception handling record.
    1.77 + */
    1.78 +struct JSTryNote {
    1.79 +    uint8_t         kind;       /* one of JSTryNoteKind */
    1.80 +    uint32_t        stackDepth; /* stack depth upon exception handler entry */
    1.81 +    uint32_t        start;      /* start of the try statement or loop
    1.82 +                                   relative to script->main */
    1.83 +    uint32_t        length;     /* length of the try statement or loop */
    1.84 +};
    1.85 +
    1.86 +namespace js {
    1.87 +
    1.88 +// A block scope has a range in bytecode: it is entered at some offset, and left
    1.89 +// at some later offset.  Scopes can be nested.  Given an offset, the
    1.90 +// BlockScopeNote containing that offset whose with the highest start value
    1.91 +// indicates the block scope.  The block scope list is sorted by increasing
    1.92 +// start value.
    1.93 +//
    1.94 +// It is possible to leave a scope nonlocally, for example via a "break"
    1.95 +// statement, so there may be short bytecode ranges in a block scope in which we
    1.96 +// are popping the block chain in preparation for a goto.  These exits are also
    1.97 +// nested with respect to outer scopes.  The scopes in these exits are indicated
    1.98 +// by the "index" field, just like any other block.  If a nonlocal exit pops the
    1.99 +// last block scope, the index will be NoBlockScopeIndex.
   1.100 +//
   1.101 +struct BlockScopeNote {
   1.102 +    static const uint32_t NoBlockScopeIndex = UINT32_MAX;
   1.103 +
   1.104 +    uint32_t        index;      // Index of NestedScopeObject in the object
   1.105 +                                // array, or NoBlockScopeIndex if there is no
   1.106 +                                // block scope in this range.
   1.107 +    uint32_t        start;      // Bytecode offset at which this scope starts,
   1.108 +                                // from script->main().
   1.109 +    uint32_t        length;     // Bytecode length of scope.
   1.110 +    uint32_t        parent;     // Index of parent block scope in notes, or UINT32_MAX.
   1.111 +};
   1.112 +
   1.113 +struct ConstArray {
   1.114 +    js::HeapValue   *vector;    /* array of indexed constant values */
   1.115 +    uint32_t        length;
   1.116 +};
   1.117 +
   1.118 +struct ObjectArray {
   1.119 +    js::HeapPtrObject *vector;  // Array of indexed objects.
   1.120 +    uint32_t        length;     // Count of indexed objects.
   1.121 +};
   1.122 +
   1.123 +struct TryNoteArray {
   1.124 +    JSTryNote       *vector;    // Array of indexed try notes.
   1.125 +    uint32_t        length;     // Count of indexed try notes.
   1.126 +};
   1.127 +
   1.128 +struct BlockScopeArray {
   1.129 +    BlockScopeNote *vector;     // Array of indexed BlockScopeNote records.
   1.130 +    uint32_t        length;     // Count of indexed try notes.
   1.131 +};
   1.132 +
   1.133 +class Binding
   1.134 +{
   1.135 +    // One JSScript stores one Binding per formal/variable so we use a
   1.136 +    // packed-word representation.
   1.137 +    uintptr_t bits_;
   1.138 +
   1.139 +    static const uintptr_t KIND_MASK = 0x3;
   1.140 +    static const uintptr_t ALIASED_BIT = 0x4;
   1.141 +    static const uintptr_t NAME_MASK = ~(KIND_MASK | ALIASED_BIT);
   1.142 +
   1.143 +  public:
   1.144 +    // A "binding" is a formal, 'var', or 'const' declaration. A function's
   1.145 +    // lexical scope is composed of these three kinds of bindings.
   1.146 +    enum Kind { ARGUMENT, VARIABLE, CONSTANT };
   1.147 +
   1.148 +    explicit Binding() : bits_(0) {}
   1.149 +
   1.150 +    Binding(PropertyName *name, Kind kind, bool aliased) {
   1.151 +        JS_STATIC_ASSERT(CONSTANT <= KIND_MASK);
   1.152 +        JS_ASSERT((uintptr_t(name) & ~NAME_MASK) == 0);
   1.153 +        JS_ASSERT((uintptr_t(kind) & ~KIND_MASK) == 0);
   1.154 +        bits_ = uintptr_t(name) | uintptr_t(kind) | (aliased ? ALIASED_BIT : 0);
   1.155 +    }
   1.156 +
   1.157 +    PropertyName *name() const {
   1.158 +        return (PropertyName *)(bits_ & NAME_MASK);
   1.159 +    }
   1.160 +
   1.161 +    Kind kind() const {
   1.162 +        return Kind(bits_ & KIND_MASK);
   1.163 +    }
   1.164 +
   1.165 +    bool aliased() const {
   1.166 +        return bool(bits_ & ALIASED_BIT);
   1.167 +    }
   1.168 +};
   1.169 +
   1.170 +JS_STATIC_ASSERT(sizeof(Binding) == sizeof(uintptr_t));
   1.171 +
   1.172 +class Bindings;
   1.173 +typedef InternalHandle<Bindings *> InternalBindingsHandle;
   1.174 +
   1.175 +/*
   1.176 + * Formal parameters and local variables are stored in a shape tree
   1.177 + * path encapsulated within this class.  This class represents bindings for
   1.178 + * both function and top-level scripts (the latter is needed to track names in
   1.179 + * strict mode eval code, to give such code its own lexical environment).
   1.180 + */
   1.181 +class Bindings
   1.182 +{
   1.183 +    friend class BindingIter;
   1.184 +    friend class AliasedFormalIter;
   1.185 +
   1.186 +    HeapPtr<Shape> callObjShape_;
   1.187 +    uintptr_t bindingArrayAndFlag_;
   1.188 +    uint16_t numArgs_;
   1.189 +    uint16_t numBlockScoped_;
   1.190 +    uint32_t numVars_;
   1.191 +
   1.192 +    /*
   1.193 +     * During parsing, bindings are allocated out of a temporary LifoAlloc.
   1.194 +     * After parsing, a JSScript object is created and the bindings are
   1.195 +     * permanently transferred to it. On error paths, the JSScript object may
   1.196 +     * end up with bindings that still point to the (new released) LifoAlloc
   1.197 +     * memory. To avoid tracing these bindings during GC, we keep track of
   1.198 +     * whether the bindings are temporary or permanent in the low bit of
   1.199 +     * bindingArrayAndFlag_.
   1.200 +     */
   1.201 +    static const uintptr_t TEMPORARY_STORAGE_BIT = 0x1;
   1.202 +    bool bindingArrayUsingTemporaryStorage() const {
   1.203 +        return bindingArrayAndFlag_ & TEMPORARY_STORAGE_BIT;
   1.204 +    }
   1.205 +
   1.206 +  public:
   1.207 +
   1.208 +    Binding *bindingArray() const {
   1.209 +        return reinterpret_cast<Binding *>(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT);
   1.210 +    }
   1.211 +
   1.212 +    inline Bindings();
   1.213 +
   1.214 +    /*
   1.215 +     * Initialize a Bindings with a pointer into temporary storage.
   1.216 +     * bindingArray must have length numArgs+numVars. Before the temporary
   1.217 +     * storage is release, switchToScriptStorage must be called, providing a
   1.218 +     * pointer into the Binding array stored in script->data.
   1.219 +     */
   1.220 +    static bool initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
   1.221 +                                         unsigned numArgs, uint32_t numVars,
   1.222 +                                         Binding *bindingArray, unsigned numBlockScoped);
   1.223 +
   1.224 +    // CompileScript parses and compiles one statement at a time, but the result
   1.225 +    // is one Script object.  There will be no vars or bindings, because those
   1.226 +    // go on the global, but there may be block-scoped locals, and the number of
   1.227 +    // block-scoped locals may increase as we parse more expressions.  This
   1.228 +    // helper updates the number of block scoped variables in a script as it is
   1.229 +    // being parsed.
   1.230 +    void updateNumBlockScoped(unsigned numBlockScoped) {
   1.231 +        JS_ASSERT(!callObjShape_);
   1.232 +        JS_ASSERT(numVars_ == 0);
   1.233 +        JS_ASSERT(numBlockScoped < LOCALNO_LIMIT);
   1.234 +        JS_ASSERT(numBlockScoped >= numBlockScoped_);
   1.235 +        numBlockScoped_ = numBlockScoped;
   1.236 +    }
   1.237 +
   1.238 +    uint8_t *switchToScriptStorage(Binding *newStorage);
   1.239 +
   1.240 +    /*
   1.241 +     * Clone srcScript's bindings (as part of js::CloneScript). dstScriptData
   1.242 +     * is the pointer to what will eventually be dstScript->data.
   1.243 +     */
   1.244 +    static bool clone(JSContext *cx, InternalBindingsHandle self, uint8_t *dstScriptData,
   1.245 +                      HandleScript srcScript);
   1.246 +
   1.247 +    unsigned numArgs() const { return numArgs_; }
   1.248 +    uint32_t numVars() const { return numVars_; }
   1.249 +    unsigned numBlockScoped() const { return numBlockScoped_; }
   1.250 +    uint32_t numLocals() const { return numVars() + numBlockScoped(); }
   1.251 +
   1.252 +    // Return the size of the bindingArray.
   1.253 +    uint32_t count() const { return numArgs() + numVars(); }
   1.254 +
   1.255 +    /* Return the initial shape of call objects created for this scope. */
   1.256 +    Shape *callObjShape() const { return callObjShape_; }
   1.257 +
   1.258 +    /* Convenience method to get the var index of 'arguments'. */
   1.259 +    static uint32_t argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle);
   1.260 +
   1.261 +    /* Return whether the binding at bindingIndex is aliased. */
   1.262 +    bool bindingIsAliased(uint32_t bindingIndex);
   1.263 +
   1.264 +    /* Return whether this scope has any aliased bindings. */
   1.265 +    bool hasAnyAliasedBindings() const {
   1.266 +        if (!callObjShape_)
   1.267 +            return false;
   1.268 +
   1.269 +        return !callObjShape_->isEmptyShape();
   1.270 +    }
   1.271 +
   1.272 +    void trace(JSTracer *trc);
   1.273 +};
   1.274 +
   1.275 +template <>
   1.276 +struct GCMethods<Bindings> {
   1.277 +    static Bindings initial();
   1.278 +    static ThingRootKind kind() { return THING_ROOT_BINDINGS; }
   1.279 +    static bool poisoned(const Bindings &bindings) {
   1.280 +        return IsPoisonedPtr(static_cast<Shape *>(bindings.callObjShape()));
   1.281 +    }
   1.282 +};
   1.283 +
   1.284 +class ScriptCounts
   1.285 +{
   1.286 +    friend class ::JSScript;
   1.287 +    friend struct ScriptAndCounts;
   1.288 +
   1.289 +    /*
   1.290 +     * This points to a single block that holds an array of PCCounts followed
   1.291 +     * by an array of doubles.  Each element in the PCCounts array has a
   1.292 +     * pointer into the array of doubles.
   1.293 +     */
   1.294 +    PCCounts *pcCountsVector;
   1.295 +
   1.296 +    /* Information about any Ion compilations for the script. */
   1.297 +    jit::IonScriptCounts *ionCounts;
   1.298 +
   1.299 + public:
   1.300 +    ScriptCounts() : pcCountsVector(nullptr), ionCounts(nullptr) { }
   1.301 +
   1.302 +    inline void destroy(FreeOp *fop);
   1.303 +
   1.304 +    void set(js::ScriptCounts counts) {
   1.305 +        pcCountsVector = counts.pcCountsVector;
   1.306 +        ionCounts = counts.ionCounts;
   1.307 +    }
   1.308 +};
   1.309 +
   1.310 +typedef HashMap<JSScript *,
   1.311 +                ScriptCounts,
   1.312 +                DefaultHasher<JSScript *>,
   1.313 +                SystemAllocPolicy> ScriptCountsMap;
   1.314 +
   1.315 +class DebugScript
   1.316 +{
   1.317 +    friend class ::JSScript;
   1.318 +
   1.319 +    /*
   1.320 +     * When non-zero, compile script in single-step mode. The top bit is set and
   1.321 +     * cleared by setStepMode, as used by JSD. The lower bits are a count,
   1.322 +     * adjusted by changeStepModeCount, used by the Debugger object. Only
   1.323 +     * when the bit is clear and the count is zero may we compile the script
   1.324 +     * without single-step support.
   1.325 +     */
   1.326 +    uint32_t        stepMode;
   1.327 +
   1.328 +    /* Number of breakpoint sites at opcodes in the script. */
   1.329 +    uint32_t        numSites;
   1.330 +
   1.331 +    /*
   1.332 +     * Array with all breakpoints installed at opcodes in the script, indexed
   1.333 +     * by the offset of the opcode into the script.
   1.334 +     */
   1.335 +    BreakpointSite  *breakpoints[1];
   1.336 +};
   1.337 +
   1.338 +typedef HashMap<JSScript *,
   1.339 +                DebugScript *,
   1.340 +                DefaultHasher<JSScript *>,
   1.341 +                SystemAllocPolicy> DebugScriptMap;
   1.342 +
   1.343 +class ScriptSource;
   1.344 +
   1.345 +class SourceDataCache
   1.346 +{
   1.347 +    typedef HashMap<ScriptSource *,
   1.348 +                    const jschar *,
   1.349 +                    DefaultHasher<ScriptSource *>,
   1.350 +                    SystemAllocPolicy> Map;
   1.351 +
   1.352 +  public:
   1.353 +    // Hold an entry in the source data cache and prevent it from being purged on GC.
   1.354 +    class AutoHoldEntry
   1.355 +    {
   1.356 +        SourceDataCache *cache_;
   1.357 +        ScriptSource *source_;
   1.358 +        const jschar *charsToFree_;
   1.359 +      public:
   1.360 +        explicit AutoHoldEntry();
   1.361 +        ~AutoHoldEntry();
   1.362 +      private:
   1.363 +        void holdEntry(SourceDataCache *cache, ScriptSource *source);
   1.364 +        void deferDelete(const jschar *chars);
   1.365 +        ScriptSource *source() const { return source_; }
   1.366 +        friend class SourceDataCache;
   1.367 +    };
   1.368 +
   1.369 +  private:
   1.370 +    Map *map_;
   1.371 +    AutoHoldEntry *holder_;
   1.372 +
   1.373 +  public:
   1.374 +    SourceDataCache() : map_(nullptr), holder_(nullptr) {}
   1.375 +
   1.376 +    const jschar *lookup(ScriptSource *ss, AutoHoldEntry &asp);
   1.377 +    bool put(ScriptSource *ss, const jschar *chars, AutoHoldEntry &asp);
   1.378 +
   1.379 +    void purge();
   1.380 +
   1.381 +    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
   1.382 +
   1.383 +  private:
   1.384 +    void holdEntry(AutoHoldEntry &holder, ScriptSource *ss);
   1.385 +    void releaseEntry(AutoHoldEntry &holder);
   1.386 +};
   1.387 +
   1.388 +class ScriptSource
   1.389 +{
   1.390 +    friend class SourceCompressionTask;
   1.391 +
   1.392 +    // A note on concurrency:
   1.393 +    //
   1.394 +    // The source may be compressed by a worker thread during parsing. (See
   1.395 +    // SourceCompressionTask.) When compression is running in the background,
   1.396 +    // ready() returns false. The compression thread touches the |data| union
   1.397 +    // and |compressedLength_|. Therefore, it is not safe to read these members
   1.398 +    // unless ready() is true. With that said, users of the public ScriptSource
   1.399 +    // API should be fine.
   1.400 +
   1.401 +    union {
   1.402 +        // Before setSourceCopy or setSource are successfully called, this union
   1.403 +        // has a nullptr pointer. When the script source is ready,
   1.404 +        // compressedLength_ != 0 implies compressed holds the compressed data;
   1.405 +        // otherwise, source holds the uncompressed source. There is a special
   1.406 +        // pointer |emptySource| for source code for length 0.
   1.407 +        //
   1.408 +        // The only function allowed to malloc, realloc, or free the pointers in
   1.409 +        // this union is adjustDataSize(). Don't do it elsewhere.
   1.410 +        jschar *source;
   1.411 +        unsigned char *compressed;
   1.412 +    } data;
   1.413 +    uint32_t refs;
   1.414 +    uint32_t length_;
   1.415 +    uint32_t compressedLength_;
   1.416 +    char *filename_;
   1.417 +    jschar *displayURL_;
   1.418 +    jschar *sourceMapURL_;
   1.419 +    JSPrincipals *originPrincipals_;
   1.420 +
   1.421 +    // bytecode offset in caller script that generated this code.
   1.422 +    // This is present for eval-ed code, as well as "new Function(...)"-introduced
   1.423 +    // scripts.
   1.424 +    uint32_t introductionOffset_;
   1.425 +
   1.426 +    // If this ScriptSource was generated by a code-introduction mechanism such as |eval|
   1.427 +    // or |new Function|, the debugger needs access to the "raw" filename of the top-level
   1.428 +    // script that contains the eval-ing code.  To keep track of this, we must preserve
   1.429 +    // the original outermost filename (of the original introducer script), so that instead
   1.430 +    // of a filename of "foo.js line 30 > eval line 10 > Function", we can obtain the
   1.431 +    // original raw filename of "foo.js".
   1.432 +    char *introducerFilename_;
   1.433 +
   1.434 +    // A string indicating how this source code was introduced into the system.
   1.435 +    // This accessor returns one of the following values:
   1.436 +    //      "eval" for code passed to |eval|.
   1.437 +    //      "Function" for code passed to the |Function| constructor.
   1.438 +    //      "Worker" for code loaded by calling the Web worker constructor&mdash;the worker's main script.
   1.439 +    //      "importScripts" for code by calling |importScripts| in a web worker.
   1.440 +    //      "handler" for code assigned to DOM elements' event handler IDL attributes.
   1.441 +    //      "scriptElement" for code belonging to <script> elements.
   1.442 +    //      undefined if the implementation doesn't know how the code was introduced.
   1.443 +    // This is a constant, statically allocated C string, so does not need
   1.444 +    // memory management.
   1.445 +    const char *introductionType_;
   1.446 +
   1.447 +    // True if we can call JSRuntime::sourceHook to load the source on
   1.448 +    // demand. If sourceRetrievable_ and hasSourceData() are false, it is not
   1.449 +    // possible to get source at all.
   1.450 +    bool sourceRetrievable_:1;
   1.451 +    bool argumentsNotIncluded_:1;
   1.452 +    bool ready_:1;
   1.453 +    bool hasIntroductionOffset_:1;
   1.454 +
   1.455 +  public:
   1.456 +    explicit ScriptSource()
   1.457 +      : refs(0),
   1.458 +        length_(0),
   1.459 +        compressedLength_(0),
   1.460 +        filename_(nullptr),
   1.461 +        displayURL_(nullptr),
   1.462 +        sourceMapURL_(nullptr),
   1.463 +        originPrincipals_(nullptr),
   1.464 +        introductionOffset_(0),
   1.465 +        introducerFilename_(nullptr),
   1.466 +        introductionType_(nullptr),
   1.467 +        sourceRetrievable_(false),
   1.468 +        argumentsNotIncluded_(false),
   1.469 +        ready_(true),
   1.470 +        hasIntroductionOffset_(false)
   1.471 +    {
   1.472 +        data.source = nullptr;
   1.473 +    }
   1.474 +    void incref() { refs++; }
   1.475 +    void decref() {
   1.476 +        JS_ASSERT(refs != 0);
   1.477 +        if (--refs == 0)
   1.478 +            destroy();
   1.479 +    }
   1.480 +    bool initFromOptions(ExclusiveContext *cx, const ReadOnlyCompileOptions &options);
   1.481 +    bool setSourceCopy(ExclusiveContext *cx,
   1.482 +                       JS::SourceBufferHolder &srcBuf,
   1.483 +                       bool argumentsNotIncluded,
   1.484 +                       SourceCompressionTask *tok);
   1.485 +    void setSource(const jschar *src, size_t length);
   1.486 +    bool ready() const { return ready_; }
   1.487 +    void setSourceRetrievable() { sourceRetrievable_ = true; }
   1.488 +    bool sourceRetrievable() const { return sourceRetrievable_; }
   1.489 +    bool hasSourceData() const { return !ready() || !!data.source; }
   1.490 +    uint32_t length() const {
   1.491 +        JS_ASSERT(hasSourceData());
   1.492 +        return length_;
   1.493 +    }
   1.494 +    bool argumentsNotIncluded() const {
   1.495 +        JS_ASSERT(hasSourceData());
   1.496 +        return argumentsNotIncluded_;
   1.497 +    }
   1.498 +    const jschar *chars(JSContext *cx, SourceDataCache::AutoHoldEntry &asp);
   1.499 +    JSFlatString *substring(JSContext *cx, uint32_t start, uint32_t stop);
   1.500 +    void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
   1.501 +                                JS::ScriptSourceInfo *info) const;
   1.502 +
   1.503 +    // XDR handling
   1.504 +    template <XDRMode mode>
   1.505 +    bool performXDR(XDRState<mode> *xdr);
   1.506 +
   1.507 +    bool setFilename(ExclusiveContext *cx, const char *filename);
   1.508 +    const char *introducerFilename() const {
   1.509 +        return introducerFilename_;
   1.510 +    }
   1.511 +    bool hasIntroductionType() const {
   1.512 +        return introductionType_;
   1.513 +    }
   1.514 +    const char *introductionType() const {
   1.515 +        JS_ASSERT(hasIntroductionType());
   1.516 +        return introductionType_;
   1.517 +    }
   1.518 +    const char *filename() const {
   1.519 +        return filename_;
   1.520 +    }
   1.521 +
   1.522 +    // Display URLs
   1.523 +    bool setDisplayURL(ExclusiveContext *cx, const jschar *displayURL);
   1.524 +    const jschar *displayURL();
   1.525 +    bool hasDisplayURL() const { return displayURL_ != nullptr; }
   1.526 +
   1.527 +    // Source maps
   1.528 +    bool setSourceMapURL(ExclusiveContext *cx, const jschar *sourceMapURL);
   1.529 +    const jschar *sourceMapURL();
   1.530 +    bool hasSourceMapURL() const { return sourceMapURL_ != nullptr; }
   1.531 +
   1.532 +    JSPrincipals *originPrincipals() const { return originPrincipals_; }
   1.533 +
   1.534 +    bool hasIntroductionOffset() const { return hasIntroductionOffset_; }
   1.535 +    uint32_t introductionOffset() const {
   1.536 +        JS_ASSERT(hasIntroductionOffset());
   1.537 +        return introductionOffset_;
   1.538 +    }
   1.539 +    void setIntroductionOffset(uint32_t offset) {
   1.540 +        JS_ASSERT(!hasIntroductionOffset());
   1.541 +        JS_ASSERT(offset <= (uint32_t)INT32_MAX);
   1.542 +        introductionOffset_ = offset;
   1.543 +        hasIntroductionOffset_ = true;
   1.544 +    }
   1.545 +
   1.546 +  private:
   1.547 +    void destroy();
   1.548 +    bool compressed() const { return compressedLength_ != 0; }
   1.549 +    size_t computedSizeOfData() const {
   1.550 +        return compressed() ? compressedLength_ : sizeof(jschar) * length_;
   1.551 +    }
   1.552 +    bool adjustDataSize(size_t nbytes);
   1.553 +    const jschar *getOffThreadCompressionChars(ExclusiveContext *cx);
   1.554 +};
   1.555 +
   1.556 +class ScriptSourceHolder
   1.557 +{
   1.558 +    ScriptSource *ss;
   1.559 +  public:
   1.560 +    explicit ScriptSourceHolder(ScriptSource *ss)
   1.561 +      : ss(ss)
   1.562 +    {
   1.563 +        ss->incref();
   1.564 +    }
   1.565 +    ~ScriptSourceHolder()
   1.566 +    {
   1.567 +        ss->decref();
   1.568 +    }
   1.569 +};
   1.570 +
   1.571 +class ScriptSourceObject : public JSObject
   1.572 +{
   1.573 +  public:
   1.574 +    static const Class class_;
   1.575 +
   1.576 +    static void trace(JSTracer *trc, JSObject *obj);
   1.577 +    static void finalize(FreeOp *fop, JSObject *obj);
   1.578 +    static ScriptSourceObject *create(ExclusiveContext *cx, ScriptSource *source,
   1.579 +                                      const ReadOnlyCompileOptions &options);
   1.580 +
   1.581 +    ScriptSource *source() {
   1.582 +        return static_cast<ScriptSource *>(getReservedSlot(SOURCE_SLOT).toPrivate());
   1.583 +    }
   1.584 +
   1.585 +    void setSource(ScriptSource *source);
   1.586 +
   1.587 +    JSObject *element() const;
   1.588 +    void initElement(HandleObject element);
   1.589 +    const Value &elementAttributeName() const;
   1.590 +
   1.591 +    JSScript *introductionScript() const {
   1.592 +        void *untyped = getReservedSlot(INTRODUCTION_SCRIPT_SLOT).toPrivate();
   1.593 +        return static_cast<JSScript *>(untyped);
   1.594 +    }
   1.595 +    void initIntroductionScript(JSScript *script);
   1.596 +
   1.597 +  private:
   1.598 +    static const uint32_t SOURCE_SLOT = 0;
   1.599 +    static const uint32_t ELEMENT_SLOT = 1;
   1.600 +    static const uint32_t ELEMENT_PROPERTY_SLOT = 2;
   1.601 +    static const uint32_t INTRODUCTION_SCRIPT_SLOT = 3;
   1.602 +    static const uint32_t RESERVED_SLOTS = 4;
   1.603 +};
   1.604 +
   1.605 +enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
   1.606 +
   1.607 +static inline unsigned
   1.608 +GeneratorKindAsBits(GeneratorKind generatorKind) {
   1.609 +    return static_cast<unsigned>(generatorKind);
   1.610 +}
   1.611 +
   1.612 +static inline GeneratorKind
   1.613 +GeneratorKindFromBits(unsigned val) {
   1.614 +    JS_ASSERT(val <= StarGenerator);
   1.615 +    return static_cast<GeneratorKind>(val);
   1.616 +}
   1.617 +
   1.618 +/*
   1.619 + * NB: after a successful XDR_DECODE, XDRScript callers must do any required
   1.620 + * subsequent set-up of owning function or script object and then call
   1.621 + * js_CallNewScriptHook.
   1.622 + */
   1.623 +template<XDRMode mode>
   1.624 +bool
   1.625 +XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
   1.626 +          HandleFunction fun, MutableHandleScript scriptp);
   1.627 +
   1.628 +JSScript *
   1.629 +CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript script,
   1.630 +            NewObjectKind newKind = GenericObject);
   1.631 +
   1.632 +template<XDRMode mode>
   1.633 +bool
   1.634 +XDRLazyScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
   1.635 +              HandleFunction fun, MutableHandle<LazyScript *> lazy);
   1.636 +
   1.637 +/*
   1.638 + * Code any constant value.
   1.639 + */
   1.640 +template<XDRMode mode>
   1.641 +bool
   1.642 +XDRScriptConst(XDRState<mode> *xdr, MutableHandleValue vp);
   1.643 +
   1.644 +} /* namespace js */
   1.645 +
   1.646 +class JSScript : public js::gc::BarrieredCell<JSScript>
   1.647 +{
   1.648 +    static const uint32_t stepFlagMask = 0x80000000U;
   1.649 +    static const uint32_t stepCountMask = 0x7fffffffU;
   1.650 +
   1.651 +    template <js::XDRMode mode>
   1.652 +    friend
   1.653 +    bool
   1.654 +    js::XDRScript(js::XDRState<mode> *xdr, js::HandleObject enclosingScope, js::HandleScript enclosingScript,
   1.655 +                  js::HandleFunction fun, js::MutableHandleScript scriptp);
   1.656 +
   1.657 +    friend JSScript *
   1.658 +    js::CloneScript(JSContext *cx, js::HandleObject enclosingScope, js::HandleFunction fun, js::HandleScript src,
   1.659 +                    js::NewObjectKind newKind);
   1.660 +
   1.661 +  public:
   1.662 +    //
   1.663 +    // We order fields according to their size in order to avoid wasting space
   1.664 +    // for alignment.
   1.665 +    //
   1.666 +
   1.667 +    // Larger-than-word-sized fields.
   1.668 +
   1.669 +  public:
   1.670 +    js::Bindings    bindings;   /* names of top-level variables in this script
   1.671 +                                   (and arguments if this is a function script) */
   1.672 +
   1.673 +    bool hasAnyAliasedBindings() const {
   1.674 +        return bindings.hasAnyAliasedBindings();
   1.675 +    }
   1.676 +
   1.677 +    js::Binding *bindingArray() const {
   1.678 +        return bindings.bindingArray();
   1.679 +    }
   1.680 +
   1.681 +    unsigned numArgs() const {
   1.682 +        return bindings.numArgs();
   1.683 +    }
   1.684 +
   1.685 +    js::Shape *callObjShape() const {
   1.686 +        return bindings.callObjShape();
   1.687 +    }
   1.688 +
   1.689 +    // Word-sized fields.
   1.690 +
   1.691 +  private:
   1.692 +    jsbytecode      *code_;     /* bytecodes and their immediate operands */
   1.693 +  public:
   1.694 +    uint8_t         *data;      /* pointer to variable-length data array (see
   1.695 +                                   comment above Create() for details) */
   1.696 +
   1.697 +    js::HeapPtrAtom *atoms;     /* maps immediate index to literal struct */
   1.698 +
   1.699 +    JSCompartment   *compartment_;
   1.700 +
   1.701 +    /* Persistent type information retained across GCs. */
   1.702 +    js::types::TypeScript *types;
   1.703 +
   1.704 +  private:
   1.705 +    // This script's ScriptSourceObject, or a CCW thereof.
   1.706 +    //
   1.707 +    // (When we clone a JSScript into a new compartment, we don't clone its
   1.708 +    // source object. Instead, the clone refers to a wrapper.)
   1.709 +    js::HeapPtrObject sourceObject_;
   1.710 +
   1.711 +    js::HeapPtrFunction function_;
   1.712 +
   1.713 +    // For callsite clones, which cannot have enclosing scopes, the original
   1.714 +    // function; otherwise the enclosing scope
   1.715 +    js::HeapPtrObject   enclosingScopeOrOriginalFunction_;
   1.716 +
   1.717 +    /* Information attached by Baseline/Ion for sequential mode execution. */
   1.718 +    js::jit::IonScript *ion;
   1.719 +    js::jit::BaselineScript *baseline;
   1.720 +
   1.721 +    /* Information attached by Ion for parallel mode execution */
   1.722 +    js::jit::IonScript *parallelIon;
   1.723 +
   1.724 +    /* Information used to re-lazify a lazily-parsed interpreted function. */
   1.725 +    js::LazyScript *lazyScript;
   1.726 +
   1.727 +    /*
   1.728 +     * Pointer to either baseline->method()->raw() or ion->method()->raw(), or
   1.729 +     * nullptr if there's no Baseline or Ion script.
   1.730 +     */
   1.731 +    uint8_t *baselineOrIonRaw;
   1.732 +    uint8_t *baselineOrIonSkipArgCheck;
   1.733 +
   1.734 +    // 32-bit fields.
   1.735 +
   1.736 +    uint32_t        length_;    /* length of code vector */
   1.737 +    uint32_t        dataSize_;  /* size of the used part of the data array */
   1.738 +
   1.739 +    uint32_t        lineno_;    /* base line number of script */
   1.740 +    uint32_t        column_;    /* base column of script, optionally set */
   1.741 +
   1.742 +    uint32_t        mainOffset_;/* offset of main entry point from code, after
   1.743 +                                   predef'ing prolog */
   1.744 +
   1.745 +    uint32_t        natoms_;    /* length of atoms array */
   1.746 +    uint32_t        nslots_;    /* vars plus maximum stack depth */
   1.747 +
   1.748 +    /* Range of characters in scriptSource which contains this script's source. */
   1.749 +    uint32_t        sourceStart_;
   1.750 +    uint32_t        sourceEnd_;
   1.751 +
   1.752 +    uint32_t        useCount;   /* Number of times the script has been called
   1.753 +                                 * or has had backedges taken. When running in
   1.754 +                                 * ion, also increased for any inlined scripts.
   1.755 +                                 * Reset if the script's JIT code is forcibly
   1.756 +                                 * discarded. */
   1.757 +
   1.758 +#ifdef DEBUG
   1.759 +    // Unique identifier within the compartment for this script, used for
   1.760 +    // printing analysis information.
   1.761 +    uint32_t        id_;
   1.762 +    uint32_t        idpad;
   1.763 +#endif
   1.764 +
   1.765 +    // 16-bit fields.
   1.766 +
   1.767 +    uint16_t        version;    /* JS version under which script was compiled */
   1.768 +
   1.769 +    uint16_t        funLength_; /* ES6 function length */
   1.770 +
   1.771 +    uint16_t        nTypeSets_; /* number of type sets used in this script for
   1.772 +                                   dynamic type monitoring */
   1.773 +
   1.774 +    uint16_t        staticLevel_;/* static level for display maintenance */
   1.775 +
   1.776 +    // Bit fields.
   1.777 +
   1.778 +  public:
   1.779 +    // The kinds of the optional arrays.
   1.780 +    enum ArrayKind {
   1.781 +        CONSTS,
   1.782 +        OBJECTS,
   1.783 +        REGEXPS,
   1.784 +        TRYNOTES,
   1.785 +        BLOCK_SCOPES,
   1.786 +        ARRAY_KIND_BITS
   1.787 +    };
   1.788 +
   1.789 +  private:
   1.790 +    // The bits in this field indicate the presence/non-presence of several
   1.791 +    // optional arrays in |data|.  See the comments above Create() for details.
   1.792 +    uint8_t         hasArrayBits:ARRAY_KIND_BITS;
   1.793 +
   1.794 +    // The GeneratorKind of the script.
   1.795 +    uint8_t         generatorKindBits_:2;
   1.796 +
   1.797 +    // 1-bit fields.
   1.798 +
   1.799 +    // No need for result value of last expression statement.
   1.800 +    bool noScriptRval_:1;
   1.801 +
   1.802 +    // Can call getCallerFunction().
   1.803 +    bool savedCallerFun_:1;
   1.804 +
   1.805 +    // Code is in strict mode.
   1.806 +    bool strict_:1;
   1.807 +
   1.808 +    // Code has "use strict"; explicitly.
   1.809 +    bool explicitUseStrict_:1;
   1.810 +
   1.811 +    // See Parser::compileAndGo.
   1.812 +    bool compileAndGo_:1;
   1.813 +
   1.814 +    // see Parser::selfHostingMode.
   1.815 +    bool selfHosted_:1;
   1.816 +
   1.817 +    // See FunctionContextFlags.
   1.818 +    bool bindingsAccessedDynamically_:1;
   1.819 +    bool funHasExtensibleScope_:1;
   1.820 +    bool funNeedsDeclEnvObject_:1;
   1.821 +
   1.822 +    // True if any formalIsAliased(i).
   1.823 +    bool funHasAnyAliasedFormal_:1;
   1.824 +
   1.825 +    // Have warned about uses of undefined properties in this script.
   1.826 +    bool warnedAboutUndefinedProp_:1;
   1.827 +
   1.828 +    // Script has singleton objects.
   1.829 +    bool hasSingletons_:1;
   1.830 +
   1.831 +    // Script is a lambda to treat as running once.
   1.832 +    bool treatAsRunOnce_:1;
   1.833 +
   1.834 +    // If treatAsRunOnce, whether script has executed.
   1.835 +    bool hasRunOnce_:1;
   1.836 +
   1.837 +    // Script has been reused for a clone.
   1.838 +    bool hasBeenCloned_:1;
   1.839 +
   1.840 +    // Script has been inlined at least once, and can't be relazified.
   1.841 +    bool hasBeenInlined_:1;
   1.842 +
   1.843 +    // Script came from eval(), and is still active.
   1.844 +    bool isActiveEval_:1;
   1.845 +
   1.846 +    // Script came from eval(), and is in eval cache.
   1.847 +    bool isCachedEval_:1;
   1.848 +
   1.849 +    // Set for functions defined at the top level within an 'eval' script.
   1.850 +    bool directlyInsideEval_:1;
   1.851 +
   1.852 +    // Both 'arguments' and f.apply() are used. This is likely to be a wrapper.
   1.853 +    bool usesArgumentsAndApply_:1;
   1.854 +
   1.855 +    /* script is attempted to be cloned anew at each callsite. This is
   1.856 +       temporarily needed for ParallelArray selfhosted code until type
   1.857 +       information can be made context sensitive. See discussion in
   1.858 +       bug 826148. */
   1.859 +    bool shouldCloneAtCallsite_:1;
   1.860 +    bool isCallsiteClone_:1; /* is a callsite clone; has a link to the original function */
   1.861 +    bool shouldInline_:1;    /* hint to inline when possible */
   1.862 +
   1.863 +    // IonMonkey compilation hints.
   1.864 +    bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */
   1.865 +    bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */
   1.866 +    bool hadFrequentBailouts_:1;
   1.867 +    bool uninlineable_:1;    /* explicitly marked as uninlineable */
   1.868 +
   1.869 +    // Idempotent cache has triggered invalidation.
   1.870 +    bool invalidatedIdempotentCache_:1;
   1.871 +
   1.872 +    // If the generator was created implicitly via a generator expression,
   1.873 +    // isGeneratorExp will be true.
   1.874 +    bool isGeneratorExp_:1;
   1.875 +
   1.876 +    // Script has an entry in JSCompartment::scriptCountsMap.
   1.877 +    bool hasScriptCounts_:1;
   1.878 +
   1.879 +    // Script has an entry in JSCompartment::debugScriptMap.
   1.880 +    bool hasDebugScript_:1;
   1.881 +
   1.882 +    // Freeze constraints for stack type sets have been generated.
   1.883 +    bool hasFreezeConstraints_:1;
   1.884 +
   1.885 +    /* See comments below. */
   1.886 +    bool argsHasVarBinding_:1;
   1.887 +    bool needsArgsAnalysis_:1;
   1.888 +    bool needsArgsObj_:1;
   1.889 +
   1.890 +    //
   1.891 +    // End of fields.  Start methods.
   1.892 +    //
   1.893 +
   1.894 +  public:
   1.895 +    static JSScript *Create(js::ExclusiveContext *cx,
   1.896 +                            js::HandleObject enclosingScope, bool savedCallerFun,
   1.897 +                            const JS::ReadOnlyCompileOptions &options, unsigned staticLevel,
   1.898 +                            js::HandleObject sourceObject, uint32_t sourceStart,
   1.899 +                            uint32_t sourceEnd);
   1.900 +
   1.901 +    void initCompartment(js::ExclusiveContext *cx);
   1.902 +
   1.903 +    // Three ways ways to initialize a JSScript. Callers of partiallyInit()
   1.904 +    // and fullyInitTrivial() are responsible for notifying the debugger after
   1.905 +    // successfully creating any kind (function or other) of new JSScript.
   1.906 +    // However, callers of fullyInitFromEmitter() do not need to do this.
   1.907 +    static bool partiallyInit(js::ExclusiveContext *cx, JS::Handle<JSScript*> script,
   1.908 +                              uint32_t nconsts, uint32_t nobjects, uint32_t nregexps,
   1.909 +                              uint32_t ntrynotes, uint32_t nblockscopes,
   1.910 +                              uint32_t nTypeSets);
   1.911 +    static bool fullyInitFromEmitter(js::ExclusiveContext *cx, JS::Handle<JSScript*> script,
   1.912 +                                     js::frontend::BytecodeEmitter *bce);
   1.913 +    // Initialize a no-op script.
   1.914 +    static bool fullyInitTrivial(js::ExclusiveContext *cx, JS::Handle<JSScript*> script);
   1.915 +
   1.916 +    inline JSPrincipals *principals();
   1.917 +
   1.918 +    JSCompartment *compartment() const { return compartment_; }
   1.919 +
   1.920 +    void setVersion(JSVersion v) { version = v; }
   1.921 +
   1.922 +    // Script bytecode is immutable after creation.
   1.923 +    jsbytecode *code() const {
   1.924 +        return code_;
   1.925 +    }
   1.926 +    size_t length() const {
   1.927 +        return length_;
   1.928 +    }
   1.929 +
   1.930 +    void setCode(jsbytecode *code) { code_ = code; }
   1.931 +    void setLength(size_t length) { length_ = length; }
   1.932 +
   1.933 +    jsbytecode *codeEnd() const { return code() + length(); }
   1.934 +
   1.935 +    bool containsPC(const jsbytecode *pc) const {
   1.936 +        return pc >= code() && pc < codeEnd();
   1.937 +    }
   1.938 +
   1.939 +    size_t pcToOffset(const jsbytecode *pc) const {
   1.940 +        JS_ASSERT(containsPC(pc));
   1.941 +        return size_t(pc - code());
   1.942 +    }
   1.943 +
   1.944 +    jsbytecode *offsetToPC(size_t offset) const {
   1.945 +        JS_ASSERT(offset < length());
   1.946 +        return code() + offset;
   1.947 +    }
   1.948 +
   1.949 +    size_t mainOffset() const {
   1.950 +        return mainOffset_;
   1.951 +    }
   1.952 +
   1.953 +    size_t lineno() const {
   1.954 +        return lineno_;
   1.955 +    }
   1.956 +
   1.957 +    size_t column() const {
   1.958 +        return column_;
   1.959 +    }
   1.960 +
   1.961 +    void setColumn(size_t column) { column_ = column; }
   1.962 +
   1.963 +    // The fixed part of a stack frame is comprised of vars (in function code)
   1.964 +    // and block-scoped locals (in all kinds of code).
   1.965 +    size_t nfixed() const {
   1.966 +        return function_ ? bindings.numLocals() : bindings.numBlockScoped();
   1.967 +    }
   1.968 +
   1.969 +    // Number of fixed slots reserved for vars.  Only nonzero for function code.
   1.970 +    size_t nfixedvars() const {
   1.971 +        return function_ ? bindings.numVars() : 0;
   1.972 +    }
   1.973 +
   1.974 +    size_t nslots() const {
   1.975 +        return nslots_;
   1.976 +    }
   1.977 +
   1.978 +    size_t staticLevel() const {
   1.979 +        return staticLevel_;
   1.980 +    }
   1.981 +
   1.982 +    size_t nTypeSets() const {
   1.983 +        return nTypeSets_;
   1.984 +    }
   1.985 +
   1.986 +    size_t funLength() const {
   1.987 +        return funLength_;
   1.988 +    }
   1.989 +
   1.990 +    size_t sourceStart() const {
   1.991 +        return sourceStart_;
   1.992 +    }
   1.993 +
   1.994 +    size_t sourceEnd() const {
   1.995 +        return sourceEnd_;
   1.996 +    }
   1.997 +
   1.998 +    bool noScriptRval() const {
   1.999 +        return noScriptRval_;
  1.1000 +    }
  1.1001 +
  1.1002 +    bool savedCallerFun() const { return savedCallerFun_; }
  1.1003 +
  1.1004 +    bool strict() const {
  1.1005 +        return strict_;
  1.1006 +    }
  1.1007 +
  1.1008 +    bool explicitUseStrict() const { return explicitUseStrict_; }
  1.1009 +
  1.1010 +    bool compileAndGo() const {
  1.1011 +        return compileAndGo_;
  1.1012 +    }
  1.1013 +
  1.1014 +    bool selfHosted() const { return selfHosted_; }
  1.1015 +    bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
  1.1016 +    bool funHasExtensibleScope() const {
  1.1017 +        return funHasExtensibleScope_;
  1.1018 +    }
  1.1019 +    bool funNeedsDeclEnvObject() const {
  1.1020 +        return funNeedsDeclEnvObject_;
  1.1021 +    }
  1.1022 +    bool funHasAnyAliasedFormal() const {
  1.1023 +        return funHasAnyAliasedFormal_;
  1.1024 +    }
  1.1025 +
  1.1026 +    bool hasSingletons() const { return hasSingletons_; }
  1.1027 +    bool treatAsRunOnce() const {
  1.1028 +        return treatAsRunOnce_;
  1.1029 +    }
  1.1030 +    bool hasRunOnce() const { return hasRunOnce_; }
  1.1031 +    bool hasBeenCloned() const { return hasBeenCloned_; }
  1.1032 +    bool hasBeenInlined() const { return hasBeenInlined_; }
  1.1033 +
  1.1034 +    void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
  1.1035 +    void setHasRunOnce() { hasRunOnce_ = true; }
  1.1036 +    void setHasBeenCloned() { hasBeenCloned_ = true; }
  1.1037 +    void setHasBeenInlined() { hasBeenInlined_ = true; }
  1.1038 +
  1.1039 +    bool isActiveEval() const { return isActiveEval_; }
  1.1040 +    bool isCachedEval() const { return isCachedEval_; }
  1.1041 +    bool directlyInsideEval() const { return directlyInsideEval_; }
  1.1042 +
  1.1043 +    void cacheForEval() {
  1.1044 +        JS_ASSERT(isActiveEval() && !isCachedEval());
  1.1045 +        isActiveEval_ = false;
  1.1046 +        isCachedEval_ = true;
  1.1047 +    }
  1.1048 +
  1.1049 +    void uncacheForEval() {
  1.1050 +        JS_ASSERT(isCachedEval() && !isActiveEval());
  1.1051 +        isCachedEval_ = false;
  1.1052 +        isActiveEval_ = true;
  1.1053 +    }
  1.1054 +
  1.1055 +    void setActiveEval() { isActiveEval_ = true; }
  1.1056 +    void setDirectlyInsideEval() { directlyInsideEval_ = true; }
  1.1057 +
  1.1058 +    bool usesArgumentsAndApply() const {
  1.1059 +        return usesArgumentsAndApply_;
  1.1060 +    }
  1.1061 +    void setUsesArgumentsAndApply() { usesArgumentsAndApply_ = true; }
  1.1062 +
  1.1063 +    bool shouldCloneAtCallsite() const {
  1.1064 +        return shouldCloneAtCallsite_;
  1.1065 +    }
  1.1066 +    bool shouldInline() const {
  1.1067 +        return shouldInline_;
  1.1068 +    }
  1.1069 +
  1.1070 +    void setShouldCloneAtCallsite() { shouldCloneAtCallsite_ = true; }
  1.1071 +    void setShouldInline() { shouldInline_ = true; }
  1.1072 +
  1.1073 +    bool isCallsiteClone() const {
  1.1074 +        return isCallsiteClone_;
  1.1075 +    }
  1.1076 +    bool isGeneratorExp() const { return isGeneratorExp_; }
  1.1077 +
  1.1078 +    bool failedBoundsCheck() const {
  1.1079 +        return failedBoundsCheck_;
  1.1080 +    }
  1.1081 +    bool failedShapeGuard() const {
  1.1082 +        return failedShapeGuard_;
  1.1083 +    }
  1.1084 +    bool hadFrequentBailouts() const {
  1.1085 +        return hadFrequentBailouts_;
  1.1086 +    }
  1.1087 +    bool uninlineable() const {
  1.1088 +        return uninlineable_;
  1.1089 +    }
  1.1090 +    bool invalidatedIdempotentCache() const {
  1.1091 +        return invalidatedIdempotentCache_;
  1.1092 +    }
  1.1093 +
  1.1094 +    void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
  1.1095 +    void setFailedShapeGuard() { failedShapeGuard_ = true; }
  1.1096 +    void setHadFrequentBailouts() { hadFrequentBailouts_ = true; }
  1.1097 +    void setUninlineable() { uninlineable_ = true; }
  1.1098 +    void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
  1.1099 +
  1.1100 +    bool hasScriptCounts() const { return hasScriptCounts_; }
  1.1101 +
  1.1102 +    bool hasFreezeConstraints() const { return hasFreezeConstraints_; }
  1.1103 +    void setHasFreezeConstraints() { hasFreezeConstraints_ = true; }
  1.1104 +    void clearHasFreezeConstraints() { hasFreezeConstraints_ = false; }
  1.1105 +
  1.1106 +    bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; }
  1.1107 +    void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; }
  1.1108 +
  1.1109 +    /* See ContextFlags::funArgumentsHasLocalBinding comment. */
  1.1110 +    bool argumentsHasVarBinding() const {
  1.1111 +        return argsHasVarBinding_;
  1.1112 +    }
  1.1113 +    jsbytecode *argumentsBytecode() const { JS_ASSERT(code()[0] == JSOP_ARGUMENTS); return code(); }
  1.1114 +    void setArgumentsHasVarBinding();
  1.1115 +    bool argumentsAliasesFormals() const {
  1.1116 +        return argumentsHasVarBinding() && !strict();
  1.1117 +    }
  1.1118 +
  1.1119 +    js::GeneratorKind generatorKind() const {
  1.1120 +        return js::GeneratorKindFromBits(generatorKindBits_);
  1.1121 +    }
  1.1122 +    bool isGenerator() const { return generatorKind() != js::NotGenerator; }
  1.1123 +    bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
  1.1124 +    bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
  1.1125 +    void setGeneratorKind(js::GeneratorKind kind) {
  1.1126 +        // A script only gets its generator kind set as part of initialization,
  1.1127 +        // so it can only transition from not being a generator.
  1.1128 +        JS_ASSERT(!isGenerator());
  1.1129 +        generatorKindBits_ = GeneratorKindAsBits(kind);
  1.1130 +    }
  1.1131 +
  1.1132 +    /*
  1.1133 +     * As an optimization, even when argsHasLocalBinding, the function prologue
  1.1134 +     * may not need to create an arguments object. This is determined by
  1.1135 +     * needsArgsObj which is set by AnalyzeArgumentsUsage before running
  1.1136 +     * the script the first time. When !needsArgsObj, the prologue may simply
  1.1137 +     * write MagicValue(JS_OPTIMIZED_ARGUMENTS) to 'arguments's slot and any
  1.1138 +     * uses of 'arguments' will be guaranteed to handle this magic value.
  1.1139 +     * So avoid spurious arguments object creation, we maintain the invariant
  1.1140 +     * that needsArgsObj is only called after the script has been analyzed.
  1.1141 +     */
  1.1142 +    bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
  1.1143 +    inline bool ensureHasAnalyzedArgsUsage(JSContext *cx);
  1.1144 +    bool needsArgsObj() const {
  1.1145 +        JS_ASSERT(analyzedArgsUsage());
  1.1146 +        return needsArgsObj_;
  1.1147 +    }
  1.1148 +    void setNeedsArgsObj(bool needsArgsObj);
  1.1149 +    static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script);
  1.1150 +
  1.1151 +    /*
  1.1152 +     * Arguments access (via JSOP_*ARG* opcodes) must access the canonical
  1.1153 +     * location for the argument. If an arguments object exists AND this is a
  1.1154 +     * non-strict function (where 'arguments' aliases formals), then all access
  1.1155 +     * must go through the arguments object. Otherwise, the local slot is the
  1.1156 +     * canonical location for the arguments. Note: if a formal is aliased
  1.1157 +     * through the scope chain, then script->formalIsAliased and JSOP_*ARG*
  1.1158 +     * opcodes won't be emitted at all.
  1.1159 +     */
  1.1160 +    bool argsObjAliasesFormals() const {
  1.1161 +        return needsArgsObj() && !strict();
  1.1162 +    }
  1.1163 +
  1.1164 +    bool hasAnyIonScript() const {
  1.1165 +        return hasIonScript() || hasParallelIonScript();
  1.1166 +    }
  1.1167 +
  1.1168 +    bool hasIonScript() const {
  1.1169 +        bool res = ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT;
  1.1170 +        MOZ_ASSERT_IF(res, baseline);
  1.1171 +        return res;
  1.1172 +    }
  1.1173 +    bool canIonCompile() const {
  1.1174 +        return ion != ION_DISABLED_SCRIPT;
  1.1175 +    }
  1.1176 +
  1.1177 +    bool isIonCompilingOffThread() const {
  1.1178 +        return ion == ION_COMPILING_SCRIPT;
  1.1179 +    }
  1.1180 +
  1.1181 +    js::jit::IonScript *ionScript() const {
  1.1182 +        JS_ASSERT(hasIonScript());
  1.1183 +        return ion;
  1.1184 +    }
  1.1185 +    js::jit::IonScript *maybeIonScript() const {
  1.1186 +        return ion;
  1.1187 +    }
  1.1188 +    js::jit::IonScript *const *addressOfIonScript() const {
  1.1189 +        return &ion;
  1.1190 +    }
  1.1191 +    void setIonScript(js::jit::IonScript *ionScript) {
  1.1192 +        if (hasIonScript())
  1.1193 +            js::jit::IonScript::writeBarrierPre(tenuredZone(), ion);
  1.1194 +        ion = ionScript;
  1.1195 +        MOZ_ASSERT_IF(hasIonScript(), hasBaselineScript());
  1.1196 +        updateBaselineOrIonRaw();
  1.1197 +    }
  1.1198 +
  1.1199 +    bool hasBaselineScript() const {
  1.1200 +        bool res = baseline && baseline != BASELINE_DISABLED_SCRIPT;
  1.1201 +        MOZ_ASSERT_IF(!res, !ion || ion == ION_DISABLED_SCRIPT);
  1.1202 +        return res;
  1.1203 +    }
  1.1204 +    bool canBaselineCompile() const {
  1.1205 +        return baseline != BASELINE_DISABLED_SCRIPT;
  1.1206 +    }
  1.1207 +    js::jit::BaselineScript *baselineScript() const {
  1.1208 +        JS_ASSERT(hasBaselineScript());
  1.1209 +        return baseline;
  1.1210 +    }
  1.1211 +    inline void setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript);
  1.1212 +
  1.1213 +    void updateBaselineOrIonRaw();
  1.1214 +
  1.1215 +    bool hasParallelIonScript() const {
  1.1216 +        return parallelIon && parallelIon != ION_DISABLED_SCRIPT && parallelIon != ION_COMPILING_SCRIPT;
  1.1217 +    }
  1.1218 +
  1.1219 +    bool canParallelIonCompile() const {
  1.1220 +        return parallelIon != ION_DISABLED_SCRIPT;
  1.1221 +    }
  1.1222 +
  1.1223 +    bool isParallelIonCompilingOffThread() const {
  1.1224 +        return parallelIon == ION_COMPILING_SCRIPT;
  1.1225 +    }
  1.1226 +
  1.1227 +    js::jit::IonScript *parallelIonScript() const {
  1.1228 +        JS_ASSERT(hasParallelIonScript());
  1.1229 +        return parallelIon;
  1.1230 +    }
  1.1231 +    js::jit::IonScript *maybeParallelIonScript() const {
  1.1232 +        return parallelIon;
  1.1233 +    }
  1.1234 +    void setParallelIonScript(js::jit::IonScript *ionScript) {
  1.1235 +        if (hasParallelIonScript())
  1.1236 +            js::jit::IonScript::writeBarrierPre(tenuredZone(), parallelIon);
  1.1237 +        parallelIon = ionScript;
  1.1238 +    }
  1.1239 +
  1.1240 +    static size_t offsetOfBaselineScript() {
  1.1241 +        return offsetof(JSScript, baseline);
  1.1242 +    }
  1.1243 +    static size_t offsetOfIonScript() {
  1.1244 +        return offsetof(JSScript, ion);
  1.1245 +    }
  1.1246 +    static size_t offsetOfParallelIonScript() {
  1.1247 +        return offsetof(JSScript, parallelIon);
  1.1248 +    }
  1.1249 +    static size_t offsetOfBaselineOrIonRaw() {
  1.1250 +        return offsetof(JSScript, baselineOrIonRaw);
  1.1251 +    }
  1.1252 +    static size_t offsetOfBaselineOrIonSkipArgCheck() {
  1.1253 +        return offsetof(JSScript, baselineOrIonSkipArgCheck);
  1.1254 +    }
  1.1255 +
  1.1256 +    bool isRelazifiable() const {
  1.1257 +        return (selfHosted() || lazyScript) &&
  1.1258 +               !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && !hasBeenInlined();
  1.1259 +    }
  1.1260 +    void setLazyScript(js::LazyScript *lazy) {
  1.1261 +        lazyScript = lazy;
  1.1262 +    }
  1.1263 +    js::LazyScript *maybeLazyScript() {
  1.1264 +        return lazyScript;
  1.1265 +    }
  1.1266 +
  1.1267 +    /*
  1.1268 +     * Original compiled function for the script, if it has a function.
  1.1269 +     * nullptr for global and eval scripts.
  1.1270 +     * The delazifying variant ensures that the function isn't lazy. The
  1.1271 +     * non-delazifying variant must only be used after earlier code has
  1.1272 +     * called ensureNonLazyCanonicalFunction and while the function can't
  1.1273 +     * have been relazified.
  1.1274 +     */
  1.1275 +    inline JSFunction *functionDelazifying() const;
  1.1276 +    JSFunction *functionNonDelazifying() const {
  1.1277 +        return function_;
  1.1278 +    }
  1.1279 +    inline void setFunction(JSFunction *fun);
  1.1280 +    /*
  1.1281 +     * De-lazifies the canonical function. Must be called before entering code
  1.1282 +     * that expects the function to be non-lazy.
  1.1283 +     */
  1.1284 +    inline void ensureNonLazyCanonicalFunction(JSContext *cx);
  1.1285 +
  1.1286 +    /*
  1.1287 +     * Donor provided itself to callsite clone; null if this is non-clone.
  1.1288 +     */
  1.1289 +    JSFunction *donorFunction() const;
  1.1290 +    void setIsCallsiteClone(JSObject *fun);
  1.1291 +
  1.1292 +    JSFlatString *sourceData(JSContext *cx);
  1.1293 +
  1.1294 +    static bool loadSource(JSContext *cx, js::ScriptSource *ss, bool *worked);
  1.1295 +
  1.1296 +    void setSourceObject(JSObject *object);
  1.1297 +    JSObject *sourceObject() const {
  1.1298 +        return sourceObject_;
  1.1299 +    }
  1.1300 +    js::ScriptSourceObject &scriptSourceUnwrap() const;
  1.1301 +    js::ScriptSource *scriptSource() const;
  1.1302 +    JSPrincipals *originPrincipals() const { return scriptSource()->originPrincipals(); }
  1.1303 +    const char *filename() const { return scriptSource()->filename(); }
  1.1304 +
  1.1305 +  public:
  1.1306 +
  1.1307 +    /* Return whether this script was compiled for 'eval' */
  1.1308 +    bool isForEval() { return isCachedEval() || isActiveEval(); }
  1.1309 +
  1.1310 +#ifdef DEBUG
  1.1311 +    unsigned id();
  1.1312 +#else
  1.1313 +    unsigned id() { return 0; }
  1.1314 +#endif
  1.1315 +
  1.1316 +    /* Ensure the script has a TypeScript. */
  1.1317 +    inline bool ensureHasTypes(JSContext *cx);
  1.1318 +
  1.1319 +    inline js::GlobalObject &global() const;
  1.1320 +    js::GlobalObject &uninlinedGlobal() const;
  1.1321 +
  1.1322 +    /* See StaticScopeIter comment. */
  1.1323 +    JSObject *enclosingStaticScope() const {
  1.1324 +        if (isCallsiteClone())
  1.1325 +            return nullptr;
  1.1326 +        return enclosingScopeOrOriginalFunction_;
  1.1327 +    }
  1.1328 +
  1.1329 +  private:
  1.1330 +    bool makeTypes(JSContext *cx);
  1.1331 +
  1.1332 +  public:
  1.1333 +    uint32_t getUseCount() const {
  1.1334 +        return useCount;
  1.1335 +    }
  1.1336 +    uint32_t incUseCount(uint32_t amount = 1) { return useCount += amount; }
  1.1337 +    uint32_t *addressOfUseCount() { return &useCount; }
  1.1338 +    static size_t offsetOfUseCount() { return offsetof(JSScript, useCount); }
  1.1339 +    void resetUseCount() { useCount = 0; }
  1.1340 +
  1.1341 +  public:
  1.1342 +    bool initScriptCounts(JSContext *cx);
  1.1343 +    js::PCCounts getPCCounts(jsbytecode *pc);
  1.1344 +    void addIonCounts(js::jit::IonScriptCounts *ionCounts);
  1.1345 +    js::jit::IonScriptCounts *getIonCounts();
  1.1346 +    js::ScriptCounts releaseScriptCounts();
  1.1347 +    void destroyScriptCounts(js::FreeOp *fop);
  1.1348 +
  1.1349 +    jsbytecode *main() {
  1.1350 +        return code() + mainOffset();
  1.1351 +    }
  1.1352 +
  1.1353 +    /*
  1.1354 +     * computedSizeOfData() is the in-use size of all the data sections.
  1.1355 +     * sizeOfData() is the size of the block allocated to hold all the data
  1.1356 +     * sections (which can be larger than the in-use size).
  1.1357 +     */
  1.1358 +    size_t computedSizeOfData() const;
  1.1359 +    size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const;
  1.1360 +    size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
  1.1361 +
  1.1362 +    uint32_t numNotes();  /* Number of srcnote slots in the srcnotes section */
  1.1363 +
  1.1364 +    /* Script notes are allocated right after the code. */
  1.1365 +    jssrcnote *notes() { return (jssrcnote *)(code() + length()); }
  1.1366 +
  1.1367 +    bool hasArray(ArrayKind kind) {
  1.1368 +        return hasArrayBits & (1 << kind);
  1.1369 +    }
  1.1370 +    void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
  1.1371 +    void cloneHasArray(JSScript *script) { hasArrayBits = script->hasArrayBits; }
  1.1372 +
  1.1373 +    bool hasConsts()        { return hasArray(CONSTS);      }
  1.1374 +    bool hasObjects()       { return hasArray(OBJECTS);     }
  1.1375 +    bool hasRegexps()       { return hasArray(REGEXPS);     }
  1.1376 +    bool hasTrynotes()      { return hasArray(TRYNOTES);    }
  1.1377 +    bool hasBlockScopes()   { return hasArray(BLOCK_SCOPES); }
  1.1378 +
  1.1379 +    #define OFF(fooOff, hasFoo, t)   (fooOff() + (hasFoo() ? sizeof(t) : 0))
  1.1380 +
  1.1381 +    size_t constsOffset()     { return 0; }
  1.1382 +    size_t objectsOffset()    { return OFF(constsOffset,     hasConsts,     js::ConstArray);      }
  1.1383 +    size_t regexpsOffset()    { return OFF(objectsOffset,    hasObjects,    js::ObjectArray);     }
  1.1384 +    size_t trynotesOffset()   { return OFF(regexpsOffset,    hasRegexps,    js::ObjectArray);     }
  1.1385 +    size_t blockScopesOffset(){ return OFF(trynotesOffset,   hasTrynotes,   js::TryNoteArray);    }
  1.1386 +
  1.1387 +    size_t dataSize() const { return dataSize_; }
  1.1388 +
  1.1389 +    js::ConstArray *consts() {
  1.1390 +        JS_ASSERT(hasConsts());
  1.1391 +        return reinterpret_cast<js::ConstArray *>(data + constsOffset());
  1.1392 +    }
  1.1393 +
  1.1394 +    js::ObjectArray *objects() {
  1.1395 +        JS_ASSERT(hasObjects());
  1.1396 +        return reinterpret_cast<js::ObjectArray *>(data + objectsOffset());
  1.1397 +    }
  1.1398 +
  1.1399 +    js::ObjectArray *regexps() {
  1.1400 +        JS_ASSERT(hasRegexps());
  1.1401 +        return reinterpret_cast<js::ObjectArray *>(data + regexpsOffset());
  1.1402 +    }
  1.1403 +
  1.1404 +    js::TryNoteArray *trynotes() {
  1.1405 +        JS_ASSERT(hasTrynotes());
  1.1406 +        return reinterpret_cast<js::TryNoteArray *>(data + trynotesOffset());
  1.1407 +    }
  1.1408 +
  1.1409 +    js::BlockScopeArray *blockScopes() {
  1.1410 +        JS_ASSERT(hasBlockScopes());
  1.1411 +        return reinterpret_cast<js::BlockScopeArray *>(data + blockScopesOffset());
  1.1412 +    }
  1.1413 +
  1.1414 +    bool hasLoops();
  1.1415 +
  1.1416 +    size_t natoms() const { return natoms_; }
  1.1417 +
  1.1418 +    js::HeapPtrAtom &getAtom(size_t index) const {
  1.1419 +        JS_ASSERT(index < natoms());
  1.1420 +        return atoms[index];
  1.1421 +    }
  1.1422 +
  1.1423 +    js::HeapPtrAtom &getAtom(jsbytecode *pc) const {
  1.1424 +        JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
  1.1425 +        return getAtom(GET_UINT32_INDEX(pc));
  1.1426 +    }
  1.1427 +
  1.1428 +    js::PropertyName *getName(size_t index) {
  1.1429 +        return getAtom(index)->asPropertyName();
  1.1430 +    }
  1.1431 +
  1.1432 +    js::PropertyName *getName(jsbytecode *pc) const {
  1.1433 +        JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
  1.1434 +        return getAtom(GET_UINT32_INDEX(pc))->asPropertyName();
  1.1435 +    }
  1.1436 +
  1.1437 +    JSObject *getObject(size_t index) {
  1.1438 +        js::ObjectArray *arr = objects();
  1.1439 +        JS_ASSERT(index < arr->length);
  1.1440 +        return arr->vector[index];
  1.1441 +    }
  1.1442 +
  1.1443 +    size_t innerObjectsStart() {
  1.1444 +        // The first object contains the caller if savedCallerFun is used.
  1.1445 +        return savedCallerFun() ? 1 : 0;
  1.1446 +    }
  1.1447 +
  1.1448 +    JSObject *getObject(jsbytecode *pc) {
  1.1449 +        JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
  1.1450 +        return getObject(GET_UINT32_INDEX(pc));
  1.1451 +    }
  1.1452 +
  1.1453 +    JSVersion getVersion() const {
  1.1454 +        return JSVersion(version);
  1.1455 +    }
  1.1456 +
  1.1457 +    inline JSFunction *getFunction(size_t index);
  1.1458 +    inline JSFunction *getCallerFunction();
  1.1459 +    inline JSFunction *functionOrCallerFunction();
  1.1460 +
  1.1461 +    inline js::RegExpObject *getRegExp(size_t index);
  1.1462 +    inline js::RegExpObject *getRegExp(jsbytecode *pc);
  1.1463 +
  1.1464 +    const js::Value &getConst(size_t index) {
  1.1465 +        js::ConstArray *arr = consts();
  1.1466 +        JS_ASSERT(index < arr->length);
  1.1467 +        return arr->vector[index];
  1.1468 +    }
  1.1469 +
  1.1470 +    js::NestedScopeObject *getStaticScope(jsbytecode *pc);
  1.1471 +
  1.1472 +    /*
  1.1473 +     * The isEmpty method tells whether this script has code that computes any
  1.1474 +     * result (not return value, result AKA normal completion value) other than
  1.1475 +     * JSVAL_VOID, or any other effects.
  1.1476 +     */
  1.1477 +    bool isEmpty() const {
  1.1478 +        if (length() > 3)
  1.1479 +            return false;
  1.1480 +
  1.1481 +        jsbytecode *pc = code();
  1.1482 +        if (noScriptRval() && JSOp(*pc) == JSOP_FALSE)
  1.1483 +            ++pc;
  1.1484 +        return JSOp(*pc) == JSOP_RETRVAL;
  1.1485 +    }
  1.1486 +
  1.1487 +    bool varIsAliased(uint32_t varSlot);
  1.1488 +    bool formalIsAliased(unsigned argSlot);
  1.1489 +    bool formalLivesInArgumentsObject(unsigned argSlot);
  1.1490 +
  1.1491 +  private:
  1.1492 +    /* Change this->stepMode to |newValue|. */
  1.1493 +    void setNewStepMode(js::FreeOp *fop, uint32_t newValue);
  1.1494 +
  1.1495 +    bool ensureHasDebugScript(JSContext *cx);
  1.1496 +    js::DebugScript *debugScript();
  1.1497 +    js::DebugScript *releaseDebugScript();
  1.1498 +    void destroyDebugScript(js::FreeOp *fop);
  1.1499 +
  1.1500 +  public:
  1.1501 +    bool hasBreakpointsAt(jsbytecode *pc);
  1.1502 +    bool hasAnyBreakpointsOrStepMode() { return hasDebugScript_; }
  1.1503 +
  1.1504 +    js::BreakpointSite *getBreakpointSite(jsbytecode *pc)
  1.1505 +    {
  1.1506 +        return hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
  1.1507 +    }
  1.1508 +
  1.1509 +    js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc);
  1.1510 +
  1.1511 +    void destroyBreakpointSite(js::FreeOp *fop, jsbytecode *pc);
  1.1512 +
  1.1513 +    void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JSObject *handler);
  1.1514 +    void clearTraps(js::FreeOp *fop);
  1.1515 +
  1.1516 +    void markTrapClosures(JSTracer *trc);
  1.1517 +
  1.1518 +    /*
  1.1519 +     * Set or clear the single-step flag. If the flag is set or the count
  1.1520 +     * (adjusted by changeStepModeCount) is non-zero, then the script is in
  1.1521 +     * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
  1.1522 +     * count-style interface.)
  1.1523 +     */
  1.1524 +    bool setStepModeFlag(JSContext *cx, bool step);
  1.1525 +
  1.1526 +    /*
  1.1527 +     * Increment or decrement the single-step count. If the count is non-zero or
  1.1528 +     * the flag (set by setStepModeFlag) is set, then the script is in
  1.1529 +     * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
  1.1530 +     * count-style interface.)
  1.1531 +     *
  1.1532 +     * Only incrementing is fallible, as it could allocate a DebugScript.
  1.1533 +     */
  1.1534 +    bool incrementStepModeCount(JSContext *cx);
  1.1535 +    void decrementStepModeCount(js::FreeOp *fop);
  1.1536 +
  1.1537 +    bool stepModeEnabled() { return hasDebugScript_ && !!debugScript()->stepMode; }
  1.1538 +
  1.1539 +#ifdef DEBUG
  1.1540 +    uint32_t stepModeCount() { return hasDebugScript_ ? (debugScript()->stepMode & stepCountMask) : 0; }
  1.1541 +#endif
  1.1542 +
  1.1543 +    void finalize(js::FreeOp *fop);
  1.1544 +
  1.1545 +    static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SCRIPT; }
  1.1546 +
  1.1547 +    void markChildren(JSTracer *trc);
  1.1548 +};
  1.1549 +
  1.1550 +/* If this fails, add/remove padding within JSScript. */
  1.1551 +static_assert(sizeof(JSScript) % js::gc::CellSize == 0,
  1.1552 +              "Size of JSScript must be an integral multiple of js::gc::CellSize");
  1.1553 +
  1.1554 +namespace js {
  1.1555 +
  1.1556 +/*
  1.1557 + * Iterator over a script's bindings (formals and variables).
  1.1558 + * The order of iteration is:
  1.1559 + *  - first, formal arguments, from index 0 to numArgs
  1.1560 + *  - next, variables, from index 0 to numLocals
  1.1561 + */
  1.1562 +class BindingIter
  1.1563 +{
  1.1564 +    const InternalBindingsHandle bindings_;
  1.1565 +    uint32_t i_;
  1.1566 +
  1.1567 +    friend class Bindings;
  1.1568 +
  1.1569 +  public:
  1.1570 +    explicit BindingIter(const InternalBindingsHandle &bindings) : bindings_(bindings), i_(0) {}
  1.1571 +    explicit BindingIter(const HandleScript &script) : bindings_(script, &script->bindings), i_(0) {}
  1.1572 +
  1.1573 +    bool done() const { return i_ == bindings_->count(); }
  1.1574 +    operator bool() const { return !done(); }
  1.1575 +    void operator++(int) { JS_ASSERT(!done()); i_++; }
  1.1576 +    BindingIter &operator++() { (*this)++; return *this; }
  1.1577 +
  1.1578 +    uint32_t frameIndex() const {
  1.1579 +        JS_ASSERT(!done());
  1.1580 +        return i_ < bindings_->numArgs() ? i_ : i_ - bindings_->numArgs();
  1.1581 +    }
  1.1582 +
  1.1583 +    const Binding &operator*() const { JS_ASSERT(!done()); return bindings_->bindingArray()[i_]; }
  1.1584 +    const Binding *operator->() const { JS_ASSERT(!done()); return &bindings_->bindingArray()[i_]; }
  1.1585 +};
  1.1586 +
  1.1587 +/*
  1.1588 + * This helper function fills the given BindingVector with the sequential
  1.1589 + * values of BindingIter.
  1.1590 + */
  1.1591 +
  1.1592 +typedef Vector<Binding, 32> BindingVector;
  1.1593 +
  1.1594 +extern bool
  1.1595 +FillBindingVector(HandleScript fromScript, BindingVector *vec);
  1.1596 +
  1.1597 +/*
  1.1598 + * Iterator over the aliased formal bindings in ascending index order. This can
  1.1599 + * be veiwed as a filtering of BindingIter with predicate
  1.1600 + *   bi->aliased() && bi->kind() == Binding::ARGUMENT
  1.1601 + */
  1.1602 +class AliasedFormalIter
  1.1603 +{
  1.1604 +    const Binding *begin_, *p_, *end_;
  1.1605 +    unsigned slot_;
  1.1606 +
  1.1607 +    void settle() {
  1.1608 +        while (p_ != end_ && !p_->aliased())
  1.1609 +            p_++;
  1.1610 +    }
  1.1611 +
  1.1612 +  public:
  1.1613 +    explicit inline AliasedFormalIter(JSScript *script);
  1.1614 +
  1.1615 +    bool done() const { return p_ == end_; }
  1.1616 +    operator bool() const { return !done(); }
  1.1617 +    void operator++(int) { JS_ASSERT(!done()); p_++; slot_++; settle(); }
  1.1618 +
  1.1619 +    const Binding &operator*() const { JS_ASSERT(!done()); return *p_; }
  1.1620 +    const Binding *operator->() const { JS_ASSERT(!done()); return p_; }
  1.1621 +    unsigned frameIndex() const { JS_ASSERT(!done()); return p_ - begin_; }
  1.1622 +    unsigned scopeSlot() const { JS_ASSERT(!done()); return slot_; }
  1.1623 +};
  1.1624 +
  1.1625 +// Information about a script which may be (or has been) lazily compiled to
  1.1626 +// bytecode from its source.
  1.1627 +class LazyScript : public gc::BarrieredCell<LazyScript>
  1.1628 +{
  1.1629 +    // If non-nullptr, the script has been compiled and this is a forwarding
  1.1630 +    // pointer to the result.
  1.1631 +    HeapPtrScript script_;
  1.1632 +
  1.1633 +    // Original function with which the lazy script is associated.
  1.1634 +    HeapPtrFunction function_;
  1.1635 +
  1.1636 +    // Function or block chain in which the script is nested, or nullptr.
  1.1637 +    HeapPtrObject enclosingScope_;
  1.1638 +
  1.1639 +    // ScriptSourceObject, or nullptr if the script in which this is nested
  1.1640 +    // has not been compiled yet. This is never a CCW; we don't clone
  1.1641 +    // LazyScripts into other compartments.
  1.1642 +    HeapPtrObject sourceObject_;
  1.1643 +
  1.1644 +    // Heap allocated table with any free variables or inner functions.
  1.1645 +    void *table_;
  1.1646 +
  1.1647 +#if JS_BITS_PER_WORD == 32
  1.1648 +    uint32_t padding;
  1.1649 +#endif
  1.1650 +
  1.1651 +    struct PackedView {
  1.1652 +        // Assorted bits that should really be in ScriptSourceObject.
  1.1653 +        uint32_t version : 8;
  1.1654 +
  1.1655 +        uint32_t numFreeVariables : 24;
  1.1656 +        uint32_t numInnerFunctions : 23;
  1.1657 +
  1.1658 +        uint32_t generatorKindBits : 2;
  1.1659 +
  1.1660 +        // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
  1.1661 +        uint32_t strict : 1;
  1.1662 +        uint32_t bindingsAccessedDynamically : 1;
  1.1663 +        uint32_t hasDebuggerStatement : 1;
  1.1664 +        uint32_t directlyInsideEval : 1;
  1.1665 +        uint32_t usesArgumentsAndApply : 1;
  1.1666 +        uint32_t hasBeenCloned : 1;
  1.1667 +        uint32_t treatAsRunOnce : 1;
  1.1668 +    };
  1.1669 +
  1.1670 +    union {
  1.1671 +        PackedView p_;
  1.1672 +        uint64_t packedFields_;
  1.1673 +    };
  1.1674 +
  1.1675 +    // Source location for the script.
  1.1676 +    uint32_t begin_;
  1.1677 +    uint32_t end_;
  1.1678 +    uint32_t lineno_;
  1.1679 +    uint32_t column_;
  1.1680 +
  1.1681 +    LazyScript(JSFunction *fun, void *table, uint64_t packedFields,
  1.1682 +               uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column);
  1.1683 +
  1.1684 +    // Create a LazyScript without initializing the freeVariables and the
  1.1685 +    // innerFunctions. To be GC-safe, the caller must initialize both vectors
  1.1686 +    // with valid atoms and functions.
  1.1687 +    static LazyScript *CreateRaw(ExclusiveContext *cx, HandleFunction fun,
  1.1688 +                                 uint64_t packedData, uint32_t begin, uint32_t end,
  1.1689 +                                 uint32_t lineno, uint32_t column);
  1.1690 +
  1.1691 +  public:
  1.1692 +    // Create a LazyScript without initializing the freeVariables and the
  1.1693 +    // innerFunctions. To be GC-safe, the caller must initialize both vectors
  1.1694 +    // with valid atoms and functions.
  1.1695 +    static LazyScript *CreateRaw(ExclusiveContext *cx, HandleFunction fun,
  1.1696 +                                 uint32_t numFreeVariables, uint32_t numInnerFunctions,
  1.1697 +                                 JSVersion version, uint32_t begin, uint32_t end,
  1.1698 +                                 uint32_t lineno, uint32_t column);
  1.1699 +
  1.1700 +    // Create a LazyScript and initialize the freeVariables and the
  1.1701 +    // innerFunctions with dummy values to be replaced in a later initialization
  1.1702 +    // phase.
  1.1703 +    static LazyScript *Create(ExclusiveContext *cx, HandleFunction fun,
  1.1704 +                              uint64_t packedData, uint32_t begin, uint32_t end,
  1.1705 +                              uint32_t lineno, uint32_t column);
  1.1706 +
  1.1707 +    void initRuntimeFields(uint64_t packedFields);
  1.1708 +
  1.1709 +    inline JSFunction *functionDelazifying(JSContext *cx) const;
  1.1710 +    JSFunction *functionNonDelazifying() const {
  1.1711 +        return function_;
  1.1712 +    }
  1.1713 +
  1.1714 +    void initScript(JSScript *script);
  1.1715 +    void resetScript();
  1.1716 +    JSScript *maybeScript() {
  1.1717 +        return script_;
  1.1718 +    }
  1.1719 +
  1.1720 +    JSObject *enclosingScope() const {
  1.1721 +        return enclosingScope_;
  1.1722 +    }
  1.1723 +    ScriptSourceObject *sourceObject() const;
  1.1724 +    ScriptSource *scriptSource() const {
  1.1725 +        return sourceObject()->source();
  1.1726 +    }
  1.1727 +    JSPrincipals *originPrincipals() const {
  1.1728 +        return scriptSource()->originPrincipals();
  1.1729 +    }
  1.1730 +    JSVersion version() const {
  1.1731 +        JS_STATIC_ASSERT(JSVERSION_UNKNOWN == -1);
  1.1732 +        return (p_.version == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(p_.version);
  1.1733 +    }
  1.1734 +
  1.1735 +    void setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject);
  1.1736 +
  1.1737 +    uint32_t numFreeVariables() const {
  1.1738 +        return p_.numFreeVariables;
  1.1739 +    }
  1.1740 +    HeapPtrAtom *freeVariables() {
  1.1741 +        return (HeapPtrAtom *)table_;
  1.1742 +    }
  1.1743 +
  1.1744 +    uint32_t numInnerFunctions() const {
  1.1745 +        return p_.numInnerFunctions;
  1.1746 +    }
  1.1747 +    HeapPtrFunction *innerFunctions() {
  1.1748 +        return (HeapPtrFunction *)&freeVariables()[numFreeVariables()];
  1.1749 +    }
  1.1750 +
  1.1751 +    GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); }
  1.1752 +
  1.1753 +    bool isGenerator() const { return generatorKind() != NotGenerator; }
  1.1754 +
  1.1755 +    bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
  1.1756 +
  1.1757 +    bool isStarGenerator() const { return generatorKind() == StarGenerator; }
  1.1758 +
  1.1759 +    void setGeneratorKind(GeneratorKind kind) {
  1.1760 +        // A script only gets its generator kind set as part of initialization,
  1.1761 +        // so it can only transition from NotGenerator.
  1.1762 +        JS_ASSERT(!isGenerator());
  1.1763 +        // Legacy generators cannot currently be lazy.
  1.1764 +        JS_ASSERT(kind != LegacyGenerator);
  1.1765 +        p_.generatorKindBits = GeneratorKindAsBits(kind);
  1.1766 +    }
  1.1767 +
  1.1768 +    bool strict() const {
  1.1769 +        return p_.strict;
  1.1770 +    }
  1.1771 +    void setStrict() {
  1.1772 +        p_.strict = true;
  1.1773 +    }
  1.1774 +
  1.1775 +    bool bindingsAccessedDynamically() const {
  1.1776 +        return p_.bindingsAccessedDynamically;
  1.1777 +    }
  1.1778 +    void setBindingsAccessedDynamically() {
  1.1779 +        p_.bindingsAccessedDynamically = true;
  1.1780 +    }
  1.1781 +
  1.1782 +    bool hasDebuggerStatement() const {
  1.1783 +        return p_.hasDebuggerStatement;
  1.1784 +    }
  1.1785 +    void setHasDebuggerStatement() {
  1.1786 +        p_.hasDebuggerStatement = true;
  1.1787 +    }
  1.1788 +
  1.1789 +    bool directlyInsideEval() const {
  1.1790 +        return p_.directlyInsideEval;
  1.1791 +    }
  1.1792 +    void setDirectlyInsideEval() {
  1.1793 +        p_.directlyInsideEval = true;
  1.1794 +    }
  1.1795 +
  1.1796 +    bool usesArgumentsAndApply() const {
  1.1797 +        return p_.usesArgumentsAndApply;
  1.1798 +    }
  1.1799 +    void setUsesArgumentsAndApply() {
  1.1800 +        p_.usesArgumentsAndApply = true;
  1.1801 +    }
  1.1802 +
  1.1803 +    bool hasBeenCloned() const {
  1.1804 +        return p_.hasBeenCloned;
  1.1805 +    }
  1.1806 +    void setHasBeenCloned() {
  1.1807 +        p_.hasBeenCloned = true;
  1.1808 +    }
  1.1809 +
  1.1810 +    bool treatAsRunOnce() const {
  1.1811 +        return p_.treatAsRunOnce;
  1.1812 +    }
  1.1813 +    void setTreatAsRunOnce() {
  1.1814 +        p_.treatAsRunOnce = true;
  1.1815 +    }
  1.1816 +
  1.1817 +    ScriptSource *source() const {
  1.1818 +        return sourceObject()->source();
  1.1819 +    }
  1.1820 +    uint32_t begin() const {
  1.1821 +        return begin_;
  1.1822 +    }
  1.1823 +    uint32_t end() const {
  1.1824 +        return end_;
  1.1825 +    }
  1.1826 +    uint32_t lineno() const {
  1.1827 +        return lineno_;
  1.1828 +    }
  1.1829 +    uint32_t column() const {
  1.1830 +        return column_;
  1.1831 +    }
  1.1832 +
  1.1833 +    bool hasUncompiledEnclosingScript() const;
  1.1834 +    uint32_t staticLevel(JSContext *cx) const;
  1.1835 +
  1.1836 +    void markChildren(JSTracer *trc);
  1.1837 +    void finalize(js::FreeOp *fop);
  1.1838 +
  1.1839 +    static inline js::ThingRootKind rootKind() { return js::THING_ROOT_LAZY_SCRIPT; }
  1.1840 +
  1.1841 +    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
  1.1842 +    {
  1.1843 +        return mallocSizeOf(table_);
  1.1844 +    }
  1.1845 +
  1.1846 +    uint64_t packedFields() const {
  1.1847 +        return packedFields_;
  1.1848 +    }
  1.1849 +};
  1.1850 +
  1.1851 +/* If this fails, add/remove padding within LazyScript. */
  1.1852 +JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0);
  1.1853 +
  1.1854 +/*
  1.1855 + * New-script-hook calling is factored from JSScript::fullyInitFromEmitter() so
  1.1856 + * that it and callers of XDRScript() can share this code.  In the case of
  1.1857 + * callers of XDRScript(), the hook should be invoked only after successful
  1.1858 + * decode of any owning function (the fun parameter) or script object (null
  1.1859 + * fun).
  1.1860 + */
  1.1861 +extern void
  1.1862 +CallNewScriptHook(JSContext *cx, JS::HandleScript script, JS::HandleFunction fun);
  1.1863 +
  1.1864 +extern void
  1.1865 +CallDestroyScriptHook(FreeOp *fop, JSScript *script);
  1.1866 +
  1.1867 +struct SharedScriptData
  1.1868 +{
  1.1869 +    uint32_t length;
  1.1870 +    uint32_t natoms;
  1.1871 +    bool marked;
  1.1872 +    jsbytecode data[1];
  1.1873 +
  1.1874 +    static SharedScriptData *new_(ExclusiveContext *cx, uint32_t codeLength,
  1.1875 +                                  uint32_t srcnotesLength, uint32_t natoms);
  1.1876 +
  1.1877 +    HeapPtrAtom *atoms() {
  1.1878 +        if (!natoms)
  1.1879 +            return nullptr;
  1.1880 +        return reinterpret_cast<HeapPtrAtom *>(data + length - sizeof(JSAtom *) * natoms);
  1.1881 +    }
  1.1882 +
  1.1883 +    static SharedScriptData *fromBytecode(const jsbytecode *bytecode) {
  1.1884 +        return (SharedScriptData *)(bytecode - offsetof(SharedScriptData, data));
  1.1885 +    }
  1.1886 +
  1.1887 +  private:
  1.1888 +    SharedScriptData() MOZ_DELETE;
  1.1889 +    SharedScriptData(const SharedScriptData&) MOZ_DELETE;
  1.1890 +};
  1.1891 +
  1.1892 +struct ScriptBytecodeHasher
  1.1893 +{
  1.1894 +    struct Lookup
  1.1895 +    {
  1.1896 +        jsbytecode          *code;
  1.1897 +        uint32_t            length;
  1.1898 +
  1.1899 +        Lookup(SharedScriptData *ssd) : code(ssd->data), length(ssd->length) {}
  1.1900 +    };
  1.1901 +    static HashNumber hash(const Lookup &l) { return mozilla::HashBytes(l.code, l.length); }
  1.1902 +    static bool match(SharedScriptData *entry, const Lookup &lookup) {
  1.1903 +        if (entry->length != lookup.length)
  1.1904 +            return false;
  1.1905 +        return mozilla::PodEqual<jsbytecode>(entry->data, lookup.code, lookup.length);
  1.1906 +    }
  1.1907 +};
  1.1908 +
  1.1909 +typedef HashSet<SharedScriptData*,
  1.1910 +                ScriptBytecodeHasher,
  1.1911 +                SystemAllocPolicy> ScriptDataTable;
  1.1912 +
  1.1913 +extern void
  1.1914 +UnmarkScriptData(JSRuntime *rt);
  1.1915 +
  1.1916 +extern void
  1.1917 +SweepScriptData(JSRuntime *rt);
  1.1918 +
  1.1919 +extern void
  1.1920 +FreeScriptData(JSRuntime *rt);
  1.1921 +
  1.1922 +struct ScriptAndCounts
  1.1923 +{
  1.1924 +    /* This structure is stored and marked from the JSRuntime. */
  1.1925 +    JSScript *script;
  1.1926 +    ScriptCounts scriptCounts;
  1.1927 +
  1.1928 +    PCCounts &getPCCounts(jsbytecode *pc) const {
  1.1929 +        return scriptCounts.pcCountsVector[script->pcToOffset(pc)];
  1.1930 +    }
  1.1931 +
  1.1932 +    jit::IonScriptCounts *getIonCounts() const {
  1.1933 +        return scriptCounts.ionCounts;
  1.1934 +    }
  1.1935 +};
  1.1936 +
  1.1937 +struct GSNCache;
  1.1938 +
  1.1939 +jssrcnote *
  1.1940 +GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc);
  1.1941 +
  1.1942 +} /* namespace js */
  1.1943 +
  1.1944 +extern jssrcnote *
  1.1945 +js_GetSrcNote(JSContext *cx, JSScript *script, jsbytecode *pc);
  1.1946 +
  1.1947 +extern jsbytecode *
  1.1948 +js_LineNumberToPC(JSScript *script, unsigned lineno);
  1.1949 +
  1.1950 +extern JS_FRIEND_API(unsigned)
  1.1951 +js_GetScriptLineExtent(JSScript *script);
  1.1952 +
  1.1953 +namespace js {
  1.1954 +
  1.1955 +extern unsigned
  1.1956 +PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp = nullptr);
  1.1957 +
  1.1958 +extern unsigned
  1.1959 +PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc,
  1.1960 +               unsigned *columnp = nullptr);
  1.1961 +
  1.1962 +/*
  1.1963 + * This function returns the file and line number of the script currently
  1.1964 + * executing on cx. If there is no current script executing on cx (e.g., a
  1.1965 + * native called directly through JSAPI (e.g., by setTimeout)), nullptr and 0
  1.1966 + * are returned as the file and line. Additionally, this function avoids the
  1.1967 + * full linear scan to compute line number when the caller guarantees that the
  1.1968 + * script compilation occurs at a JSOP_EVAL/JSOP_SPREADEVAL.
  1.1969 + */
  1.1970 +
  1.1971 +enum LineOption {
  1.1972 +    CALLED_FROM_JSOP_EVAL,
  1.1973 +    NOT_CALLED_FROM_JSOP_EVAL
  1.1974 +};
  1.1975 +
  1.1976 +extern void
  1.1977 +DescribeScriptedCallerForCompilation(JSContext *cx, MutableHandleScript maybeScript,
  1.1978 +                                     const char **file, unsigned *linenop,
  1.1979 +                                     uint32_t *pcOffset, JSPrincipals **origin,
  1.1980 +                                     LineOption opt = NOT_CALLED_FROM_JSOP_EVAL);
  1.1981 +
  1.1982 +bool
  1.1983 +CloneFunctionScript(JSContext *cx, HandleFunction original, HandleFunction clone,
  1.1984 +                    NewObjectKind newKind = GenericObject);
  1.1985 +
  1.1986 +/*
  1.1987 + * JSAPI clients are allowed to leave CompileOptions.originPrincipals nullptr in
  1.1988 + * which case the JS engine sets options.originPrincipals = origin.principals.
  1.1989 + * This normalization step must occur before the originPrincipals get stored in
  1.1990 + * the JSScript/ScriptSource.
  1.1991 + */
  1.1992 +
  1.1993 +static inline JSPrincipals *
  1.1994 +NormalizeOriginPrincipals(JSPrincipals *principals, JSPrincipals *originPrincipals)
  1.1995 +{
  1.1996 +    return originPrincipals ? originPrincipals : principals;
  1.1997 +}
  1.1998 +
  1.1999 +} /* namespace js */
  1.2000 +
  1.2001 +#endif /* jsscript_h */

mercurial