author | Ted Campbell <tcampbell@mozilla.com> |
Tue, 28 Apr 2020 08:22:01 +0000 | |
changeset 526470 | 5d3704bf89d5abe274c7587afbacf59d92439723 |
parent 526469 | 6158f69d21c7e5cdba5d2d6847aba2d4074fa7c1 |
child 526471 | 33897701906977158dece6031ec204b2bd532627 |
push id | 37357 |
push user | opoprus@mozilla.com |
push date | Tue, 28 Apr 2020 21:47:47 +0000 |
treeherder | mozilla-central@a34695d9b99d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1633425 |
milestone | 77.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
js/src/jit/Ion.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/IonCode.h | file | annotate | diff | comparison | revisions |
--- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -612,16 +612,24 @@ IonScript* IonScript::New(JSContext* cx, size_t safepointsSize, OptimizationLevel optimizationLevel) { if (snapshotsListSize >= MAX_BUFFER_SIZE || (bailoutEntries >= MAX_BUFFER_SIZE / sizeof(uint32_t))) { ReportOutOfMemory(cx); return nullptr; } + // Verify the hardcoded sizes in header are accurate. + static_assert(SizeOf_OsiIndex == sizeof(OsiIndex), + "IonScript has wrong size for OsiIndex"); + static_assert(SizeOf_SafepointIndex == sizeof(SafepointIndex), + "IonScript has wrong size for SafepointIndex"); + static_assert(SizeOf_SnapshotOffset == sizeof(SnapshotOffset), + "IonScript has wrong size for SnapshotOffset"); + CheckedInt<Offset> allocSize = sizeof(IonScript); allocSize += CheckedInt<Offset>(constants) * sizeof(Value); allocSize += CheckedInt<Offset>(runtimeSize); allocSize += CheckedInt<Offset>(osiIndices) * sizeof(OsiIndex); allocSize += CheckedInt<Offset>(safepointIndices) * sizeof(SafepointIndex); allocSize += CheckedInt<Offset>(bailoutEntries) * sizeof(SnapshotOffset); allocSize += CheckedInt<Offset>(icEntries) * sizeof(uint32_t); allocSize += CheckedInt<Offset>(safepointsSize); @@ -640,61 +648,64 @@ IonScript* IonScript::New(JSContext* cx, return nullptr; } IonScript* script = new (raw) IonScript( compilationId, frameSlots, argumentSlots, frameSize, optimizationLevel); Offset offsetCursor = sizeof(IonScript); MOZ_ASSERT(offsetCursor % alignof(Value) == 0); - script->constantTable_ = offsetCursor; - script->constantEntries_ = constants; + script->constantTableOffset_ = offsetCursor; offsetCursor += constants * sizeof(Value); MOZ_ASSERT(offsetCursor % alignof(uint64_t) == 0); - script->runtimeData_ = offsetCursor; - script->runtimeSize_ = runtimeSize; + script->runtimeDataOffset_ = offsetCursor; offsetCursor += runtimeSize; MOZ_ASSERT(offsetCursor % alignof(OsiIndex) == 0); script->osiIndexOffset_ = offsetCursor; - script->osiIndexEntries_ = osiIndices; offsetCursor += osiIndices * sizeof(OsiIndex); MOZ_ASSERT(offsetCursor % alignof(SafepointIndex) == 0); script->safepointIndexOffset_ = offsetCursor; - script->safepointIndexEntries_ = safepointIndices; offsetCursor += safepointIndices * sizeof(SafepointIndex); MOZ_ASSERT(offsetCursor % alignof(SnapshotOffset) == 0); - script->bailoutTable_ = offsetCursor; - script->bailoutEntries_ = bailoutEntries; + script->bailoutTableOffset_ = offsetCursor; offsetCursor += bailoutEntries * sizeof(SnapshotOffset); MOZ_ASSERT(offsetCursor % alignof(uint32_t) == 0); - script->icIndex_ = offsetCursor; - script->icEntries_ = icEntries; + script->icIndexOffset_ = offsetCursor; offsetCursor += icEntries * sizeof(uint32_t); - script->safepointsStart_ = offsetCursor; - script->safepointsSize_ = safepointsSize; + script->safepointsOffset_ = offsetCursor; offsetCursor += safepointsSize; - script->snapshots_ = offsetCursor; - script->snapshotsListSize_ = snapshotsListSize; - script->snapshotsRVATableSize_ = snapshotsRVATableSize; + script->snapshotsOffset_ = offsetCursor; offsetCursor += snapshotsListSize; + + script->rvaTableOffset_ = offsetCursor; offsetCursor += snapshotsRVATableSize; - script->recovers_ = offsetCursor; - script->recoversSize_ = recoversSize; + script->recoversOffset_ = offsetCursor; offsetCursor += recoversSize; script->allocBytes_ = offsetCursor; - MOZ_ASSERT(offsetCursor == allocSize.value()); + + MOZ_ASSERT(script->numConstants() == constants); + MOZ_ASSERT(script->runtimeSize() == runtimeSize); + MOZ_ASSERT(script->numOsiIndices() == osiIndices); + MOZ_ASSERT(script->numSafepointIndices() == safepointIndices); + MOZ_ASSERT(script->numBailoutEntries() == bailoutEntries); + MOZ_ASSERT(script->numICs() == icEntries); + MOZ_ASSERT(script->safepointsSize() == safepointsSize); + MOZ_ASSERT(script->snapshotsListSize() == snapshotsListSize); + MOZ_ASSERT(script->snapshotsRVATableSize() == snapshotsRVATableSize); + MOZ_ASSERT(script->recoversSize() == recoversSize); + MOZ_ASSERT(script->endOffset() == offsetCursor); return script; } void IonScript::trace(JSTracer* trc) { if (method_) { TraceEdge(trc, &method_, "method"); } @@ -712,81 +723,84 @@ void IonScript::trace(JSTracer* trc) { /* static */ void IonScript::writeBarrierPre(Zone* zone, IonScript* ionScript) { if (zone->needsIncrementalBarrier()) { ionScript->trace(zone->barrierTracer()); } } void IonScript::copySnapshots(const SnapshotWriter* writer) { - MOZ_ASSERT(writer->listSize() == snapshotsListSize_); - memcpy((uint8_t*)this + snapshots_, writer->listBuffer(), snapshotsListSize_); - - MOZ_ASSERT(snapshotsRVATableSize_); - MOZ_ASSERT(writer->RVATableSize() == snapshotsRVATableSize_); - memcpy((uint8_t*)this + snapshots_ + snapshotsListSize_, - writer->RVATableBuffer(), snapshotsRVATableSize_); + MOZ_ASSERT(writer->listSize() == snapshotsListSize()); + memcpy(offsetToPointer<uint8_t>(snapshotsOffset()), writer->listBuffer(), + snapshotsListSize()); + + MOZ_ASSERT(snapshotsRVATableSize()); + MOZ_ASSERT(writer->RVATableSize() == snapshotsRVATableSize()); + memcpy(offsetToPointer<uint8_t>(rvaTableOffset()), writer->RVATableBuffer(), + snapshotsRVATableSize()); } void IonScript::copyRecovers(const RecoverWriter* writer) { - MOZ_ASSERT(writer->size() == recoversSize_); - memcpy((uint8_t*)this + recovers_, writer->buffer(), recoversSize_); + MOZ_ASSERT(writer->size() == recoversSize()); + memcpy(offsetToPointer<uint8_t>(recoversOffset()), writer->buffer(), + recoversSize()); } void IonScript::copySafepoints(const SafepointWriter* writer) { - MOZ_ASSERT(writer->size() == safepointsSize_); - memcpy((uint8_t*)this + safepointsStart_, writer->buffer(), safepointsSize_); + MOZ_ASSERT(writer->size() == safepointsSize()); + memcpy(offsetToPointer<uint8_t>(safepointsOffset()), writer->buffer(), + safepointsSize()); } void IonScript::copyBailoutTable(const SnapshotOffset* table) { - memcpy(bailoutTable(), table, bailoutEntries_ * sizeof(uint32_t)); + memcpy(bailoutTable(), table, numBailoutEntries() * sizeof(SnapshotOffset)); } void IonScript::copyConstants(const Value* vp) { - for (size_t i = 0; i < constantEntries_; i++) { + for (size_t i = 0; i < numConstants(); i++) { constants()[i].init(vp[i]); } } void IonScript::copySafepointIndices(const CodegenSafepointIndex* si) { // Convert CodegenSafepointIndex to more compact form. SafepointIndex* table = safepointIndices(); - for (size_t i = 0; i < safepointIndexEntries_; ++i) { + for (size_t i = 0; i < numSafepointIndices(); ++i) { table[i] = SafepointIndex(si[i]); } } void IonScript::copyOsiIndices(const OsiIndex* oi) { - memcpy(osiIndices(), oi, osiIndexEntries_ * sizeof(OsiIndex)); + memcpy(osiIndices(), oi, numOsiIndices() * sizeof(OsiIndex)); } void IonScript::copyRuntimeData(const uint8_t* data) { memcpy(runtimeData(), data, runtimeSize()); } void IonScript::copyICEntries(const uint32_t* icEntries) { memcpy(icIndex(), icEntries, numICs() * sizeof(uint32_t)); // Update the codeRaw_ field in the ICs now that we know the code address. for (size_t i = 0; i < numICs(); i++) { getICFromIndex(i).resetCodeRaw(this); } } const SafepointIndex* IonScript::getSafepointIndex(uint32_t disp) const { - MOZ_ASSERT(safepointIndexEntries_ > 0); + MOZ_ASSERT(numSafepointIndices() > 0); const SafepointIndex* table = safepointIndices(); - if (safepointIndexEntries_ == 1) { + if (numSafepointIndices() == 1) { MOZ_ASSERT(disp == table[0].displacement()); return &table[0]; } size_t minEntry = 0; - size_t maxEntry = safepointIndexEntries_ - 1; + size_t maxEntry = numSafepointIndices() - 1; uint32_t min = table[minEntry].displacement(); uint32_t max = table[maxEntry].displacement(); // Raise if the element is not in the list. MOZ_ASSERT(min <= disp && disp <= max); // Approximate the location of the FrameInfo. size_t guess = (disp - min) * (maxEntry - minEntry) / (max - min) + minEntry; @@ -817,17 +831,17 @@ const SafepointIndex* IonScript::getSafe } } } MOZ_CRASH("displacement not found."); } const OsiIndex* IonScript::getOsiIndex(uint32_t disp) const { - const OsiIndex* end = osiIndices() + osiIndexEntries_; + const OsiIndex* end = osiIndices() + numOsiIndices(); for (const OsiIndex* it = osiIndices(); it != end; ++it) { if (it->returnPointDisplacement() == disp) { return it; } } MOZ_CRASH("Failed to find OSI point return address"); }
--- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -170,57 +170,31 @@ class IonIC; // uint8_t[] snapshotsRVATable() // uint8_t[] recovers() // // Note: These are arranged in order of descending alignment requirements to // avoid the need for padding. The `runtimeData` uses uint64_t alignement due to // its use of mozilla::AlignedStorage2. struct alignas(8) IonScript final : public TrailingArray { private: - // Table of constants referenced in snapshots. (JS::Value alignment) - uint32_t constantTable_ = 0; - uint32_t constantEntries_ = 0; - - // IonIC data structures. (uint64_t alignment) - uint32_t runtimeData_ = 0; - uint32_t runtimeSize_ = 0; - - // Map OSI-point displacement to snapshot. - uint32_t osiIndexOffset_ = 0; - uint32_t osiIndexEntries_ = 0; - - // Map code displacement to safepoint / OSI-patch-delta. - uint32_t safepointIndexOffset_ = 0; - uint32_t safepointIndexEntries_ = 0; - - // Table mapping bailout IDs to snapshot offsets. - uint32_t bailoutTable_ = 0; - uint32_t bailoutEntries_ = 0; + // Offset (in bytes) from `this` to the start of each trailing array. Each + // array ends where following one begins. There is no implicit padding (except + // possible at very end). + Offset constantTableOffset_ = 0; // JS::Value aligned + Offset runtimeDataOffset_ = 0; // uint64_t aligned + Offset osiIndexOffset_ = 0; + Offset safepointIndexOffset_ = 0; + Offset bailoutTableOffset_ = 0; + Offset icIndexOffset_ = 0; + Offset safepointsOffset_ = 0; + Offset snapshotsOffset_ = 0; + Offset rvaTableOffset_ = 0; + Offset recoversOffset_ = 0; + Offset allocBytes_ = 0; - // Offset into `runtimeData` for each (variable-length) IonIC. - uint32_t icIndex_ = 0; - uint32_t icEntries_ = 0; - - // Safepoint table as a CompactBuffer. - uint32_t safepointsStart_ = 0; - uint32_t safepointsSize_ = 0; - - // Snapshot and RValueAllocation tables as CompactBuffers. - uint32_t snapshots_ = 0; - uint32_t snapshotsListSize_ = 0; - uint32_t snapshotsRVATableSize_ = 0; - - // Recover instruction table as a CompactBuffer. - uint32_t recovers_ = 0; - uint32_t recoversSize_ = 0; - - // The size of this allocation. - uint32_t allocBytes_ = 0; - - private: // Code pointer containing the actual method. HeapPtrJitCode method_ = nullptr; // Entrypoint for OSR, or nullptr. jsbytecode* osrPc_ = nullptr; // Offset to OSR entrypoint from method_->raw(), or 0. uint32_t osrEntryOffset_ = 0; @@ -268,43 +242,141 @@ struct alignas(8) IonScript final : publ // Number of times we tried to enter this script via OSR but failed due to // a LOOPENTRY pc other than osrPc_. uint32_t osrPcMismatchCounter_ = 0; // TraceLogger events that are baked into the IonScript. TraceLoggerEventVector traceLoggerEvents_; + // End of fields. + private: inline uint8_t* bottomBuffer() { return reinterpret_cast<uint8_t*>(this); } inline const uint8_t* bottomBuffer() const { return reinterpret_cast<const uint8_t*>(this); } + // Layout helpers + Offset constantTableOffset() const { return constantTableOffset_; } + Offset runtimeDataOffset() const { return runtimeDataOffset_; } + Offset osiIndexOffset() const { return osiIndexOffset_; } + Offset safepointIndexOffset() const { return safepointIndexOffset_; } + Offset bailoutTableOffset() const { return bailoutTableOffset_; } + Offset icIndexOffset() const { return icIndexOffset_; } + Offset safepointsOffset() const { return safepointsOffset_; } + Offset snapshotsOffset() const { return snapshotsOffset_; } + Offset rvaTableOffset() const { return rvaTableOffset_; } + Offset recoversOffset() const { return recoversOffset_; } + Offset endOffset() const { return allocBytes_; } + + // Hardcode size of incomplete types. These are verified in Ion.cpp. + static constexpr size_t SizeOf_OsiIndex = 2 * sizeof(uint32_t); + static constexpr size_t SizeOf_SafepointIndex = 2 * sizeof(uint32_t); + static constexpr size_t SizeOf_SnapshotOffset = sizeof(uint32_t); + public: - SnapshotOffset* bailoutTable() { - return (SnapshotOffset*)&bottomBuffer()[bailoutTable_]; - } + // + // Table of constants referenced in snapshots. (JS::Value alignment) + // PreBarrieredValue* constants() { // Nursery constants are manually barriered in CodeGenerator::link() so a // post barrier is not required.. - return (PreBarrieredValue*)&bottomBuffer()[constantTable_]; + return offsetToPointer<PreBarrieredValue>(constantTableOffset()); + } + size_t numConstants() const { + return (runtimeDataOffset() - constantTableOffset()) / + sizeof(PreBarrieredValue); + } + + // + // IonIC data structures. (uint64_t alignment) + // + uint8_t* runtimeData() { + return offsetToPointer<uint8_t>(runtimeDataOffset()); + } + size_t runtimeSize() const { + return (osiIndexOffset() - runtimeDataOffset()) / sizeof(uint8_t); + } + + // + // Map OSI-point displacement to snapshot. + // + OsiIndex* osiIndices() { return offsetToPointer<OsiIndex>(osiIndexOffset()); } + const OsiIndex* osiIndices() const { + return offsetToPointer<OsiIndex>(osiIndexOffset()); + } + size_t numOsiIndices() const { + return (safepointIndexOffset() - osiIndexOffset()) / SizeOf_OsiIndex; + } + + // + // Map code displacement to safepoint / OSI-patch-delta. + // + SafepointIndex* safepointIndices() { + return offsetToPointer<SafepointIndex>(safepointIndexOffset()); } const SafepointIndex* safepointIndices() const { - return const_cast<IonScript*>(this)->safepointIndices(); + return offsetToPointer<SafepointIndex>(safepointIndexOffset()); + } + size_t numSafepointIndices() const { + return (bailoutTableOffset() - safepointIndexOffset()) / + SizeOf_SafepointIndex; } - SafepointIndex* safepointIndices() { - return (SafepointIndex*)&bottomBuffer()[safepointIndexOffset_]; + + // + // Table mapping bailout IDs to snapshot offsets. + // + SnapshotOffset* bailoutTable() { + return offsetToPointer<SnapshotOffset>(bailoutTableOffset()); + } + size_t numBailoutEntries() const { + return (icIndexOffset() - bailoutTableOffset()) / SizeOf_SnapshotOffset; + } + + // + // Offset into `runtimeData` for each (variable-length) IonIC. + // + uint32_t* icIndex() { return offsetToPointer<uint32_t>(icIndexOffset()); } + size_t numICs() const { + return (safepointsOffset() - icIndexOffset()) / sizeof(uint32_t); } - const OsiIndex* osiIndices() const { - return const_cast<IonScript*>(this)->osiIndices(); + + // + // Safepoint table as a CompactBuffer. + // + const uint8_t* safepoints() const { + return offsetToPointer<uint8_t>(safepointsOffset()); + } + size_t safepointsSize() const { + return (snapshotsOffset() - safepointsOffset()) / sizeof(uint8_t); + } + + // + // Snapshot and RValueAllocation tables as CompactBuffers. + // + const uint8_t* snapshots() const { + return offsetToPointer<uint8_t>(snapshotsOffset()); } - OsiIndex* osiIndices() { return (OsiIndex*)&bottomBuffer()[osiIndexOffset_]; } - uint32_t* icIndex() { return (uint32_t*)&bottomBuffer()[icIndex_]; } - uint8_t* runtimeData() { return &bottomBuffer()[runtimeData_]; } + size_t snapshotsListSize() const { + return (rvaTableOffset() - snapshotsOffset()) / sizeof(uint8_t); + } + size_t snapshotsRVATableSize() const { + return (recoversOffset() - rvaTableOffset()) / sizeof(uint8_t); + } + + // + // Recover instruction table as a CompactBuffer. + // + const uint8_t* recovers() const { + return offsetToPointer<uint8_t>(recoversOffset()); + } + size_t recoversSize() const { + return (endOffset() - recoversOffset()) / sizeof(uint8_t); + } private: IonScript(IonCompilationId compilationId, uint32_t frameSlots, uint32_t argumentSlots, uint32_t frameSize, OptimizationLevel optimizationLevel); public: static IonScript* New(JSContext* cx, IonCompilationId compilationId, @@ -391,63 +463,47 @@ struct alignas(8) IonScript final : publ } bool hasProfilingInstrumentation() const { return hasProfilingInstrumentation_; } MOZ_MUST_USE bool addTraceLoggerEvent(TraceLoggerEvent& event) { MOZ_ASSERT(event.hasTextId()); return traceLoggerEvents_.append(std::move(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_); + MOZ_ASSERT(bailoutId < numBailoutEntries()); 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; IonIC& getICFromIndex(uint32_t index) { - MOZ_ASSERT(index < icEntries_); + MOZ_ASSERT(index < numICs()); uint32_t offset = icIndex()[index]; return getIC(offset); } inline IonIC& getIC(uint32_t offset) { - MOZ_ASSERT(offset < runtimeSize_); - return *(IonIC*)&runtimeData()[offset]; + MOZ_ASSERT(offset < runtimeSize()); + return *reinterpret_cast<IonIC*>(runtimeData() + offset); } - size_t numICs() const { return icEntries_; } - size_t runtimeSize() const { return runtimeSize_; } void purgeICs(Zone* zone); void copySnapshots(const SnapshotWriter* writer); void copyRecovers(const RecoverWriter* writer); void copyBailoutTable(const SnapshotOffset* table); void copyConstants(const Value* vp); void copySafepointIndices(const CodegenSafepointIndex* firstSafepointIndex); void copyOsiIndices(const OsiIndex* firstOsiIndex); void copyRuntimeData(const uint8_t* data);