mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-09-29 12:54:46 +00:00
807 lines
24 KiB
C++
807 lines
24 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef jit_IonCode_h
|
|
#define jit_IonCode_h
|
|
|
|
#include "mozilla/Atomics.h"
|
|
#include "mozilla/MemoryReporting.h"
|
|
#include "mozilla/PodOperations.h"
|
|
|
|
#include "jstypes.h"
|
|
|
|
#include "gc/Heap.h"
|
|
#include "jit/ExecutableAllocator.h"
|
|
#include "jit/ICStubSpace.h"
|
|
#include "jit/IonOptimizationLevels.h"
|
|
#include "jit/IonTypes.h"
|
|
#include "js/UbiNode.h"
|
|
#include "vm/TraceLogging.h"
|
|
#include "vm/TypeInference.h"
|
|
|
|
namespace js {
|
|
namespace jit {
|
|
|
|
class MacroAssembler;
|
|
class PatchableBackedge;
|
|
class IonBuilder;
|
|
class IonICEntry;
|
|
|
|
typedef Vector<JSObject*, 4, JitAllocPolicy> ObjectVector;
|
|
|
|
class JitCode : public gc::TenuredCell
|
|
{
|
|
protected:
|
|
uint8_t* code_;
|
|
ExecutablePool* pool_;
|
|
uint32_t bufferSize_; // Total buffer size. Does not include headerSize_.
|
|
uint32_t insnSize_; // Instruction stream size.
|
|
uint32_t dataSize_; // Size of the read-only data area.
|
|
uint32_t jumpRelocTableBytes_; // Size of the jump relocation table.
|
|
uint32_t dataRelocTableBytes_; // Size of the data relocation table.
|
|
uint32_t preBarrierTableBytes_; // Size of the prebarrier table.
|
|
uint8_t headerSize_ : 5; // Number of bytes allocated before codeStart.
|
|
uint8_t kind_ : 3; // jit::CodeKind, for the memory reporters.
|
|
bool invalidated_ : 1; // Whether the code object has been invalidated.
|
|
// This is necessary to prevent GC tracing.
|
|
bool hasBytecodeMap_ : 1; // Whether the code object has been registered with
|
|
// native=>bytecode mapping tables.
|
|
|
|
#if JS_BITS_PER_WORD == 32
|
|
// Ensure JitCode is gc::Cell aligned.
|
|
uint32_t padding_;
|
|
#endif
|
|
|
|
JitCode()
|
|
: code_(nullptr),
|
|
pool_(nullptr)
|
|
{ }
|
|
JitCode(uint8_t* code, uint32_t bufferSize, uint32_t headerSize, ExecutablePool* pool,
|
|
CodeKind kind)
|
|
: code_(code),
|
|
pool_(pool),
|
|
bufferSize_(bufferSize),
|
|
insnSize_(0),
|
|
dataSize_(0),
|
|
jumpRelocTableBytes_(0),
|
|
dataRelocTableBytes_(0),
|
|
preBarrierTableBytes_(0),
|
|
headerSize_(headerSize),
|
|
kind_(kind),
|
|
invalidated_(false),
|
|
hasBytecodeMap_(false)
|
|
{
|
|
MOZ_ASSERT(CodeKind(kind_) == kind);
|
|
MOZ_ASSERT(headerSize_ == headerSize);
|
|
}
|
|
|
|
uint32_t dataOffset() const {
|
|
return insnSize_;
|
|
}
|
|
uint32_t jumpRelocTableOffset() const {
|
|
return dataOffset() + dataSize_;
|
|
}
|
|
uint32_t dataRelocTableOffset() const {
|
|
return jumpRelocTableOffset() + jumpRelocTableBytes_;
|
|
}
|
|
uint32_t preBarrierTableOffset() const {
|
|
return dataRelocTableOffset() + dataRelocTableBytes_;
|
|
}
|
|
|
|
public:
|
|
uint8_t* raw() const {
|
|
return code_;
|
|
}
|
|
uint8_t* rawEnd() const {
|
|
return code_ + insnSize_;
|
|
}
|
|
bool containsNativePC(const void* addr) const {
|
|
const uint8_t* addr_u8 = (const uint8_t*) addr;
|
|
return raw() <= addr_u8 && addr_u8 < rawEnd();
|
|
}
|
|
size_t instructionsSize() const {
|
|
return insnSize_;
|
|
}
|
|
size_t bufferSize() const {
|
|
return bufferSize_;
|
|
}
|
|
size_t headerSize() const {
|
|
return headerSize_;
|
|
}
|
|
|
|
void traceChildren(JSTracer* trc);
|
|
void finalize(FreeOp* fop);
|
|
void fixupAfterMovingGC() {}
|
|
void setInvalidated() {
|
|
invalidated_ = true;
|
|
}
|
|
|
|
void setHasBytecodeMap() {
|
|
hasBytecodeMap_ = true;
|
|
}
|
|
|
|
void togglePreBarriers(bool enabled);
|
|
|
|
// If this JitCode object has been, effectively, corrupted due to
|
|
// invalidation patching, then we have to remember this so we don't try and
|
|
// trace relocation entries that may now be corrupt.
|
|
bool invalidated() const {
|
|
return !!invalidated_;
|
|
}
|
|
|
|
template <typename T> T as() const {
|
|
return JS_DATA_TO_FUNC_PTR(T, raw());
|
|
}
|
|
|
|
void copyFrom(MacroAssembler& masm);
|
|
|
|
static JitCode* FromExecutable(uint8_t* buffer) {
|
|
JitCode* code = *(JitCode**)(buffer - sizeof(JitCode*));
|
|
MOZ_ASSERT(code->raw() == buffer);
|
|
return code;
|
|
}
|
|
|
|
static size_t offsetOfCode() {
|
|
return offsetof(JitCode, code_);
|
|
}
|
|
|
|
uint8_t* jumpRelocTable() {
|
|
return code_ + jumpRelocTableOffset();
|
|
}
|
|
|
|
// Allocates a new JitCode object which will be managed by the GC. If no
|
|
// object can be allocated, nullptr is returned. On failure, |pool| is
|
|
// automatically released, so the code may be freed.
|
|
template <AllowGC allowGC>
|
|
static JitCode* New(JSContext* cx, uint8_t* code, uint32_t bufferSize, uint32_t headerSize,
|
|
ExecutablePool* pool, CodeKind kind);
|
|
|
|
public:
|
|
static inline ThingRootKind rootKind() { return THING_ROOT_JIT_CODE; }
|
|
};
|
|
|
|
class SnapshotWriter;
|
|
class RecoverWriter;
|
|
class SafepointWriter;
|
|
class SafepointIndex;
|
|
class OsiIndex;
|
|
class IonCache;
|
|
struct PatchableBackedgeInfo;
|
|
struct CacheLocation;
|
|
|
|
// An IonScript attaches Ion-generated information to a JSScript.
|
|
struct IonScript
|
|
{
|
|
private:
|
|
// Code pointer containing the actual method.
|
|
PreBarrieredJitCode method_;
|
|
|
|
// Deoptimization table used by this method.
|
|
PreBarrieredJitCode deoptTable_;
|
|
|
|
// Entrypoint for OSR, or nullptr.
|
|
jsbytecode* osrPc_;
|
|
|
|
// Offset to OSR entrypoint from method_->raw(), or 0.
|
|
uint32_t osrEntryOffset_;
|
|
|
|
// Offset to entrypoint skipping type arg check from method_->raw().
|
|
uint32_t skipArgCheckEntryOffset_;
|
|
|
|
// Offset of the invalidation epilogue (which pushes this IonScript
|
|
// and calls the invalidation thunk).
|
|
uint32_t invalidateEpilogueOffset_;
|
|
|
|
// The offset immediately after the IonScript immediate.
|
|
// NOTE: technically a constant delta from
|
|
// |invalidateEpilogueOffset_|, so we could hard-code this
|
|
// per-platform if we want.
|
|
uint32_t invalidateEpilogueDataOffset_;
|
|
|
|
// Number of times this script bailed out without invalidation.
|
|
uint32_t numBailouts_;
|
|
|
|
// Flag set if IonScript was compiled with profiling enabled.
|
|
bool hasProfilingInstrumentation_;
|
|
|
|
// Flag for if this script is getting recompiled.
|
|
uint32_t recompiling_;
|
|
|
|
// Any kind of data needed by the runtime, these can be either cache
|
|
// information or profiling info.
|
|
uint32_t runtimeData_;
|
|
uint32_t runtimeSize_;
|
|
|
|
// State for polymorphic caches in the compiled code. All caches are stored
|
|
// in the runtimeData buffer and indexed by the cacheIndex which give a
|
|
// relative offset in the runtimeData array.
|
|
uint32_t cacheIndex_;
|
|
uint32_t cacheEntries_;
|
|
|
|
// Map code displacement to safepoint / OSI-patch-delta.
|
|
uint32_t safepointIndexOffset_;
|
|
uint32_t safepointIndexEntries_;
|
|
|
|
// Offset to and length of the safepoint table in bytes.
|
|
uint32_t safepointsStart_;
|
|
uint32_t safepointsSize_;
|
|
|
|
// Number of bytes this function reserves on the stack.
|
|
uint32_t frameSlots_;
|
|
|
|
// Number of bytes used passed in as formal arguments or |this|.
|
|
uint32_t argumentSlots_;
|
|
|
|
// Frame size is the value that can be added to the StackPointer along
|
|
// with the frame prefix to get a valid JitFrameLayout.
|
|
uint32_t frameSize_;
|
|
|
|
// Table mapping bailout IDs to snapshot offsets.
|
|
uint32_t bailoutTable_;
|
|
uint32_t bailoutEntries_;
|
|
|
|
// Map OSI-point displacement to snapshot.
|
|
uint32_t osiIndexOffset_;
|
|
uint32_t osiIndexEntries_;
|
|
|
|
// Offset from the start of the code buffer to its snapshot buffer.
|
|
uint32_t snapshots_;
|
|
uint32_t snapshotsListSize_;
|
|
uint32_t snapshotsRVATableSize_;
|
|
|
|
// List of instructions needed to recover stack frames.
|
|
uint32_t recovers_;
|
|
uint32_t recoversSize_;
|
|
|
|
// Constant table for constants stored in snapshots.
|
|
uint32_t constantTable_;
|
|
uint32_t constantEntries_;
|
|
|
|
// List of patchable backedges which are threaded into the runtime's list.
|
|
uint32_t backedgeList_;
|
|
uint32_t backedgeEntries_;
|
|
|
|
// List of entries to the shared stub.
|
|
uint32_t sharedStubList_;
|
|
uint32_t sharedStubEntries_;
|
|
|
|
// Number of references from invalidation records.
|
|
uint32_t invalidationCount_;
|
|
|
|
// Identifier of the compilation which produced this code.
|
|
RecompileInfo recompileInfo_;
|
|
|
|
// The optimization level this script was compiled in.
|
|
OptimizationLevel optimizationLevel_;
|
|
|
|
// Number of times we tried to enter this script via OSR but failed due to
|
|
// a LOOPENTRY pc other than osrPc_.
|
|
uint32_t osrPcMismatchCounter_;
|
|
|
|
// Allocated space for fallback stubs.
|
|
FallbackICStubSpace fallbackStubSpace_;
|
|
|
|
// The tracelogger event used to log the start/stop of this IonScript.
|
|
TraceLoggerEvent traceLoggerScriptEvent_;
|
|
|
|
private:
|
|
inline uint8_t* bottomBuffer() {
|
|
return reinterpret_cast<uint8_t*>(this);
|
|
}
|
|
inline const uint8_t* bottomBuffer() const {
|
|
return reinterpret_cast<const uint8_t*>(this);
|
|
}
|
|
|
|
public:
|
|
|
|
SnapshotOffset* bailoutTable() {
|
|
return (SnapshotOffset*) &bottomBuffer()[bailoutTable_];
|
|
}
|
|
PreBarrieredValue* constants() {
|
|
return (PreBarrieredValue*) &bottomBuffer()[constantTable_];
|
|
}
|
|
const SafepointIndex* safepointIndices() const {
|
|
return const_cast<IonScript*>(this)->safepointIndices();
|
|
}
|
|
SafepointIndex* safepointIndices() {
|
|
return (SafepointIndex*) &bottomBuffer()[safepointIndexOffset_];
|
|
}
|
|
const OsiIndex* osiIndices() const {
|
|
return const_cast<IonScript*>(this)->osiIndices();
|
|
}
|
|
OsiIndex* osiIndices() {
|
|
return (OsiIndex*) &bottomBuffer()[osiIndexOffset_];
|
|
}
|
|
uint32_t* cacheIndex() {
|
|
return (uint32_t*) &bottomBuffer()[cacheIndex_];
|
|
}
|
|
uint8_t* runtimeData() {
|
|
return &bottomBuffer()[runtimeData_];
|
|
}
|
|
PatchableBackedge* backedgeList() {
|
|
return (PatchableBackedge*) &bottomBuffer()[backedgeList_];
|
|
}
|
|
|
|
private:
|
|
void trace(JSTracer* trc);
|
|
|
|
public:
|
|
// Do not call directly, use IonScript::New. This is public for cx->new_.
|
|
IonScript();
|
|
|
|
static IonScript* New(JSContext* cx, RecompileInfo recompileInfo,
|
|
uint32_t frameSlots, uint32_t argumentSlots, uint32_t frameSize,
|
|
size_t snapshotsListSize, size_t snapshotsRVATableSize,
|
|
size_t recoversSize, size_t bailoutEntries,
|
|
size_t constants, size_t safepointIndexEntries,
|
|
size_t osiIndexEntries, size_t cacheEntries,
|
|
size_t runtimeSize, size_t safepointsSize,
|
|
size_t backedgeEntries, size_t sharedStubEntries,
|
|
OptimizationLevel optimizationLevel);
|
|
static void Trace(JSTracer* trc, IonScript* script);
|
|
static void Destroy(FreeOp* fop, IonScript* script);
|
|
|
|
static inline size_t offsetOfMethod() {
|
|
return offsetof(IonScript, method_);
|
|
}
|
|
static inline size_t offsetOfOsrEntryOffset() {
|
|
return offsetof(IonScript, osrEntryOffset_);
|
|
}
|
|
static inline size_t offsetOfSkipArgCheckEntryOffset() {
|
|
return offsetof(IonScript, skipArgCheckEntryOffset_);
|
|
}
|
|
static inline size_t offsetOfInvalidationCount() {
|
|
return offsetof(IonScript, invalidationCount_);
|
|
}
|
|
static inline size_t offsetOfRecompiling() {
|
|
return offsetof(IonScript, recompiling_);
|
|
}
|
|
|
|
public:
|
|
JitCode* method() const {
|
|
return method_;
|
|
}
|
|
void setMethod(JitCode* code) {
|
|
MOZ_ASSERT(!invalidated());
|
|
method_ = code;
|
|
}
|
|
void setDeoptTable(JitCode* code) {
|
|
deoptTable_ = code;
|
|
}
|
|
void setOsrPc(jsbytecode* osrPc) {
|
|
osrPc_ = osrPc;
|
|
}
|
|
jsbytecode* osrPc() const {
|
|
return osrPc_;
|
|
}
|
|
void setOsrEntryOffset(uint32_t offset) {
|
|
MOZ_ASSERT(!osrEntryOffset_);
|
|
osrEntryOffset_ = offset;
|
|
}
|
|
uint32_t osrEntryOffset() const {
|
|
return osrEntryOffset_;
|
|
}
|
|
void setSkipArgCheckEntryOffset(uint32_t offset) {
|
|
MOZ_ASSERT(!skipArgCheckEntryOffset_);
|
|
skipArgCheckEntryOffset_ = offset;
|
|
}
|
|
uint32_t getSkipArgCheckEntryOffset() const {
|
|
return skipArgCheckEntryOffset_;
|
|
}
|
|
bool containsCodeAddress(uint8_t* addr) const {
|
|
return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize();
|
|
}
|
|
bool containsReturnAddress(uint8_t* addr) const {
|
|
// This accounts for an off by one error caused by the return address of a
|
|
// bailout sitting outside the range of the containing function.
|
|
return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize();
|
|
}
|
|
void setInvalidationEpilogueOffset(uint32_t offset) {
|
|
MOZ_ASSERT(!invalidateEpilogueOffset_);
|
|
invalidateEpilogueOffset_ = offset;
|
|
}
|
|
uint32_t invalidateEpilogueOffset() const {
|
|
MOZ_ASSERT(invalidateEpilogueOffset_);
|
|
return invalidateEpilogueOffset_;
|
|
}
|
|
void setInvalidationEpilogueDataOffset(uint32_t offset) {
|
|
MOZ_ASSERT(!invalidateEpilogueDataOffset_);
|
|
invalidateEpilogueDataOffset_ = offset;
|
|
}
|
|
uint32_t invalidateEpilogueDataOffset() const {
|
|
MOZ_ASSERT(invalidateEpilogueDataOffset_);
|
|
return invalidateEpilogueDataOffset_;
|
|
}
|
|
void incNumBailouts() {
|
|
numBailouts_++;
|
|
}
|
|
uint32_t numBailouts() const {
|
|
return numBailouts_;
|
|
}
|
|
bool bailoutExpected() const {
|
|
return numBailouts_ > 0;
|
|
}
|
|
void setHasProfilingInstrumentation() {
|
|
hasProfilingInstrumentation_ = true;
|
|
}
|
|
void clearHasProfilingInstrumentation() {
|
|
hasProfilingInstrumentation_ = false;
|
|
}
|
|
bool hasProfilingInstrumentation() const {
|
|
return hasProfilingInstrumentation_;
|
|
}
|
|
void setTraceLoggerEvent(TraceLoggerEvent& event) {
|
|
traceLoggerScriptEvent_ = event;
|
|
}
|
|
const uint8_t* snapshots() const {
|
|
return reinterpret_cast<const uint8_t*>(this) + snapshots_;
|
|
}
|
|
size_t snapshotsListSize() const {
|
|
return snapshotsListSize_;
|
|
}
|
|
size_t snapshotsRVATableSize() const {
|
|
return snapshotsRVATableSize_;
|
|
}
|
|
const uint8_t* recovers() const {
|
|
return reinterpret_cast<const uint8_t*>(this) + recovers_;
|
|
}
|
|
size_t recoversSize() const {
|
|
return recoversSize_;
|
|
}
|
|
const uint8_t* safepoints() const {
|
|
return reinterpret_cast<const uint8_t*>(this) + safepointsStart_;
|
|
}
|
|
size_t safepointsSize() const {
|
|
return safepointsSize_;
|
|
}
|
|
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
|
return mallocSizeOf(this);
|
|
}
|
|
PreBarrieredValue& getConstant(size_t index) {
|
|
MOZ_ASSERT(index < numConstants());
|
|
return constants()[index];
|
|
}
|
|
size_t numConstants() const {
|
|
return constantEntries_;
|
|
}
|
|
uint32_t frameSlots() const {
|
|
return frameSlots_;
|
|
}
|
|
uint32_t argumentSlots() const {
|
|
return argumentSlots_;
|
|
}
|
|
uint32_t frameSize() const {
|
|
return frameSize_;
|
|
}
|
|
SnapshotOffset bailoutToSnapshot(uint32_t bailoutId) {
|
|
MOZ_ASSERT(bailoutId < bailoutEntries_);
|
|
return bailoutTable()[bailoutId];
|
|
}
|
|
const SafepointIndex* getSafepointIndex(uint32_t disp) const;
|
|
const SafepointIndex* getSafepointIndex(uint8_t* retAddr) const {
|
|
MOZ_ASSERT(containsCodeAddress(retAddr));
|
|
return getSafepointIndex(retAddr - method()->raw());
|
|
}
|
|
const OsiIndex* getOsiIndex(uint32_t disp) const;
|
|
const OsiIndex* getOsiIndex(uint8_t* retAddr) const;
|
|
inline IonCache& getCacheFromIndex(uint32_t index) {
|
|
MOZ_ASSERT(index < cacheEntries_);
|
|
uint32_t offset = cacheIndex()[index];
|
|
return getCache(offset);
|
|
}
|
|
inline IonCache& getCache(uint32_t offset) {
|
|
MOZ_ASSERT(offset < runtimeSize_);
|
|
return *(IonCache*) &runtimeData()[offset];
|
|
}
|
|
size_t numCaches() const {
|
|
return cacheEntries_;
|
|
}
|
|
IonICEntry* sharedStubList() {
|
|
return (IonICEntry*) &bottomBuffer()[sharedStubList_];
|
|
}
|
|
size_t numSharedStubs() const {
|
|
return sharedStubEntries_;
|
|
}
|
|
size_t runtimeSize() const {
|
|
return runtimeSize_;
|
|
}
|
|
CacheLocation* getCacheLocs(uint32_t locIndex) {
|
|
MOZ_ASSERT(locIndex < runtimeSize_);
|
|
return (CacheLocation*) &runtimeData()[locIndex];
|
|
}
|
|
void toggleBarriers(bool enabled);
|
|
void purgeCaches();
|
|
void unlinkFromRuntime(FreeOp* fop);
|
|
void copySnapshots(const SnapshotWriter* writer);
|
|
void copyRecovers(const RecoverWriter* writer);
|
|
void copyBailoutTable(const SnapshotOffset* table);
|
|
void copyConstants(const Value* vp);
|
|
void copySafepointIndices(const SafepointIndex* firstSafepointIndex, MacroAssembler& masm);
|
|
void copyOsiIndices(const OsiIndex* firstOsiIndex, MacroAssembler& masm);
|
|
void copyRuntimeData(const uint8_t* data);
|
|
void copyCacheEntries(const uint32_t* caches, MacroAssembler& masm);
|
|
void copySafepoints(const SafepointWriter* writer);
|
|
void copyPatchableBackedges(JSContext* cx, JitCode* code,
|
|
PatchableBackedgeInfo* backedges,
|
|
MacroAssembler& masm);
|
|
|
|
bool invalidated() const {
|
|
return invalidationCount_ != 0;
|
|
}
|
|
|
|
// Invalidate the current compilation.
|
|
bool invalidate(JSContext* cx, bool resetUses, const char* reason);
|
|
|
|
size_t invalidationCount() const {
|
|
return invalidationCount_;
|
|
}
|
|
void incrementInvalidationCount() {
|
|
invalidationCount_++;
|
|
}
|
|
void decrementInvalidationCount(FreeOp* fop) {
|
|
MOZ_ASSERT(invalidationCount_);
|
|
invalidationCount_--;
|
|
if (!invalidationCount_)
|
|
Destroy(fop, this);
|
|
}
|
|
const RecompileInfo& recompileInfo() const {
|
|
return recompileInfo_;
|
|
}
|
|
RecompileInfo& recompileInfoRef() {
|
|
return recompileInfo_;
|
|
}
|
|
OptimizationLevel optimizationLevel() const {
|
|
return optimizationLevel_;
|
|
}
|
|
uint32_t incrOsrPcMismatchCounter() {
|
|
return ++osrPcMismatchCounter_;
|
|
}
|
|
void resetOsrPcMismatchCounter() {
|
|
osrPcMismatchCounter_ = 0;
|
|
}
|
|
|
|
void setRecompiling() {
|
|
recompiling_ = true;
|
|
}
|
|
|
|
bool isRecompiling() const {
|
|
return recompiling_;
|
|
}
|
|
|
|
void clearRecompiling() {
|
|
recompiling_ = false;
|
|
}
|
|
|
|
FallbackICStubSpace* fallbackStubSpace() {
|
|
return &fallbackStubSpace_;
|
|
}
|
|
void adoptFallbackStubs(FallbackICStubSpace* stubSpace);
|
|
void purgeOptimizedStubs(Zone* zone);
|
|
|
|
enum ShouldIncreaseAge {
|
|
IncreaseAge = true,
|
|
KeepAge = false
|
|
};
|
|
|
|
static void writeBarrierPre(Zone* zone, IonScript* ionScript);
|
|
};
|
|
|
|
// Execution information for a basic block which may persist after the
|
|
// accompanying IonScript is destroyed, for use during profiling.
|
|
struct IonBlockCounts
|
|
{
|
|
private:
|
|
uint32_t id_;
|
|
|
|
// Approximate bytecode in the outer (not inlined) script this block
|
|
// was generated from.
|
|
uint32_t offset_;
|
|
|
|
// File and line of the inner script this block was generated from.
|
|
char* description_;
|
|
|
|
// ids for successors of this block.
|
|
uint32_t numSuccessors_;
|
|
uint32_t* successors_;
|
|
|
|
// Hit count for this block.
|
|
uint64_t hitCount_;
|
|
|
|
// Text information about the code generated for this block.
|
|
char* code_;
|
|
|
|
public:
|
|
|
|
bool init(uint32_t id, uint32_t offset, char* description, uint32_t numSuccessors) {
|
|
id_ = id;
|
|
offset_ = offset;
|
|
description_ = description;
|
|
numSuccessors_ = numSuccessors;
|
|
if (numSuccessors) {
|
|
successors_ = js_pod_calloc<uint32_t>(numSuccessors);
|
|
if (!successors_)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void destroy() {
|
|
js_free(description_);
|
|
js_free(successors_);
|
|
js_free(code_);
|
|
}
|
|
|
|
uint32_t id() const {
|
|
return id_;
|
|
}
|
|
|
|
uint32_t offset() const {
|
|
return offset_;
|
|
}
|
|
|
|
const char* description() const {
|
|
return description_;
|
|
}
|
|
|
|
size_t numSuccessors() const {
|
|
return numSuccessors_;
|
|
}
|
|
|
|
void setSuccessor(size_t i, uint32_t id) {
|
|
MOZ_ASSERT(i < numSuccessors_);
|
|
successors_[i] = id;
|
|
}
|
|
|
|
uint32_t successor(size_t i) const {
|
|
MOZ_ASSERT(i < numSuccessors_);
|
|
return successors_[i];
|
|
}
|
|
|
|
uint64_t* addressOfHitCount() {
|
|
return &hitCount_;
|
|
}
|
|
|
|
uint64_t hitCount() const {
|
|
return hitCount_;
|
|
}
|
|
|
|
void setCode(const char* code) {
|
|
char* ncode = js_pod_malloc<char>(strlen(code) + 1);
|
|
if (ncode) {
|
|
strcpy(ncode, code);
|
|
code_ = ncode;
|
|
}
|
|
}
|
|
|
|
const char* code() const {
|
|
return code_;
|
|
}
|
|
};
|
|
|
|
// Execution information for a compiled script which may persist after the
|
|
// IonScript is destroyed, for use during profiling.
|
|
struct IonScriptCounts
|
|
{
|
|
private:
|
|
// Any previous invalidated compilation(s) for the script.
|
|
IonScriptCounts* previous_;
|
|
|
|
// Information about basic blocks in this script.
|
|
size_t numBlocks_;
|
|
IonBlockCounts* blocks_;
|
|
|
|
public:
|
|
|
|
IonScriptCounts() {
|
|
mozilla::PodZero(this);
|
|
}
|
|
|
|
~IonScriptCounts() {
|
|
for (size_t i = 0; i < numBlocks_; i++)
|
|
blocks_[i].destroy();
|
|
js_free(blocks_);
|
|
// The list can be long in some corner cases (bug 1140084), so
|
|
// unroll the recursion.
|
|
IonScriptCounts* victims = previous_;
|
|
while (victims) {
|
|
IonScriptCounts* victim = victims;
|
|
victims = victim->previous_;
|
|
victim->previous_ = nullptr;
|
|
js_delete(victim);
|
|
}
|
|
}
|
|
|
|
bool init(size_t numBlocks) {
|
|
blocks_ = js_pod_calloc<IonBlockCounts>(numBlocks);
|
|
if (!blocks_)
|
|
return false;
|
|
|
|
numBlocks_ = numBlocks;
|
|
return true;
|
|
}
|
|
|
|
size_t numBlocks() const {
|
|
return numBlocks_;
|
|
}
|
|
|
|
IonBlockCounts& block(size_t i) {
|
|
MOZ_ASSERT(i < numBlocks_);
|
|
return blocks_[i];
|
|
}
|
|
|
|
void setPrevious(IonScriptCounts* previous) {
|
|
previous_ = previous;
|
|
}
|
|
|
|
IonScriptCounts* previous() const {
|
|
return previous_;
|
|
}
|
|
};
|
|
|
|
struct VMFunction;
|
|
|
|
struct AutoFlushICache
|
|
{
|
|
private:
|
|
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_PPC_OSX)
|
|
uintptr_t start_;
|
|
uintptr_t stop_;
|
|
const char* name_;
|
|
bool inhibit_;
|
|
AutoFlushICache* prev_;
|
|
#endif
|
|
|
|
public:
|
|
static void setRange(uintptr_t p, size_t len);
|
|
static void flush(uintptr_t p, size_t len);
|
|
static void setInhibit();
|
|
~AutoFlushICache();
|
|
explicit AutoFlushICache(const char* nonce, bool inhibit=false);
|
|
};
|
|
|
|
} // namespace jit
|
|
|
|
namespace gc {
|
|
|
|
inline bool
|
|
IsMarked(JSRuntime* rt, const jit::VMFunction*)
|
|
{
|
|
// VMFunction are only static objects which are used by WeakMaps as keys.
|
|
// It is considered as a root object which is always marked.
|
|
return true;
|
|
}
|
|
|
|
} // namespace gc
|
|
|
|
} // namespace js
|
|
|
|
// JS::ubi::Nodes can point to js::jit::JitCode instances; they're js::gc::Cell
|
|
// instances with no associated compartment.
|
|
namespace JS {
|
|
namespace ubi {
|
|
template<>
|
|
struct Concrete<js::jit::JitCode> : TracerConcrete<js::jit::JitCode> {
|
|
CoarseType coarseType() const final { return CoarseType::Script; }
|
|
|
|
Size size(mozilla::MallocSizeOf mallocSizeOf) const override {
|
|
Size size = js::gc::Arena::thingSize(get().asTenured().getAllocKind());
|
|
size += get().bufferSize();
|
|
size += get().headerSize();
|
|
return size;
|
|
}
|
|
|
|
protected:
|
|
explicit Concrete(js::jit::JitCode *ptr) : TracerConcrete<js::jit::JitCode>(ptr) { }
|
|
|
|
public:
|
|
static void construct(void *storage, js::jit::JitCode *ptr) { new (storage) Concrete(ptr); }
|
|
};
|
|
|
|
} // namespace ubi
|
|
} // namespace JS
|
|
|
|
#endif /* jit_IonCode_h */
|