js/src/jit/IonCode.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/IonCode.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,789 @@
     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 +#ifndef jit_IonCode_h
    1.11 +#define jit_IonCode_h
    1.12 +
    1.13 +#include "mozilla/Atomics.h"
    1.14 +#include "mozilla/MemoryReporting.h"
    1.15 +#include "mozilla/PodOperations.h"
    1.16 +
    1.17 +#include "jsinfer.h"
    1.18 +#include "jstypes.h"
    1.19 +
    1.20 +#include "assembler/jit/ExecutableAllocator.h"
    1.21 +#include "gc/Heap.h"
    1.22 +#include "jit/IonOptimizationLevels.h"
    1.23 +#include "jit/IonTypes.h"
    1.24 +
    1.25 +namespace JSC {
    1.26 +    class ExecutablePool;
    1.27 +}
    1.28 +
    1.29 +namespace js {
    1.30 +
    1.31 +class AsmJSModule;
    1.32 +
    1.33 +namespace jit {
    1.34 +
    1.35 +class MacroAssembler;
    1.36 +class CodeOffsetLabel;
    1.37 +class PatchableBackedge;
    1.38 +
    1.39 +class JitCode : public gc::BarrieredCell<JitCode>
    1.40 +{
    1.41 +  protected:
    1.42 +    uint8_t *code_;
    1.43 +    JSC::ExecutablePool *pool_;
    1.44 +    uint32_t bufferSize_;             // Total buffer size. Does not include headerSize_.
    1.45 +    uint32_t insnSize_;               // Instruction stream size.
    1.46 +    uint32_t dataSize_;               // Size of the read-only data area.
    1.47 +    uint32_t jumpRelocTableBytes_;    // Size of the jump relocation table.
    1.48 +    uint32_t dataRelocTableBytes_;    // Size of the data relocation table.
    1.49 +    uint32_t preBarrierTableBytes_;   // Size of the prebarrier table.
    1.50 +    uint8_t headerSize_ : 5;          // Number of bytes allocated before codeStart.
    1.51 +    uint8_t kind_ : 3;                // JSC::CodeKind, for the memory reporters.
    1.52 +    bool invalidated_ : 1;            // Whether the code object has been invalidated.
    1.53 +                                      // This is necessary to prevent GC tracing.
    1.54 +
    1.55 +#if JS_BITS_PER_WORD == 32
    1.56 +    // Ensure JitCode is gc::Cell aligned.
    1.57 +    uint32_t padding_;
    1.58 +#endif
    1.59 +
    1.60 +    JitCode()
    1.61 +      : code_(nullptr),
    1.62 +        pool_(nullptr)
    1.63 +    { }
    1.64 +    JitCode(uint8_t *code, uint32_t bufferSize, uint32_t headerSize, JSC::ExecutablePool *pool,
    1.65 +            JSC::CodeKind kind)
    1.66 +      : code_(code),
    1.67 +        pool_(pool),
    1.68 +        bufferSize_(bufferSize),
    1.69 +        insnSize_(0),
    1.70 +        dataSize_(0),
    1.71 +        jumpRelocTableBytes_(0),
    1.72 +        dataRelocTableBytes_(0),
    1.73 +        preBarrierTableBytes_(0),
    1.74 +        headerSize_(headerSize),
    1.75 +        kind_(kind),
    1.76 +        invalidated_(false)
    1.77 +    {
    1.78 +        MOZ_ASSERT(JSC::CodeKind(kind_) == kind);
    1.79 +        MOZ_ASSERT(headerSize_ == headerSize);
    1.80 +    }
    1.81 +
    1.82 +    uint32_t dataOffset() const {
    1.83 +        return insnSize_;
    1.84 +    }
    1.85 +    uint32_t jumpRelocTableOffset() const {
    1.86 +        return dataOffset() + dataSize_;
    1.87 +    }
    1.88 +    uint32_t dataRelocTableOffset() const {
    1.89 +        return jumpRelocTableOffset() + jumpRelocTableBytes_;
    1.90 +    }
    1.91 +    uint32_t preBarrierTableOffset() const {
    1.92 +        return dataRelocTableOffset() + dataRelocTableBytes_;
    1.93 +    }
    1.94 +
    1.95 +  public:
    1.96 +    uint8_t *raw() const {
    1.97 +        return code_;
    1.98 +    }
    1.99 +    size_t instructionsSize() const {
   1.100 +        return insnSize_;
   1.101 +    }
   1.102 +    void trace(JSTracer *trc);
   1.103 +    void finalize(FreeOp *fop);
   1.104 +    void setInvalidated() {
   1.105 +        invalidated_ = true;
   1.106 +    }
   1.107 +
   1.108 +    void togglePreBarriers(bool enabled);
   1.109 +
   1.110 +    // If this JitCode object has been, effectively, corrupted due to
   1.111 +    // invalidation patching, then we have to remember this so we don't try and
   1.112 +    // trace relocation entries that may now be corrupt.
   1.113 +    bool invalidated() const {
   1.114 +        return !!invalidated_;
   1.115 +    }
   1.116 +
   1.117 +    template <typename T> T as() const {
   1.118 +        return JS_DATA_TO_FUNC_PTR(T, raw());
   1.119 +    }
   1.120 +
   1.121 +    void copyFrom(MacroAssembler &masm);
   1.122 +
   1.123 +    static JitCode *FromExecutable(uint8_t *buffer) {
   1.124 +        JitCode *code = *(JitCode **)(buffer - sizeof(JitCode *));
   1.125 +        JS_ASSERT(code->raw() == buffer);
   1.126 +        return code;
   1.127 +    }
   1.128 +
   1.129 +    static size_t offsetOfCode() {
   1.130 +        return offsetof(JitCode, code_);
   1.131 +    }
   1.132 +
   1.133 +    uint8_t *jumpRelocTable() {
   1.134 +        return code_ + jumpRelocTableOffset();
   1.135 +    }
   1.136 +
   1.137 +    // Allocates a new JitCode object which will be managed by the GC. If no
   1.138 +    // object can be allocated, nullptr is returned. On failure, |pool| is
   1.139 +    // automatically released, so the code may be freed.
   1.140 +    template <AllowGC allowGC>
   1.141 +    static JitCode *New(JSContext *cx, uint8_t *code, uint32_t bufferSize, uint32_t headerSize,
   1.142 +                        JSC::ExecutablePool *pool, JSC::CodeKind kind);
   1.143 +
   1.144 +  public:
   1.145 +    static inline ThingRootKind rootKind() { return THING_ROOT_JIT_CODE; }
   1.146 +};
   1.147 +
   1.148 +class SnapshotWriter;
   1.149 +class RecoverWriter;
   1.150 +class SafepointWriter;
   1.151 +class SafepointIndex;
   1.152 +class OsiIndex;
   1.153 +class IonCache;
   1.154 +struct PatchableBackedgeInfo;
   1.155 +struct CacheLocation;
   1.156 +
   1.157 +// Describes a single AsmJSModule which jumps (via an FFI exit with the given
   1.158 +// index) directly into an IonScript.
   1.159 +struct DependentAsmJSModuleExit
   1.160 +{
   1.161 +    const AsmJSModule *module;
   1.162 +    size_t exitIndex;
   1.163 +
   1.164 +    DependentAsmJSModuleExit(const AsmJSModule *module, size_t exitIndex)
   1.165 +      : module(module),
   1.166 +        exitIndex(exitIndex)
   1.167 +    { }
   1.168 +};
   1.169 +
   1.170 +// An IonScript attaches Ion-generated information to a JSScript.
   1.171 +struct IonScript
   1.172 +{
   1.173 +  private:
   1.174 +    // Code pointer containing the actual method.
   1.175 +    EncapsulatedPtr<JitCode> method_;
   1.176 +
   1.177 +    // Deoptimization table used by this method.
   1.178 +    EncapsulatedPtr<JitCode> deoptTable_;
   1.179 +
   1.180 +    // Entrypoint for OSR, or nullptr.
   1.181 +    jsbytecode *osrPc_;
   1.182 +
   1.183 +    // Offset to OSR entrypoint from method_->raw(), or 0.
   1.184 +    uint32_t osrEntryOffset_;
   1.185 +
   1.186 +    // Offset to entrypoint skipping type arg check from method_->raw().
   1.187 +    uint32_t skipArgCheckEntryOffset_;
   1.188 +
   1.189 +    // Offset of the invalidation epilogue (which pushes this IonScript
   1.190 +    // and calls the invalidation thunk).
   1.191 +    uint32_t invalidateEpilogueOffset_;
   1.192 +
   1.193 +    // The offset immediately after the IonScript immediate.
   1.194 +    // NOTE: technically a constant delta from
   1.195 +    // |invalidateEpilogueOffset_|, so we could hard-code this
   1.196 +    // per-platform if we want.
   1.197 +    uint32_t invalidateEpilogueDataOffset_;
   1.198 +
   1.199 +    // Number of times this script bailed out without invalidation.
   1.200 +    uint32_t numBailouts_;
   1.201 +
   1.202 +    // Flag set when it is likely that one of our (transitive) call
   1.203 +    // targets is not compiled.  Used in ForkJoin.cpp to decide when
   1.204 +    // we should add call targets to the worklist.
   1.205 +    mozilla::Atomic<bool, mozilla::Relaxed> hasUncompiledCallTarget_;
   1.206 +
   1.207 +    // Flag set when this script is used as an entry script to parallel
   1.208 +    // execution. If this is true, then the parent JSScript must be in its
   1.209 +    // JitCompartment's parallel entry script set.
   1.210 +    bool isParallelEntryScript_;
   1.211 +
   1.212 +    // Flag set if IonScript was compiled with SPS profiling enabled.
   1.213 +    bool hasSPSInstrumentation_;
   1.214 +
   1.215 +    // Flag for if this script is getting recompiled.
   1.216 +    uint32_t recompiling_;
   1.217 +
   1.218 +    // Any kind of data needed by the runtime, these can be either cache
   1.219 +    // information or profiling info.
   1.220 +    uint32_t runtimeData_;
   1.221 +    uint32_t runtimeSize_;
   1.222 +
   1.223 +    // State for polymorphic caches in the compiled code. All caches are stored
   1.224 +    // in the runtimeData buffer and indexed by the cacheIndex which give a
   1.225 +    // relative offset in the runtimeData array.
   1.226 +    uint32_t cacheIndex_;
   1.227 +    uint32_t cacheEntries_;
   1.228 +
   1.229 +    // Map code displacement to safepoint / OSI-patch-delta.
   1.230 +    uint32_t safepointIndexOffset_;
   1.231 +    uint32_t safepointIndexEntries_;
   1.232 +
   1.233 +    // Offset to and length of the safepoint table in bytes.
   1.234 +    uint32_t safepointsStart_;
   1.235 +    uint32_t safepointsSize_;
   1.236 +
   1.237 +    // Number of bytes this function reserves on the stack.
   1.238 +    uint32_t frameSlots_;
   1.239 +
   1.240 +    // Frame size is the value that can be added to the StackPointer along
   1.241 +    // with the frame prefix to get a valid IonJSFrameLayout.
   1.242 +    uint32_t frameSize_;
   1.243 +
   1.244 +    // Table mapping bailout IDs to snapshot offsets.
   1.245 +    uint32_t bailoutTable_;
   1.246 +    uint32_t bailoutEntries_;
   1.247 +
   1.248 +    // Map OSI-point displacement to snapshot.
   1.249 +    uint32_t osiIndexOffset_;
   1.250 +    uint32_t osiIndexEntries_;
   1.251 +
   1.252 +    // Offset from the start of the code buffer to its snapshot buffer.
   1.253 +    uint32_t snapshots_;
   1.254 +    uint32_t snapshotsListSize_;
   1.255 +    uint32_t snapshotsRVATableSize_;
   1.256 +
   1.257 +    // List of instructions needed to recover stack frames.
   1.258 +    uint32_t recovers_;
   1.259 +    uint32_t recoversSize_;
   1.260 +
   1.261 +    // Constant table for constants stored in snapshots.
   1.262 +    uint32_t constantTable_;
   1.263 +    uint32_t constantEntries_;
   1.264 +
   1.265 +    // List of scripts that we call.
   1.266 +    //
   1.267 +    // Currently this is only non-nullptr for parallel IonScripts.
   1.268 +    uint32_t callTargetList_;
   1.269 +    uint32_t callTargetEntries_;
   1.270 +
   1.271 +    // List of patchable backedges which are threaded into the runtime's list.
   1.272 +    uint32_t backedgeList_;
   1.273 +    uint32_t backedgeEntries_;
   1.274 +
   1.275 +    // Number of references from invalidation records.
   1.276 +    uint32_t refcount_;
   1.277 +
   1.278 +    // If this is a parallel script, the number of major GC collections it has
   1.279 +    // been idle, otherwise 0.
   1.280 +    //
   1.281 +    // JSScripts with parallel IonScripts are preserved across GC if the
   1.282 +    // parallel age is < MAX_PARALLEL_AGE.
   1.283 +    uint32_t parallelAge_;
   1.284 +
   1.285 +    // Identifier of the compilation which produced this code.
   1.286 +    types::RecompileInfo recompileInfo_;
   1.287 +
   1.288 +    // The optimization level this script was compiled in.
   1.289 +    OptimizationLevel optimizationLevel_;
   1.290 +
   1.291 +    // Number of times we tried to enter this script via OSR but failed due to
   1.292 +    // a LOOPENTRY pc other than osrPc_.
   1.293 +    uint32_t osrPcMismatchCounter_;
   1.294 +
   1.295 +    // If non-null, the list of AsmJSModules
   1.296 +    // that contain an optimized call directly into this IonScript.
   1.297 +    Vector<DependentAsmJSModuleExit> *dependentAsmJSModules;
   1.298 +
   1.299 +  private:
   1.300 +    inline uint8_t *bottomBuffer() {
   1.301 +        return reinterpret_cast<uint8_t *>(this);
   1.302 +    }
   1.303 +    inline const uint8_t *bottomBuffer() const {
   1.304 +        return reinterpret_cast<const uint8_t *>(this);
   1.305 +    }
   1.306 +
   1.307 +  public:
   1.308 +    SnapshotOffset *bailoutTable() {
   1.309 +        return (SnapshotOffset *) &bottomBuffer()[bailoutTable_];
   1.310 +    }
   1.311 +    EncapsulatedValue *constants() {
   1.312 +        return (EncapsulatedValue *) &bottomBuffer()[constantTable_];
   1.313 +    }
   1.314 +    const SafepointIndex *safepointIndices() const {
   1.315 +        return const_cast<IonScript *>(this)->safepointIndices();
   1.316 +    }
   1.317 +    SafepointIndex *safepointIndices() {
   1.318 +        return (SafepointIndex *) &bottomBuffer()[safepointIndexOffset_];
   1.319 +    }
   1.320 +    const OsiIndex *osiIndices() const {
   1.321 +        return const_cast<IonScript *>(this)->osiIndices();
   1.322 +    }
   1.323 +    OsiIndex *osiIndices() {
   1.324 +        return (OsiIndex *) &bottomBuffer()[osiIndexOffset_];
   1.325 +    }
   1.326 +    uint32_t *cacheIndex() {
   1.327 +        return (uint32_t *) &bottomBuffer()[cacheIndex_];
   1.328 +    }
   1.329 +    uint8_t *runtimeData() {
   1.330 +        return  &bottomBuffer()[runtimeData_];
   1.331 +    }
   1.332 +    JSScript **callTargetList() {
   1.333 +        return (JSScript **) &bottomBuffer()[callTargetList_];
   1.334 +    }
   1.335 +    PatchableBackedge *backedgeList() {
   1.336 +        return (PatchableBackedge *) &bottomBuffer()[backedgeList_];
   1.337 +    }
   1.338 +    bool addDependentAsmJSModule(JSContext *cx, DependentAsmJSModuleExit exit);
   1.339 +    void removeDependentAsmJSModule(DependentAsmJSModuleExit exit) {
   1.340 +        if (!dependentAsmJSModules)
   1.341 +            return;
   1.342 +        for (size_t i = 0; i < dependentAsmJSModules->length(); i++) {
   1.343 +            if (dependentAsmJSModules->begin()[i].module == exit.module &&
   1.344 +                dependentAsmJSModules->begin()[i].exitIndex == exit.exitIndex)
   1.345 +            {
   1.346 +                dependentAsmJSModules->erase(dependentAsmJSModules->begin() + i);
   1.347 +                break;
   1.348 +            }
   1.349 +        }
   1.350 +    }
   1.351 +
   1.352 +  private:
   1.353 +    void trace(JSTracer *trc);
   1.354 +
   1.355 +  public:
   1.356 +    // Do not call directly, use IonScript::New. This is public for cx->new_.
   1.357 +    IonScript();
   1.358 +
   1.359 +    static IonScript *New(JSContext *cx, types::RecompileInfo recompileInfo,
   1.360 +                          uint32_t frameLocals, uint32_t frameSize,
   1.361 +                          size_t snapshotsListSize, size_t snapshotsRVATableSize,
   1.362 +                          size_t recoversSize, size_t bailoutEntries,
   1.363 +                          size_t constants, size_t safepointIndexEntries,
   1.364 +                          size_t osiIndexEntries, size_t cacheEntries,
   1.365 +                          size_t runtimeSize, size_t safepointsSize,
   1.366 +                          size_t callTargetEntries, size_t backedgeEntries,
   1.367 +                          OptimizationLevel optimizationLevel);
   1.368 +    static void Trace(JSTracer *trc, IonScript *script);
   1.369 +    static void Destroy(FreeOp *fop, IonScript *script);
   1.370 +
   1.371 +    static inline size_t offsetOfMethod() {
   1.372 +        return offsetof(IonScript, method_);
   1.373 +    }
   1.374 +    static inline size_t offsetOfOsrEntryOffset() {
   1.375 +        return offsetof(IonScript, osrEntryOffset_);
   1.376 +    }
   1.377 +    static inline size_t offsetOfSkipArgCheckEntryOffset() {
   1.378 +        return offsetof(IonScript, skipArgCheckEntryOffset_);
   1.379 +    }
   1.380 +    static inline size_t offsetOfRefcount() {
   1.381 +        return offsetof(IonScript, refcount_);
   1.382 +    }
   1.383 +    static inline size_t offsetOfRecompiling() {
   1.384 +        return offsetof(IonScript, recompiling_);
   1.385 +    }
   1.386 +
   1.387 +  public:
   1.388 +    JitCode *method() const {
   1.389 +        return method_;
   1.390 +    }
   1.391 +    void setMethod(JitCode *code) {
   1.392 +        JS_ASSERT(!invalidated());
   1.393 +        method_ = code;
   1.394 +    }
   1.395 +    void setDeoptTable(JitCode *code) {
   1.396 +        deoptTable_ = code;
   1.397 +    }
   1.398 +    void setOsrPc(jsbytecode *osrPc) {
   1.399 +        osrPc_ = osrPc;
   1.400 +    }
   1.401 +    jsbytecode *osrPc() const {
   1.402 +        return osrPc_;
   1.403 +    }
   1.404 +    void setOsrEntryOffset(uint32_t offset) {
   1.405 +        JS_ASSERT(!osrEntryOffset_);
   1.406 +        osrEntryOffset_ = offset;
   1.407 +    }
   1.408 +    uint32_t osrEntryOffset() const {
   1.409 +        return osrEntryOffset_;
   1.410 +    }
   1.411 +    void setSkipArgCheckEntryOffset(uint32_t offset) {
   1.412 +        JS_ASSERT(!skipArgCheckEntryOffset_);
   1.413 +        skipArgCheckEntryOffset_ = offset;
   1.414 +    }
   1.415 +    uint32_t getSkipArgCheckEntryOffset() const {
   1.416 +        return skipArgCheckEntryOffset_;
   1.417 +    }
   1.418 +    bool containsCodeAddress(uint8_t *addr) const {
   1.419 +        return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize();
   1.420 +    }
   1.421 +    bool containsReturnAddress(uint8_t *addr) const {
   1.422 +        // This accounts for an off by one error caused by the return address of a
   1.423 +        // bailout sitting outside the range of the containing function.
   1.424 +        return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize();
   1.425 +    }
   1.426 +    void setInvalidationEpilogueOffset(uint32_t offset) {
   1.427 +        JS_ASSERT(!invalidateEpilogueOffset_);
   1.428 +        invalidateEpilogueOffset_ = offset;
   1.429 +    }
   1.430 +    uint32_t invalidateEpilogueOffset() const {
   1.431 +        JS_ASSERT(invalidateEpilogueOffset_);
   1.432 +        return invalidateEpilogueOffset_;
   1.433 +    }
   1.434 +    void setInvalidationEpilogueDataOffset(uint32_t offset) {
   1.435 +        JS_ASSERT(!invalidateEpilogueDataOffset_);
   1.436 +        invalidateEpilogueDataOffset_ = offset;
   1.437 +    }
   1.438 +    uint32_t invalidateEpilogueDataOffset() const {
   1.439 +        JS_ASSERT(invalidateEpilogueDataOffset_);
   1.440 +        return invalidateEpilogueDataOffset_;
   1.441 +    }
   1.442 +    void incNumBailouts() {
   1.443 +        numBailouts_++;
   1.444 +    }
   1.445 +    uint32_t numBailouts() const {
   1.446 +        return numBailouts_;
   1.447 +    }
   1.448 +    bool bailoutExpected() const {
   1.449 +        return numBailouts_ > 0;
   1.450 +    }
   1.451 +    void setHasUncompiledCallTarget() {
   1.452 +        hasUncompiledCallTarget_ = true;
   1.453 +    }
   1.454 +    void clearHasUncompiledCallTarget() {
   1.455 +        hasUncompiledCallTarget_ = false;
   1.456 +    }
   1.457 +    bool hasUncompiledCallTarget() const {
   1.458 +        return hasUncompiledCallTarget_;
   1.459 +    }
   1.460 +    void setIsParallelEntryScript() {
   1.461 +        isParallelEntryScript_ = true;
   1.462 +    }
   1.463 +    bool isParallelEntryScript() const {
   1.464 +        return isParallelEntryScript_;
   1.465 +    }
   1.466 +    void setHasSPSInstrumentation() {
   1.467 +        hasSPSInstrumentation_ = true;
   1.468 +    }
   1.469 +    void clearHasSPSInstrumentation() {
   1.470 +        hasSPSInstrumentation_ = false;
   1.471 +    }
   1.472 +    bool hasSPSInstrumentation() const {
   1.473 +        return hasSPSInstrumentation_;
   1.474 +    }
   1.475 +    const uint8_t *snapshots() const {
   1.476 +        return reinterpret_cast<const uint8_t *>(this) + snapshots_;
   1.477 +    }
   1.478 +    size_t snapshotsListSize() const {
   1.479 +        return snapshotsListSize_;
   1.480 +    }
   1.481 +    size_t snapshotsRVATableSize() const {
   1.482 +        return snapshotsRVATableSize_;
   1.483 +    }
   1.484 +    const uint8_t *recovers() const {
   1.485 +        return reinterpret_cast<const uint8_t *>(this) + recovers_;
   1.486 +    }
   1.487 +    size_t recoversSize() const {
   1.488 +        return recoversSize_;
   1.489 +    }
   1.490 +    const uint8_t *safepoints() const {
   1.491 +        return reinterpret_cast<const uint8_t *>(this) + safepointsStart_;
   1.492 +    }
   1.493 +    size_t safepointsSize() const {
   1.494 +        return safepointsSize_;
   1.495 +    }
   1.496 +    size_t callTargetEntries() const {
   1.497 +        return callTargetEntries_;
   1.498 +    }
   1.499 +    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1.500 +        return mallocSizeOf(this);
   1.501 +    }
   1.502 +    EncapsulatedValue &getConstant(size_t index) {
   1.503 +        JS_ASSERT(index < numConstants());
   1.504 +        return constants()[index];
   1.505 +    }
   1.506 +    size_t numConstants() const {
   1.507 +        return constantEntries_;
   1.508 +    }
   1.509 +    uint32_t frameSlots() const {
   1.510 +        return frameSlots_;
   1.511 +    }
   1.512 +    uint32_t frameSize() const {
   1.513 +        return frameSize_;
   1.514 +    }
   1.515 +    SnapshotOffset bailoutToSnapshot(uint32_t bailoutId) {
   1.516 +        JS_ASSERT(bailoutId < bailoutEntries_);
   1.517 +        return bailoutTable()[bailoutId];
   1.518 +    }
   1.519 +    const SafepointIndex *getSafepointIndex(uint32_t disp) const;
   1.520 +    const SafepointIndex *getSafepointIndex(uint8_t *retAddr) const {
   1.521 +        JS_ASSERT(containsCodeAddress(retAddr));
   1.522 +        return getSafepointIndex(retAddr - method()->raw());
   1.523 +    }
   1.524 +    const OsiIndex *getOsiIndex(uint32_t disp) const;
   1.525 +    const OsiIndex *getOsiIndex(uint8_t *retAddr) const;
   1.526 +    inline IonCache &getCacheFromIndex(uint32_t index) {
   1.527 +        JS_ASSERT(index < cacheEntries_);
   1.528 +        uint32_t offset = cacheIndex()[index];
   1.529 +        return getCache(offset);
   1.530 +    }
   1.531 +    inline IonCache &getCache(uint32_t offset) {
   1.532 +        JS_ASSERT(offset < runtimeSize_);
   1.533 +        return *(IonCache *) &runtimeData()[offset];
   1.534 +    }
   1.535 +    size_t numCaches() const {
   1.536 +        return cacheEntries_;
   1.537 +    }
   1.538 +    size_t runtimeSize() const {
   1.539 +        return runtimeSize_;
   1.540 +    }
   1.541 +    CacheLocation *getCacheLocs(uint32_t locIndex) {
   1.542 +        JS_ASSERT(locIndex < runtimeSize_);
   1.543 +        return (CacheLocation *) &runtimeData()[locIndex];
   1.544 +    }
   1.545 +    void toggleBarriers(bool enabled);
   1.546 +    void purgeCaches();
   1.547 +    void destroyCaches();
   1.548 +    void unlinkFromRuntime(FreeOp *fop);
   1.549 +    void copySnapshots(const SnapshotWriter *writer);
   1.550 +    void copyRecovers(const RecoverWriter *writer);
   1.551 +    void copyBailoutTable(const SnapshotOffset *table);
   1.552 +    void copyConstants(const Value *vp);
   1.553 +    void copySafepointIndices(const SafepointIndex *firstSafepointIndex, MacroAssembler &masm);
   1.554 +    void copyOsiIndices(const OsiIndex *firstOsiIndex, MacroAssembler &masm);
   1.555 +    void copyRuntimeData(const uint8_t *data);
   1.556 +    void copyCacheEntries(const uint32_t *caches, MacroAssembler &masm);
   1.557 +    void copySafepoints(const SafepointWriter *writer);
   1.558 +    void copyCallTargetEntries(JSScript **callTargets);
   1.559 +    void copyPatchableBackedges(JSContext *cx, JitCode *code,
   1.560 +                                PatchableBackedgeInfo *backedges);
   1.561 +
   1.562 +    bool invalidated() const {
   1.563 +        return refcount_ != 0;
   1.564 +    }
   1.565 +    size_t refcount() const {
   1.566 +        return refcount_;
   1.567 +    }
   1.568 +    void incref() {
   1.569 +        refcount_++;
   1.570 +    }
   1.571 +    void decref(FreeOp *fop) {
   1.572 +        JS_ASSERT(refcount_);
   1.573 +        refcount_--;
   1.574 +        if (!refcount_)
   1.575 +            Destroy(fop, this);
   1.576 +    }
   1.577 +    const types::RecompileInfo& recompileInfo() const {
   1.578 +        return recompileInfo_;
   1.579 +    }
   1.580 +    types::RecompileInfo& recompileInfoRef() {
   1.581 +        return recompileInfo_;
   1.582 +    }
   1.583 +    OptimizationLevel optimizationLevel() const {
   1.584 +        return optimizationLevel_;
   1.585 +    }
   1.586 +    uint32_t incrOsrPcMismatchCounter() {
   1.587 +        return ++osrPcMismatchCounter_;
   1.588 +    }
   1.589 +    void resetOsrPcMismatchCounter() {
   1.590 +        osrPcMismatchCounter_ = 0;
   1.591 +    }
   1.592 +
   1.593 +    void setRecompiling() {
   1.594 +        recompiling_ = true;
   1.595 +    }
   1.596 +
   1.597 +    bool isRecompiling() const {
   1.598 +        return recompiling_;
   1.599 +    }
   1.600 +
   1.601 +    void clearRecompiling() {
   1.602 +        recompiling_ = false;
   1.603 +    }
   1.604 +
   1.605 +    static const uint32_t MAX_PARALLEL_AGE = 5;
   1.606 +
   1.607 +    void resetParallelAge() {
   1.608 +        MOZ_ASSERT(isParallelEntryScript());
   1.609 +        parallelAge_ = 0;
   1.610 +    }
   1.611 +    uint32_t parallelAge() const {
   1.612 +        return parallelAge_;
   1.613 +    }
   1.614 +    uint32_t increaseParallelAge() {
   1.615 +        MOZ_ASSERT(isParallelEntryScript());
   1.616 +        return ++parallelAge_;
   1.617 +    }
   1.618 +
   1.619 +    static void writeBarrierPre(Zone *zone, IonScript *ionScript);
   1.620 +};
   1.621 +
   1.622 +// Execution information for a basic block which may persist after the
   1.623 +// accompanying IonScript is destroyed, for use during profiling.
   1.624 +struct IonBlockCounts
   1.625 +{
   1.626 +  private:
   1.627 +    uint32_t id_;
   1.628 +
   1.629 +    // Approximate bytecode in the outer (not inlined) script this block
   1.630 +    // was generated from.
   1.631 +    uint32_t offset_;
   1.632 +
   1.633 +    // ids for successors of this block.
   1.634 +    uint32_t numSuccessors_;
   1.635 +    uint32_t *successors_;
   1.636 +
   1.637 +    // Hit count for this block.
   1.638 +    uint64_t hitCount_;
   1.639 +
   1.640 +    // Text information about the code generated for this block.
   1.641 +    char *code_;
   1.642 +
   1.643 +  public:
   1.644 +
   1.645 +    bool init(uint32_t id, uint32_t offset, uint32_t numSuccessors) {
   1.646 +        id_ = id;
   1.647 +        offset_ = offset;
   1.648 +        numSuccessors_ = numSuccessors;
   1.649 +        if (numSuccessors) {
   1.650 +            successors_ = js_pod_calloc<uint32_t>(numSuccessors);
   1.651 +            if (!successors_)
   1.652 +                return false;
   1.653 +        }
   1.654 +        return true;
   1.655 +    }
   1.656 +
   1.657 +    void destroy() {
   1.658 +        js_free(successors_);
   1.659 +        js_free(code_);
   1.660 +    }
   1.661 +
   1.662 +    uint32_t id() const {
   1.663 +        return id_;
   1.664 +    }
   1.665 +
   1.666 +    uint32_t offset() const {
   1.667 +        return offset_;
   1.668 +    }
   1.669 +
   1.670 +    size_t numSuccessors() const {
   1.671 +        return numSuccessors_;
   1.672 +    }
   1.673 +
   1.674 +    void setSuccessor(size_t i, uint32_t id) {
   1.675 +        JS_ASSERT(i < numSuccessors_);
   1.676 +        successors_[i] = id;
   1.677 +    }
   1.678 +
   1.679 +    uint32_t successor(size_t i) const {
   1.680 +        JS_ASSERT(i < numSuccessors_);
   1.681 +        return successors_[i];
   1.682 +    }
   1.683 +
   1.684 +    uint64_t *addressOfHitCount() {
   1.685 +        return &hitCount_;
   1.686 +    }
   1.687 +
   1.688 +    uint64_t hitCount() const {
   1.689 +        return hitCount_;
   1.690 +    }
   1.691 +
   1.692 +    void setCode(const char *code) {
   1.693 +        char *ncode = (char *) js_malloc(strlen(code) + 1);
   1.694 +        if (ncode) {
   1.695 +            strcpy(ncode, code);
   1.696 +            code_ = ncode;
   1.697 +        }
   1.698 +    }
   1.699 +
   1.700 +    const char *code() const {
   1.701 +        return code_;
   1.702 +    }
   1.703 +};
   1.704 +
   1.705 +// Execution information for a compiled script which may persist after the
   1.706 +// IonScript is destroyed, for use during profiling.
   1.707 +struct IonScriptCounts
   1.708 +{
   1.709 +  private:
   1.710 +    // Any previous invalidated compilation(s) for the script.
   1.711 +    IonScriptCounts *previous_;
   1.712 +
   1.713 +    // Information about basic blocks in this script.
   1.714 +    size_t numBlocks_;
   1.715 +    IonBlockCounts *blocks_;
   1.716 +
   1.717 +  public:
   1.718 +
   1.719 +    IonScriptCounts() {
   1.720 +        mozilla::PodZero(this);
   1.721 +    }
   1.722 +
   1.723 +    ~IonScriptCounts() {
   1.724 +        for (size_t i = 0; i < numBlocks_; i++)
   1.725 +            blocks_[i].destroy();
   1.726 +        js_free(blocks_);
   1.727 +        js_delete(previous_);
   1.728 +    }
   1.729 +
   1.730 +    bool init(size_t numBlocks) {
   1.731 +        numBlocks_ = numBlocks;
   1.732 +        blocks_ = js_pod_calloc<IonBlockCounts>(numBlocks);
   1.733 +        return blocks_ != nullptr;
   1.734 +    }
   1.735 +
   1.736 +    size_t numBlocks() const {
   1.737 +        return numBlocks_;
   1.738 +    }
   1.739 +
   1.740 +    IonBlockCounts &block(size_t i) {
   1.741 +        JS_ASSERT(i < numBlocks_);
   1.742 +        return blocks_[i];
   1.743 +    }
   1.744 +
   1.745 +    void setPrevious(IonScriptCounts *previous) {
   1.746 +        previous_ = previous;
   1.747 +    }
   1.748 +
   1.749 +    IonScriptCounts *previous() const {
   1.750 +        return previous_;
   1.751 +    }
   1.752 +};
   1.753 +
   1.754 +struct VMFunction;
   1.755 +
   1.756 +class JitCompartment;
   1.757 +class JitRuntime;
   1.758 +
   1.759 +struct AutoFlushICache
   1.760 +{
   1.761 +  private:
   1.762 +    uintptr_t start_;
   1.763 +    uintptr_t stop_;
   1.764 +    const char *name_;
   1.765 +    bool inhibit_;
   1.766 +    AutoFlushICache *prev_;
   1.767 +
   1.768 +  public:
   1.769 +    static void setRange(uintptr_t p, size_t len);
   1.770 +    static void flush(uintptr_t p, size_t len);
   1.771 +    static void setInhibit();
   1.772 +    ~AutoFlushICache();
   1.773 +    AutoFlushICache(const char *nonce, bool inhibit=false);
   1.774 +};
   1.775 +
   1.776 +} // namespace jit
   1.777 +
   1.778 +namespace gc {
   1.779 +
   1.780 +inline bool
   1.781 +IsMarked(const jit::VMFunction *)
   1.782 +{
   1.783 +    // VMFunction are only static objects which are used by WeakMaps as keys.
   1.784 +    // It is considered as a root object which is always marked.
   1.785 +    return true;
   1.786 +}
   1.787 +
   1.788 +} // namespace gc
   1.789 +
   1.790 +} // namespace js
   1.791 +
   1.792 +#endif /* jit_IonCode_h */

mercurial