JitcodeMap.h
/* -*- 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_JitcodeMap_h
#define jit_JitcodeMap_h
#include "ds/SplayTree.h"
#include "jit/CompactBuffer.h"
#include "jit/CompileInfo.h"
#include "jit/shared/CodeGenerator-shared.h"
namespace js {
namespace jit {
/*
* The Ion jitcode map implements tables to allow mapping from addresses in ion jitcode
* to the list of (JSScript *, jsbytecode *) pairs that are implicitly active in the frame at
* that point in the native code.
*
* To represent this information efficiently, a multi-level table is used.
*
* At the top level, a global splay-tree of JitcodeGlobalEntry describings the mapping for
* each individual IonCode script generated by compiles. The entries are ordered by their
* nativeStartAddr.
*
* Every entry in the table is of fixed size, but there are different entry types,
* distinguished by the kind field.
*/
class JitcodeIonTable;
class JitcodeRegionEntry;
class JitcodeGlobalEntry
{
public:
enum Kind {
INVALID = 0,
Ion,
Baseline,
IonCache,
Query,
LIMIT
};
JS_STATIC_ASSERT(LIMIT <= 8);
struct BytecodeLocation {
JSScript *script;
jsbytecode *pc;
BytecodeLocation(JSScript *script, jsbytecode *pc) : script(script), pc(pc) {}
};
typedef Vector<BytecodeLocation, 0, SystemAllocPolicy> BytecodeLocationVector;
struct BaseEntry
{
void *nativeStartAddr_;
void *nativeEndAddr_;
Kind kind_;
void init() {
nativeStartAddr_ = nullptr;
nativeEndAddr_ = nullptr;
kind_ = INVALID;
}
void init(Kind kind, void *nativeStartAddr, void *nativeEndAddr) {
MOZ_ASSERT(nativeStartAddr);
MOZ_ASSERT(nativeEndAddr);
MOZ_ASSERT(kind > INVALID && kind < LIMIT);
nativeStartAddr_ = nativeStartAddr;
nativeEndAddr_ = nativeEndAddr;
kind_ = kind;
}
Kind kind() const {
return kind_;
}
void *nativeStartAddr() const {
return nativeStartAddr_;
}
void *nativeEndAddr() const {
return nativeEndAddr_;
}
bool startsBelowPointer(void *ptr) const {
return ((uint8_t *)nativeStartAddr()) <= ((uint8_t *) ptr);
}
bool endsAbovePointer(void *ptr) const {
return ((uint8_t *)nativeEndAddr()) > ((uint8_t *) ptr);
}
bool containsPointer(void *ptr) const {
return startsBelowPointer(ptr) && endsAbovePointer(ptr);
}
};
struct IonEntry : public BaseEntry
{
uintptr_t scriptList_;
// regionTable_ points to the start of the region table within the
// packed map for compile represented by this entry. Since the
// region table occurs at the tail of the memory region, this pointer
// points somewhere inside the region memory space, and not to the start
// of the memory space.
JitcodeIonTable *regionTable_;
static const unsigned LowBits = 3;
static const uintptr_t LowMask = (uintptr_t(1) << LowBits) - 1;
enum ScriptListTag {
Single = 0,
Multi = 7
};
struct SizedScriptList {
uint32_t size;
JSScript *scripts[0];
SizedScriptList(uint32_t sz, JSScript **scr) : size(sz) {
for (uint32_t i = 0; i < size; i++)
scripts[i] = scr[i];
}
static uint32_t AllocSizeFor(uint32_t nscripts) {
return sizeof(SizedScriptList) + (nscripts * sizeof(JSScript *));
}
};
void init(void *nativeStartAddr, void *nativeEndAddr,
JSScript *script, JitcodeIonTable *regionTable)
{
MOZ_ASSERT((uintptr_t(script) & LowMask) == 0);
MOZ_ASSERT(script);
MOZ_ASSERT(regionTable);
BaseEntry::init(Ion, nativeStartAddr, nativeEndAddr);
scriptList_ = uintptr_t(script);
regionTable_ = regionTable;
}
void init(void *nativeStartAddr, void *nativeEndAddr,
unsigned numScripts, JSScript **scripts, JitcodeIonTable *regionTable)
{
MOZ_ASSERT((uintptr_t(scripts) & LowMask) == 0);
MOZ_ASSERT(numScripts >= 1);
MOZ_ASSERT(numScripts <= 6);
MOZ_ASSERT(scripts);
MOZ_ASSERT(regionTable);
BaseEntry::init(Ion, nativeStartAddr, nativeEndAddr);
scriptList_ = uintptr_t(scripts) | numScripts;
regionTable_ = regionTable;
}
void init(void *nativeStartAddr, void *nativeEndAddr,
SizedScriptList *scripts, JitcodeIonTable *regionTable)
{
MOZ_ASSERT((uintptr_t(scripts) & LowMask) == 0);
MOZ_ASSERT(scripts->size > 6);
MOZ_ASSERT(scripts);
MOZ_ASSERT(regionTable);
BaseEntry::init(Ion, nativeStartAddr, nativeEndAddr);
scriptList_ = uintptr_t(scripts) | uintptr_t(Multi);
regionTable_ = regionTable;
}
ScriptListTag scriptListTag() const {
return static_cast<ScriptListTag>(scriptList_ & LowMask);
}
void *scriptListPointer() const {
return reinterpret_cast<void *>(scriptList_ & ~LowMask);
}
JSScript *singleScript() const {
MOZ_ASSERT(scriptListTag() == Single);
return reinterpret_cast<JSScript *>(scriptListPointer());
}
JSScript **rawScriptArray() const {
MOZ_ASSERT(scriptListTag() < Multi);
return reinterpret_cast<JSScript **>(scriptListPointer());
}
SizedScriptList *sizedScriptList() const {
MOZ_ASSERT(scriptListTag() == Multi);
return reinterpret_cast<SizedScriptList *>(scriptListPointer());
}
unsigned numScripts() const {
ScriptListTag tag = scriptListTag();
if (tag == Single)
return 1;
if (tag < Multi) {
MOZ_ASSERT(int(tag) >= 2);
return static_cast<unsigned>(tag);
}
return sizedScriptList()->size;
}
JSScript *getScript(unsigned idx) const {
MOZ_ASSERT(idx < numScripts());
ScriptListTag tag = scriptListTag();
if (tag == Single)
return singleScript();
if (tag < Multi) {
MOZ_ASSERT(int(tag) >= 2);
return rawScriptArray()[idx];
}
return sizedScriptList()->scripts[idx];
}
void destroy();
JitcodeIonTable *regionTable() const {
return regionTable_;
}
int scriptIndex(JSScript *script) const {
unsigned count = numScripts();
for (unsigned i = 0; i < count; i++) {
if (getScript(i) == script)
return i;
}
return -1;
}
bool callStackAtAddr(JSRuntime *rt, void *ptr, BytecodeLocationVector &results,
uint32_t *depth) const;
};
struct BaselineEntry : public BaseEntry
{
JSScript *script_;
void init(void *nativeStartAddr, void *nativeEndAddr, JSScript *script)
{
MOZ_ASSERT(script != nullptr);
BaseEntry::init(Baseline, nativeStartAddr, nativeEndAddr);
script_ = script;
}
JSScript *script() const {
return script_;
}
void destroy() {}
bool callStackAtAddr(JSRuntime *rt, void *ptr, BytecodeLocationVector &results,
uint32_t *depth) const;
};
struct IonCacheEntry : public BaseEntry
{
void *rejoinAddr_;
void init(void *nativeStartAddr, void *nativeEndAddr, void *rejoinAddr)
{
MOZ_ASSERT(rejoinAddr != nullptr);
BaseEntry::init(IonCache, nativeStartAddr, nativeEndAddr);
rejoinAddr_ = rejoinAddr;
}
void *rejoinAddr() const {
return rejoinAddr_;
}
void destroy() {}
bool callStackAtAddr(JSRuntime *rt, void *ptr, BytecodeLocationVector &results,
uint32_t *depth) const;
};
// QueryEntry is never stored in the table, just used for queries
// where an instance of JitcodeGlobalEntry is required to do tree
// lookups.
struct QueryEntry : public BaseEntry
{
void init(void *addr) {
BaseEntry::init(Query, addr, addr);
}
uint8_t *addr() const {
return reinterpret_cast<uint8_t *>(nativeStartAddr());
}
void destroy() {}
};
private:
union {
// Shadowing BaseEntry instance to allow access to base fields
// and type extraction.
BaseEntry base_;
// The most common entry type: describing jitcode generated by
// Ion main-line code.
IonEntry ion_;
// Baseline jitcode.
BaselineEntry baseline_;
// IonCache stubs.
IonCacheEntry ionCache_;
// When doing queries on the SplayTree for particular addresses,
// the query addresses are representd using a QueryEntry.
QueryEntry query_;
};
public:
JitcodeGlobalEntry() {
base_.init();
}
explicit JitcodeGlobalEntry(const IonEntry &ion) {
ion_ = ion;
}
explicit JitcodeGlobalEntry(const BaselineEntry &baseline) {
baseline_ = baseline;
}
explicit JitcodeGlobalEntry(const IonCacheEntry &ionCache) {
ionCache_ = ionCache;
}
explicit JitcodeGlobalEntry(const QueryEntry &query) {
query_ = query;
}
static JitcodeGlobalEntry MakeQuery(void *ptr) {
QueryEntry query;
query.init(ptr);
return JitcodeGlobalEntry(query);
}
void destroy() {
switch (kind()) {
case Ion:
ionEntry().destroy();
break;
case Baseline:
baselineEntry().destroy();
break;
case IonCache:
ionCacheEntry().destroy();
break;
case Query:
queryEntry().destroy();
break;
default:
MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
}
}
void *nativeStartAddr() const {
return base_.nativeStartAddr();
}
void *nativeEndAddr() const {
return base_.nativeEndAddr();
}
bool startsBelowPointer(void *ptr) const {
return base_.startsBelowPointer(ptr);
}
bool endsAbovePointer(void *ptr) const {
return base_.endsAbovePointer(ptr);
}
bool containsPointer(void *ptr) const {
return base_.containsPointer(ptr);
}
bool overlapsWith(const JitcodeGlobalEntry &entry) const {
// Catch full containment of |entry| within |this|, and partial overlaps.
if (containsPointer(entry.nativeStartAddr()) || containsPointer(entry.nativeEndAddr()))
return true;
// Catch full containment of |this| within |entry|.
if (startsBelowPointer(entry.nativeEndAddr()) && endsAbovePointer(entry.nativeStartAddr()))
return true;
return false;
}
Kind kind() const {
return base_.kind();
}
bool isIon() const {
return kind() == Ion;
}
bool isBaseline() const {
return kind() == Baseline;
}
bool isIonCache() const {
return kind() == IonCache;
}
bool isQuery() const {
return kind() == Query;
}
IonEntry &ionEntry() {
MOZ_ASSERT(isIon());
return ion_;
}
BaselineEntry &baselineEntry() {
MOZ_ASSERT(isBaseline());
return baseline_;
}
IonCacheEntry &ionCacheEntry() {
MOZ_ASSERT(isIonCache());
return ionCache_;
}
QueryEntry &queryEntry() {
MOZ_ASSERT(isQuery());
return query_;
}
const IonEntry &ionEntry() const {
MOZ_ASSERT(isIon());
return ion_;
}
const BaselineEntry &baselineEntry() const {
MOZ_ASSERT(isBaseline());
return baseline_;
}
const IonCacheEntry &ionCacheEntry() const {
MOZ_ASSERT(isIonCache());
return ionCache_;
}
const QueryEntry &queryEntry() const {
MOZ_ASSERT(isQuery());
return query_;
}
// Read the inline call stack at a given point in the native code and append into
// the given vector. Innermost (script,pc) pair will be appended first, and
// outermost appended last.
//
// Returns false on memory failure.
bool callStackAtAddr(JSRuntime *rt, void *ptr, BytecodeLocationVector &results,
uint32_t *depth) const
{
switch (kind()) {
case Ion:
return ionEntry().callStackAtAddr(rt, ptr, results, depth);
case Baseline:
return baselineEntry().callStackAtAddr(rt, ptr, results, depth);
case IonCache:
return ionCacheEntry().callStackAtAddr(rt, ptr, results, depth);
default:
MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
}
return false;
}
// Figure out the number of the (JSScript *, jsbytecode *) pairs that are active
// at this location.
uint32_t lookupInlineCallDepth(void *ptr);
// Compare two global entries.
static int compare(const JitcodeGlobalEntry &ent1, const JitcodeGlobalEntry &ent2);
};
/*
* Global table of JitcodeGlobalEntry values sorted by native address range.
*/
class JitcodeGlobalTable
{
public:
typedef SplayTree<JitcodeGlobalEntry, JitcodeGlobalEntry> EntryTree;
typedef Vector<JitcodeGlobalEntry, 0, SystemAllocPolicy> EntryVector;
private:
static const size_t LIFO_CHUNK_SIZE = 16 * 1024;
LifoAlloc treeAlloc_;
EntryTree tree_;
EntryVector entries_;
public:
JitcodeGlobalTable() : treeAlloc_(LIFO_CHUNK_SIZE), tree_(&treeAlloc_), entries_() {
// Always checking coherency in DEBUG builds may cause tests to time
// out under --baseline-eager or --ion-eager.
tree_.disableCheckCoherency();
}
~JitcodeGlobalTable() {}
bool empty() const {
return tree_.empty();
}
bool lookup(void *ptr, JitcodeGlobalEntry *result);
void lookupInfallible(void *ptr, JitcodeGlobalEntry *result);
bool addEntry(const JitcodeGlobalEntry::IonEntry &entry) {
return addEntry(JitcodeGlobalEntry(entry));
}
bool addEntry(const JitcodeGlobalEntry::BaselineEntry &entry) {
return addEntry(JitcodeGlobalEntry(entry));
}
bool addEntry(const JitcodeGlobalEntry::IonCacheEntry &entry) {
return addEntry(JitcodeGlobalEntry(entry));
}
void removeEntry(void *startAddr);
private:
bool addEntry(const JitcodeGlobalEntry &entry);
};
/*
* Container class for main jitcode table.
* The Region table's memory is structured as follows:
*
* +------------------------------------------------+ |
* | Region 1 Run | |
* |------------------------------------------------| |
* | Region 2 Run | |
* | | |
* | | |
* |------------------------------------------------| |
* | Region 3 Run | |
* | | |
* |------------------------------------------------| |-- Payload
* | | |
* | ... | |
* | | |
* |------------------------------------------------| |
* | Region M Run | |
* | | |
* +================================================+ <- RegionTable pointer points here
* | uint23_t numRegions = M | |
* +------------------------------------------------+ |
* | Region 1 | |
* | uint32_t entryOffset = size(Payload) | |
* +------------------------------------------------+ |
* | | |-- Table
* | ... | |
* | | |
* +------------------------------------------------+ |
* | Region M | |
* | uint32_t entryOffset | |
* +------------------------------------------------+ |
*
* The region table is composed of two sections: a tail section that contains a table of
* fixed-size entries containing offsets into the the head section, and a head section that
* holds a sequence of variable-sized runs. The table in the tail section serves to
* locate the variable-length encoded structures in the head section.
*
* The entryOffsets in the table indicate the bytes offset to subtract from the regionTable
* pointer to arrive at the encoded region in the payload.
*
*
* Variable-length entries in payload
* ----------------------------------
* The entryOffsets in the region table's fixed-sized entries refer to a location within the
* variable-length payload section. This location contains a compactly encoded "run" of
* mappings.
*
* Each run starts by describing the offset within the native code it starts at, and the
* sequence of (JSScript *, jsbytecode *) pairs active at that site. Following that, there
* are a number of variable-length entries encoding (nativeOffsetDelta, bytecodeOffsetDelta)
* pairs for the run.
*
* VarUint32 nativeOffset;
* - The offset from nativeStartAddr in the global table entry at which
* the jitcode for this region starts.
*
* Uint8_t scriptDepth;
* - The depth of inlined scripts for this region.
*
* List<VarUint32> inlineScriptPcStack;
* - We encode (2 * scriptDepth) VarUint32s here. Each pair of uint32s are taken
* as an index into the scriptList in the global table entry, and a pcOffset
* respectively.
*
* List<NativeAndBytecodeDelta> deltaRun;
* - The rest of the entry is a deltaRun that stores a series of variable-length
* encoded NativeAndBytecodeDelta datums.
*/
class JitcodeRegionEntry
{
private:
static const unsigned MAX_RUN_LENGTH = 100;
public:
static void WriteHead(CompactBufferWriter &writer,
uint32_t nativeOffset, uint8_t scriptDepth);
static void ReadHead(CompactBufferReader &reader,
uint32_t *nativeOffset, uint8_t *scriptDepth);
static void WriteScriptPc(CompactBufferWriter &writer, uint32_t scriptIdx, uint32_t pcOffset);
static void ReadScriptPc(CompactBufferReader &reader, uint32_t *scriptIdx, uint32_t *pcOffset);
static void WriteDelta(CompactBufferWriter &writer, uint32_t nativeDelta, int32_t pcDelta);
static void ReadDelta(CompactBufferReader &reader, uint32_t *nativeDelta, int32_t *pcDelta);
// Given a pointer into an array of NativeToBytecode (and a pointer to the end of the array),
// compute the number of entries that would be consume by outputting a run starting
// at this one.
static uint32_t ExpectedRunLength(const CodeGeneratorShared::NativeToBytecode *entry,
const CodeGeneratorShared::NativeToBytecode *end);
// Write a run, starting at the given NativeToBytecode entry, into the given buffer writer.
static bool WriteRun(CompactBufferWriter &writer,
JSScript **scriptList, uint32_t scriptListSize,
uint32_t runLength, const CodeGeneratorShared::NativeToBytecode *entry);
// Delta Run entry formats are encoded little-endian:
//
// byte 0
// NNNN-BBB0
// Single byte format. nativeDelta in [0, 15], pcDelta in [0, 7]
//
static const uint32_t ENC1_MASK = 0x1;
static const uint32_t ENC1_MASK_VAL = 0x0;
static const uint32_t ENC1_NATIVE_DELTA_MAX = 0xf;
static const unsigned ENC1_NATIVE_DELTA_SHIFT = 4;
static const uint32_t ENC1_PC_DELTA_MASK = 0x0e;
static const int32_t ENC1_PC_DELTA_MAX = 0x7;
static const unsigned ENC1_PC_DELTA_SHIFT = 1;
// byte 1 byte 0
// NNNN-NNNN BBBB-BB01
// Two-byte format. nativeDelta in [0, 255], pcDelta in [0, 63]
//
static const uint32_t ENC2_MASK = 0x3;
static const uint32_t ENC2_MASK_VAL = 0x1;
static const uint32_t ENC2_NATIVE_DELTA_MAX = 0xff;
static const unsigned ENC2_NATIVE_DELTA_SHIFT = 8;
static const uint32_t ENC2_PC_DELTA_MASK = 0x00fc;
static const int32_t ENC2_PC_DELTA_MAX = 0x3f;
static const unsigned ENC2_PC_DELTA_SHIFT = 2;
// byte 2 byte 1 byte 0
// NNNN-NNNN NNNB-BBBB BBBB-B011
// Three-byte format. nativeDelta in [0, 2047], pcDelta in [-512, 511]
//
static const uint32_t ENC3_MASK = 0x7;
static const uint32_t ENC3_MASK_VAL = 0x3;
static const uint32_t ENC3_NATIVE_DELTA_MAX = 0x7ff;
static const unsigned ENC3_NATIVE_DELTA_SHIFT = 13;
static const uint32_t ENC3_PC_DELTA_MASK = 0x001ff8;
static const int32_t ENC3_PC_DELTA_MAX = 0x1ff;
static const int32_t ENC3_PC_DELTA_MIN = -ENC3_PC_DELTA_MAX - 1;
static const unsigned ENC3_PC_DELTA_SHIFT = 3;
// byte 3 byte 2 byte 1 byte 0
// NNNN-NNNN NNNN-NNNN BBBB-BBBB BBBB-B111
// Three-byte format. nativeDelta in [0, 65535], pcDelta in [-4096, 4095]
static const uint32_t ENC4_MASK = 0x7;
static const uint32_t ENC4_MASK_VAL = 0x7;
static const uint32_t ENC4_NATIVE_DELTA_MAX = 0xffff;
static const unsigned ENC4_NATIVE_DELTA_SHIFT = 16;
static const uint32_t ENC4_PC_DELTA_MASK = 0x0000fff8;
static const int32_t ENC4_PC_DELTA_MAX = 0xfff;
static const int32_t ENC4_PC_DELTA_MIN = -ENC4_PC_DELTA_MAX - 1;
static const unsigned ENC4_PC_DELTA_SHIFT = 3;
static bool IsDeltaEncodeable(uint32_t nativeDelta, int32_t pcDelta) {
return (nativeDelta <= ENC4_NATIVE_DELTA_MAX) &&
(pcDelta >= ENC4_PC_DELTA_MIN) && (pcDelta <= ENC4_PC_DELTA_MAX);
}
private:
const uint8_t *data_;
const uint8_t *end_;
// Unpacked state from jitcode entry.
uint32_t nativeOffset_;
uint8_t scriptDepth_;
const uint8_t *scriptPcStack_;
const uint8_t *deltaRun_;
void unpack();
public:
JitcodeRegionEntry(const uint8_t *data, const uint8_t *end)
: data_(data), end_(end),
nativeOffset_(0), scriptDepth_(0),
scriptPcStack_(nullptr), deltaRun_(nullptr)
{
MOZ_ASSERT(data_ < end_);
unpack();
MOZ_ASSERT(scriptPcStack_ < end_);
MOZ_ASSERT(deltaRun_ <= end_);
}
uint32_t nativeOffset() const {
return nativeOffset_;
}
uint32_t scriptDepth() const {
return scriptDepth_;
}
class ScriptPcIterator
{
private:
uint32_t count_;
const uint8_t *start_;
const uint8_t *end_;
uint32_t idx_;
const uint8_t *cur_;
public:
ScriptPcIterator(uint32_t count, const uint8_t *start, const uint8_t *end)
: count_(count), start_(start), end_(end), idx_(0), cur_(start_)
{}
bool hasMore() const
{
MOZ_ASSERT((idx_ == count_) == (cur_ == end_));
MOZ_ASSERT((idx_ < count_) == (cur_ < end_));
return cur_ < end_;
}
void readNext(uint32_t *scriptIdxOut, uint32_t *pcOffsetOut)
{
MOZ_ASSERT(scriptIdxOut);
MOZ_ASSERT(pcOffsetOut);
MOZ_ASSERT(hasMore());
CompactBufferReader reader(cur_, end_);
ReadScriptPc(reader, scriptIdxOut, pcOffsetOut);
cur_ = reader.currentPosition();
MOZ_ASSERT(cur_ <= end_);
idx_++;
MOZ_ASSERT_IF(idx_ == count_, cur_ == end_);
}
void reset() {
idx_ = 0;
cur_ = start_;
}
};
ScriptPcIterator scriptPcIterator() const {
// End of script+pc sequence is the start of the delta run.
return ScriptPcIterator(scriptDepth_, scriptPcStack_, deltaRun_);
}
class DeltaIterator {
private:
const uint8_t *start_;
const uint8_t *end_;
const uint8_t *cur_;
public:
DeltaIterator(const uint8_t *start, const uint8_t *end)
: start_(start), end_(end), cur_(start)
{}
bool hasMore() const
{
MOZ_ASSERT(cur_ <= end_);
return cur_ < end_;
}
void readNext(uint32_t *nativeDeltaOut, int32_t *pcDeltaOut)
{
MOZ_ASSERT(nativeDeltaOut != nullptr);
MOZ_ASSERT(pcDeltaOut != nullptr);
MOZ_ASSERT(hasMore());
CompactBufferReader reader(cur_, end_);
ReadDelta(reader, nativeDeltaOut, pcDeltaOut);
cur_ = reader.currentPosition();
MOZ_ASSERT(cur_ <= end_);
}
void reset() {
cur_ = start_;
}
};
DeltaIterator deltaIterator() const {
return DeltaIterator(deltaRun_, end_);
}
uint32_t findPcOffset(uint32_t queryNativeOffset, uint32_t startPcOffset) const;
};
class JitcodeIonTable
{
private:
/* Variable length payload section "below" here. */
uint32_t numRegions_;
uint32_t regionOffsets_[0];
const uint8_t *payloadEnd() const {
return reinterpret_cast<const uint8_t *>(this);
}
public:
explicit JitcodeIonTable(uint32_t numRegions)
: numRegions_(numRegions)
{
for (uint32_t i = 0; i < numRegions; i++)
regionOffsets_[i] = 0;
}
bool makeIonEntry(JSContext *cx, JitCode *code, uint32_t numScripts, JSScript **scripts,
JitcodeGlobalEntry::IonEntry &out);
uint32_t numRegions() const {
return numRegions_;
}
uint32_t regionOffset(uint32_t regionIndex) const {
MOZ_ASSERT(regionIndex < numRegions());
return regionOffsets_[regionIndex];
}
JitcodeRegionEntry regionEntry(uint32_t regionIndex) const {
const uint8_t *regionStart = payloadEnd() - regionOffset(regionIndex);
const uint8_t *regionEnd = payloadEnd();
if (regionIndex < numRegions_ - 1)
regionEnd -= regionOffset(regionIndex + 1);
return JitcodeRegionEntry(regionStart, regionEnd);
}
bool regionContainsOffset(uint32_t regionIndex, uint32_t nativeOffset) {
MOZ_ASSERT(regionIndex < numRegions());
JitcodeRegionEntry ent = regionEntry(regionIndex);
if (nativeOffset < ent.nativeOffset())
return false;
if (regionIndex == numRegions_ - 1)
return true;
return nativeOffset < regionEntry(regionIndex + 1).nativeOffset();
}
uint32_t findRegionEntry(uint32_t offset) const;
const uint8_t *payloadStart() const {
// The beginning of the payload the beginning of the first region are the same.
return payloadEnd() - regionOffset(0);
}
static bool WriteIonTable(CompactBufferWriter &writer,
JSScript **scriptList, uint32_t scriptListSize,
const CodeGeneratorShared::NativeToBytecode *start,
const CodeGeneratorShared::NativeToBytecode *end,
uint32_t *tableOffsetOut, uint32_t *numRegionsOut);
};
} // namespace jit
} // namespace js
#endif /* jit_JitcodeMap_h */