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 */