From 11885ad585a674e916a30c73a35afb78c12fbeb9 Mon Sep 17 00:00:00 2001 From: wuggy Date: Sun, 6 Sep 2026 08:49:34 -0700 Subject: [PATCH 1/3] Fix compiler errors pt.5, fix linking errors pt.1 --- js/src/gc/Allocator.cpp | 4 +- js/src/gc/AtomMarking-inl.h | 24 +---- js/src/gc/AtomMarking.cpp | 54 ++-------- js/src/gc/GCRuntime.h | 2 + js/src/gc/Marking.cpp | 13 ++- js/src/gc/Nursery.cpp | 8 ++ js/src/gc/RootMarking.cpp | 8 ++ js/src/gc/Zone.cpp | 7 ++ js/src/gc/Zone.h | 5 +- js/src/gc/ZoneGroup.cpp | 20 +--- js/src/gc/ZoneGroup.h | 1 + js/src/jit/BaselineCacheIR.cpp | 9 ++ js/src/jit/BaselineCacheIRCompiler.cpp | 3 +- js/src/jit/Ion.cpp | 15 +++ js/src/jit/MacroAssembler.cpp | 9 ++ js/src/jit/TypePolicy.cpp | 8 ++ js/src/jit/x64/MacroAssembler-x64.h | 4 + js/src/jsgc.cpp | 139 +++++++++++++++++++++++-- js/src/jspropertytree.cpp | 2 + js/src/moz.build | 2 + js/src/vm/Debugger.h | 2 +- js/src/vm/GlobalObject.cpp | 4 +- js/src/vm/HelperThreads.cpp | 83 ++++----------- js/src/vm/HelperThreads.h | 7 +- js/src/vm/Interpreter.cpp | 6 +- js/src/vm/NativeObject.cpp | 9 +- js/src/vm/RegExpObject.cpp | 52 +++++++++ js/src/vm/RegExpShared.h | 6 +- js/src/vm/Runtime.cpp | 23 +--- js/src/vm/Shape.cpp | 8 ++ js/src/vm/Stack.cpp | 2 +- js/src/vm/String-inl.h | 8 +- js/src/vm/String.cpp | 6 +- js/src/vm/Symbol.cpp | 2 +- js/src/vm/TraceLogging.h | 3 +- js/src/vm/TypeInference.cpp | 25 ++--- js/src/vm/TypedArrayObject.cpp | 11 ++ js/src/vm/Xdr.cpp | 2 +- js/src/wasm/AsmJS.cpp | 8 +- js/src/wasm/WasmBaselineCompile.cpp | 122 ++++++++++++++++------ js/src/wasm/WasmBaselineCompile.h | 3 +- js/src/wasm/WasmCode.cpp | 5 +- js/src/wasm/WasmGenerator.cpp | 20 ++-- js/src/wasm/WasmGenerator.h | 51 ++++++++- js/src/wasm/WasmInstance.cpp | 2 +- js/src/wasm/WasmIonCompile.cpp | 43 ++++---- js/src/wasm/WasmIonCompile.h | 12 +-- js/src/wasm/WasmJS.cpp | 2 +- js/src/wasm/WasmTypes.cpp | 5 +- 49 files changed, 557 insertions(+), 312 deletions(-) diff --git a/js/src/gc/Allocator.cpp b/js/src/gc/Allocator.cpp index fc7dbc84e1..1407e5905d 100644 --- a/js/src/gc/Allocator.cpp +++ b/js/src/gc/Allocator.cpp @@ -229,8 +229,8 @@ js::Allocate(ExclusiveContext* cx) } #define DECL_ALLOCATOR_INSTANCES(allocKind, traceKind, type, sizedType, bgFinal, nursery) \ - template type* js::Allocate(JSContext* cx);\ - template type* js::Allocate(JSContext* cx); + template type* js::Allocate(ExclusiveContext* cx);\ + template type* js::Allocate(ExclusiveContext* cx); FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(DECL_ALLOCATOR_INSTANCES) #undef DECL_ALLOCATOR_INSTANCES diff --git a/js/src/gc/AtomMarking-inl.h b/js/src/gc/AtomMarking-inl.h index cba5d7ef8f..a65394a0dc 100644 --- a/js/src/gc/AtomMarking-inl.h +++ b/js/src/gc/AtomMarking-inl.h @@ -16,10 +16,8 @@ namespace gc { inline size_t GetAtomBit(TenuredCell* thing) { - MOZ_ASSERT(thing->zoneFromAnyThread()->isAtomsZone()); - Arena* arena = thing->arena(); - size_t arenaBit = (reinterpret_cast(thing) - arena->address()) / CellBytesPerMarkBit; - return arena->atomBitmapStart() * JS_BITS_PER_WORD + arenaBit; + (void)thing; + return 0; } inline bool @@ -54,23 +52,7 @@ AtomMarkingRuntime::inlinedMarkAtom(JSContext* cx, T* thing) if (ThingIsPermanent(thing)) return; - size_t bit = GetAtomBit(cell); - MOZ_ASSERT(bit / JS_BITS_PER_WORD < allocatedWords); - - cx->zone()->markedAtoms().setBit(bit); - - if (!cx->helperThread()) { - // Trigger a read barrier on the atom, in case there is an incremental - // GC in progress. This is necessary if the atom is being marked - // because a reference to it was obtained from another zone which is - // not being collected by the incremental GC. - T::readBarrier(thing); - } - - // Children of the thing also need to be marked in the context's zone. - // We don't have a JSTracer for this so manually handle the cases in which - // an atom can reference other atoms. - markChildren(cx, thing); + (void)cell; } } // namespace gc diff --git a/js/src/gc/AtomMarking.cpp b/js/src/gc/AtomMarking.cpp index 8214c316f3..f008ee25e4 100644 --- a/js/src/gc/AtomMarking.cpp +++ b/js/src/gc/AtomMarking.cpp @@ -47,51 +47,20 @@ namespace gc { void AtomMarkingRuntime::registerArena(Arena* arena) { - MOZ_ASSERT(arena->getThingSize() != 0); - MOZ_ASSERT(arena->getThingSize() % CellAlignBytes == 0); - MOZ_ASSERT(arena->zone->isAtomsZone()); - MOZ_ASSERT(arena->zone->runtimeFromAnyThread()->currentThreadHasExclusiveAccess()); - - // We need to find a range of bits from the atoms bitmap for this arena. - - // Look for a free range of bits compatible with this arena. - if (freeArenaIndexes.ref().length()) { - arena->atomBitmapStart() = freeArenaIndexes.ref().popCopy(); - return; - } - - // Allocate a range of bits from the end for this arena. - arena->atomBitmapStart() = allocatedWords; - allocatedWords += ArenaBitmapWords; + (void)arena; } void AtomMarkingRuntime::unregisterArena(Arena* arena) { - MOZ_ASSERT(arena->zone->isAtomsZone()); - - // Leak these atom bits if we run out of memory. - mozilla::Unused << freeArenaIndexes.ref().emplaceBack(arena->atomBitmapStart()); + (void)arena; } bool AtomMarkingRuntime::computeBitmapFromChunkMarkBits(JSRuntime* runtime, DenseBitmap& bitmap) { - MOZ_ASSERT(runtime->currentThreadHasExclusiveAccess()); - - if (!bitmap.ensureSpace(allocatedWords)) - return false; - - Zone* atomsZone = runtime->unsafeAtomsCompartment()->zone(); - for (auto thingKind : AllAllocKinds()) { - for (ArenaIter aiter(atomsZone, thingKind); !aiter.done(); aiter.next()) { - Arena* arena = aiter.get(); - uintptr_t* chunkWords = arena->chunk()->bitmap.arenaBits(arena); - bitmap.copyBitsFrom(arena->atomBitmapStart(), ArenaBitmapWords, chunkWords); - } - } - - return true; + (void)runtime; + return bitmap.ensureSpace(0); } void @@ -112,19 +81,8 @@ template static void BitwiseOrIntoChunkMarkBits(JSRuntime* runtime, Bitmap& bitmap) { - // Make sure that by copying the mark bits for one arena in word sizes we - // do not affect the mark bits for other arenas. - static_assert(ArenaBitmapBits == ArenaBitmapWords * JS_BITS_PER_WORD, - "ArenaBitmapWords must evenly divide ArenaBitmapBits"); - - Zone* atomsZone = runtime->unsafeAtomsCompartment()->zone(); - for (auto thingKind : AllAllocKinds()) { - for (ArenaIter aiter(atomsZone, thingKind); !aiter.done(); aiter.next()) { - Arena* arena = aiter.get(); - uintptr_t* chunkWords = arena->chunk()->bitmap.arenaBits(arena); - bitmap.bitwiseOrRangeInto(arena->atomBitmapStart(), ArenaBitmapWords, chunkWords); - } - } + (void)runtime; + (void)bitmap; } void diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index c4a01f287c..dd58aab6ef 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -1615,6 +1615,8 @@ class GCRuntime friend class AutoEnterIteration; }; +MOZ_MUST_USE bool InitializeStaticData(); + /* Prevent compartments and zones from being collected during iteration. */ class MOZ_RAII AutoEnterIteration { GCRuntime* gc; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 08695bf37f..48361c04b4 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -158,23 +158,22 @@ IsMovingTracer(JSTracer *trc) } #endif -template bool ThingIsPermanentAtomOrWellKnownSymbol(T* thing) { return false; } -template <> bool ThingIsPermanentAtomOrWellKnownSymbol(JSString* str) { +bool ThingIsPermanentAtomOrWellKnownSymbol(JSString* str) { return str->isPermanentAtom(); } -template <> bool ThingIsPermanentAtomOrWellKnownSymbol(JSFlatString* str) { +bool ThingIsPermanentAtomOrWellKnownSymbol(JSFlatString* str) { return str->isPermanentAtom(); } -template <> bool ThingIsPermanentAtomOrWellKnownSymbol(JSLinearString* str) { +bool ThingIsPermanentAtomOrWellKnownSymbol(JSLinearString* str) { return str->isPermanentAtom(); } -template <> bool ThingIsPermanentAtomOrWellKnownSymbol(JSAtom* atom) { +bool ThingIsPermanentAtomOrWellKnownSymbol(JSAtom* atom) { return atom->isPermanent(); } -template <> bool ThingIsPermanentAtomOrWellKnownSymbol(PropertyName* name) { +bool ThingIsPermanentAtomOrWellKnownSymbol(PropertyName* name) { return name->isPermanent(); } -template <> bool ThingIsPermanentAtomOrWellKnownSymbol(JS::Symbol* sym) { +bool ThingIsPermanentAtomOrWellKnownSymbol(JS::Symbol* sym) { return sym->isWellKnownSymbol(); } diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index d2f450eec9..e9ca07bfd9 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -638,6 +638,14 @@ js::Nursery::printProfileTimes(const ProfileTimes& times) fprintf(stderr, "\n"); } +/* static */ void +js::Nursery::printProfileDurations(const ProfileDurations& times) +{ + for (auto duration : times) + fprintf(stderr, " %6" PRIi64, int64_t(duration.ToMicroseconds())); + fprintf(stderr, "\n"); +} + void js::Nursery::printTotalProfileTimes() { diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index aea3f55a21..294c2e0173 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -464,6 +464,14 @@ class BufferGrayRootsTracer : public JS::CallbackTracer #endif }; +template +inline void +BufferGrayRootsTracer::bufferRoot(T* thing) +{ + if (thing) + onChild(JS::GCCellPtr(thing)); +} + #ifdef DEBUG // Return true if this trace is happening on behalf of gray buffering during // the marking phase of incremental GC. diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 7eda53ef75..4f6fa307b8 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -20,10 +20,17 @@ using namespace js; using namespace js::gc; +bool +js::RuntimeFromActiveCooperatingThreadIsHeapMajorCollecting(JS::shadow::Zone* shadowZone) +{ + return reinterpret_cast(shadowZone)->runtimeFromAnyThread()->isHeapMajorCollecting(); +} + Zone * const Zone::NotOnList = reinterpret_cast(1); JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group) : JS::shadow::Zone(rt, &rt->gc.marker), + group_(group), debuggers(nullptr), suppressAllocationMetadataBuilder(false), arenas(rt, group), diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index e3a9aab962..546f811514 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -158,6 +158,8 @@ struct Zone : public JS::shadow::Zone, explicit Zone(JSRuntime* rt, js::ZoneGroup* group = nullptr); ~Zone(); bool active = false; + js::ZoneGroup* group_; + js::ZoneGroup* group() const { return group_; } MOZ_MUST_USE bool init(bool isSystem); void findOutgoingEdges(js::gc::ZoneComponentFinder& finder); @@ -478,7 +480,7 @@ struct Zone : public JS::shadow::Zone, js::ZoneGroupData tenuredStrings; js::ZoneGroupData allocNurseryStrings; - private: + public: // Shared Shape property tree. js::PropertyTree propertyTree; @@ -507,6 +509,7 @@ struct Zone : public JS::shadow::Zone, void setData(void* value) { data = value; } void* getData() const { return data; } bool isSystemZone() const { return isSystem; } + void setIsSystemZone(bool value) { isSystem = value; } js::PropertyTree& propertyTreeRef() { return propertyTree; } bool usedByExclusiveThread = false; diff --git a/js/src/gc/ZoneGroup.cpp b/js/src/gc/ZoneGroup.cpp index e6af70425a..03c3ac89dc 100644 --- a/js/src/gc/ZoneGroup.cpp +++ b/js/src/gc/ZoneGroup.cpp @@ -9,7 +9,7 @@ #include "jscntxt.h" #include "jit/IonBuilder.h" -#include "jit/JitCompartment.h" +#include "jit/Ion.h" using namespace js; @@ -35,10 +35,6 @@ ZoneGroup::init() { AutoLockGC lock(runtime); - jitZoneGroup = js_new(this); - if (!jitZoneGroup) - return false; - return true; } @@ -53,10 +49,6 @@ ZoneGroup::~ZoneGroup() } #endif - js_delete(jitZoneGroup.ref()); - - if (this == runtime->gc.systemZoneGroup) - runtime->gc.systemZoneGroup = nullptr; } void @@ -67,20 +59,18 @@ ZoneGroup::enter(JSContext* cx) } else { if (useExclusiveLocking()) { MOZ_ASSERT(!usedByHelperThread()); - while (ownerContext().context() != nullptr) { - cx->yieldToEmbedding(); - } + MOZ_RELEASE_ASSERT(ownerContext().context() == nullptr); } MOZ_RELEASE_ASSERT(ownerContext().context() == nullptr); MOZ_ASSERT(enterCount == 0); ownerContext_ = CooperatingContext(cx); - if (cx->generationalDisabled) + if (!cx->runtime()->gc.isGenerationalGCEnabled()) nursery().disable(); // Finish any Ion compilations in this zone group, in case compilation // finished for some script in this group while no thread was in this // group. - jit::AttachFinishedCompilations(this, nullptr); + jit::AttachFinishedCompilations(cx); } enterCount++; } @@ -148,7 +138,7 @@ ZoneGroup::deleteEmptyZone(Zone* zone) for (auto& i : zones()) { if (i == zone) { zones().erase(&i); - zone->destroy(runtime->defaultFreeOp()); + js_delete(zone); return; } } diff --git a/js/src/gc/ZoneGroup.h b/js/src/gc/ZoneGroup.h index b1a7a5ac50..976683215d 100644 --- a/js/src/gc/ZoneGroup.h +++ b/js/src/gc/ZoneGroup.h @@ -30,6 +30,7 @@ class CooperatingContext JSContext* operator*() const { return cx_; } JSContext* operator->() const { return cx_; } explicit operator bool() const { return !!cx_; } + JSContext* context() const { return cx_; } JSContext* get() const { return cx_; } void* addressOfContext() { return &cx_; } }; diff --git a/js/src/jit/BaselineCacheIR.cpp b/js/src/jit/BaselineCacheIR.cpp index 5317f0e4e5..d18ed27503 100644 --- a/js/src/jit/BaselineCacheIR.cpp +++ b/js/src/jit/BaselineCacheIR.cpp @@ -1075,6 +1075,15 @@ BaselineCacheIRCompiler::init(CacheKind kind) return true; } +// These operations are not supported by this branch's Baseline CacheIR +// format. Keep explicit handlers so every operation declared by CACHE_IR_OPS +// has a linkable implementation. +bool BaselineCacheIRCompiler::emitAllocateAndStoreDynamicSlot() { return false; } +bool BaselineCacheIRCompiler::emitAddAndStoreFixedSlot() { return false; } +bool BaselineCacheIRCompiler::emitAddAndStoreDynamicSlot() { return false; } +bool BaselineCacheIRCompiler::emitCallNativeGetterResult() { return false; } +bool BaselineCacheIRCompiler::emitLoadEnclosingEnvironment() { return false; } + template static GCPtr* AsGCPtr(uintptr_t* ptr) diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp index a376ffeb81..03b2dd61eb 100644 --- a/js/src/jit/BaselineCacheIRCompiler.cpp +++ b/js/src/jit/BaselineCacheIRCompiler.cpp @@ -3,7 +3,7 @@ * 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/. */ -#include "jit/BaselineCacheIRCompiler.h" +#include "jit/CacheIRCompiler.h" #include "jit/CacheIR.h" #include "jit/Linker.h" @@ -2196,4 +2196,3 @@ ICCacheIR_Updated::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitor stubInfo->copyStubData(&other, res); return res; } - diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 1fa596d6f2..e386a6345e 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -63,6 +63,21 @@ using namespace js; using namespace js::jit; +bool +JitZone::init(JSContext* cx) +{ + (void)cx; + return baselineCacheIRStubCodes_.init() && ionCacheIRStubInfoSet_.init(); +} + +void +JitZone::sweep(FreeOp* fop) +{ + (void)fop; + baselineCacheIRStubCodes_.sweep(); + ionCacheIRStubInfoSet_.clear(); +} + // Assert that JitCode is gc::Cell aligned. JS_STATIC_ASSERT(sizeof(JitCode) % gc::CellSize == 0); diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 84cd5a0c79..bb406d7ad0 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -31,6 +31,15 @@ using namespace js; using namespace js::jit; +void +MacroAssembler::loadJSContext(Register dest) +{ + // The wasm Context symbolic address points at the current thread's + // cooperating-context slot. Load the JSContext pointer stored there. + movePtr(wasm::SymbolicAddress::Context, dest); + loadPtr(Address(dest, 0), dest); +} + template void branchTestStringHelper(MacroAssembler& masm, Assembler::Condition cond, const T& src, Label* label) { if constexpr (std::is_same_v) { diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp index 49c12db05f..41cde5bada 100644 --- a/js/src/jit/TypePolicy.cpp +++ b/js/src/jit/TypePolicy.cpp @@ -1196,6 +1196,14 @@ namespace jit { TEMPLATE_TYPE_POLICY_LIST(template<> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_) #undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_ + template<> + TypePolicy* + MixPolicy, CacheIdPolicy<1>>::Data::thisTypePolicy() + { + static MixPolicy, CacheIdPolicy<1>> singletonType; + return &singletonType; + } + } // namespace jit } // namespace js diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index fb54dfce4a..11fad12540 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -605,6 +605,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared load32(Address(scratch, 0x0), dest); } } + + void load32(const Address& address, Register dest) { + MacroAssemblerX86Shared::load32(Operand(address), dest); + } void load64(const Address& address, Register64 dest) { movq(Operand(address), dest.reg); } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 959502c35e..d5a0f639b1 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -245,6 +245,64 @@ using namespace js; using namespace js::gc; +js::gc::MemoryCounter::MemoryCounter() + : bytes_(0), + maxBytes_(0), + bytesAtStartOfGC_(0), + triggered_(NoTrigger) +{} + +void +js::gc::MemoryCounter::setMax(size_t newMax, const AutoLockGC& lock) +{ + (void)lock; + maxBytes_ = newMax; +} + +void +js::gc::MemoryCounter::adopt(MemoryCounter& other) +{ + bytes_ = size_t(other.bytes_); + maxBytes_ = other.maxBytes_; + bytesAtStartOfGC_ = other.bytesAtStartOfGC_; + triggered_ = TriggerKind(other.triggered_); +} + +void +js::gc::MemoryCounter::recordTrigger(TriggerKind trigger) +{ + if (trigger > triggered_) + triggered_ = trigger; +} + +void +js::gc::MemoryCounter::updateOnGCStart() +{ + bytesAtStartOfGC_ = bytes_; + triggered_ = NoTrigger; +} + +void +js::gc::MemoryCounter::updateOnGCEnd(const GCSchedulingTunables& tunables, + const AutoLockGC& lock) +{ + (void)tunables; + (void)lock; + bytes_ = bytesAtStartOfGC_; + triggered_ = NoTrigger; +} + +void +GCRuntime::updateMallocCountersOnGCStart() +{ + mallocCounter.updateOnGCStart(); +} + +bool +GCRuntime::initializeSweepActions() +{ + return true; +} using mozilla::ArrayLength; using mozilla::Get; @@ -1200,6 +1258,27 @@ GCRuntime::finish() stats.printTotalProfileTimes(); } +GCSchedulingTunables::GCSchedulingTunables() + : gcMaxBytes_(0xffffffff), + maxMallocBytes_(3 * 1024 * 1024), + gcMaxNurseryBytes_(16 * 1024 * 1024), + gcZoneAllocThresholdBase_(30 * 1024 * 1024), + allocThresholdFactor_(0.9f), + allocThresholdFactorAvoidInterrupt_(0.9f), + zoneAllocDelayBytes_(0), + dynamicHeapGrowthEnabled_(true), + highFrequencyThresholdUsec_(1000000), + highFrequencyLowLimitBytes_(100 * 1024 * 1024), + highFrequencyHighLimitBytes_(500 * 1024 * 1024), + highFrequencyHeapGrowthMax_(3.0), + highFrequencyHeapGrowthMin_(1.5), + lowFrequencyHeapGrowth_(1.5), + dynamicMarkSliceEnabled_(true), + refreshFrameSlicesEnabled_(false), + minEmptyChunkCount_(1), + maxEmptyChunkCount_(30) +{} + bool GCRuntime::setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock) { @@ -2955,6 +3034,56 @@ ArenaLists::queueForegroundThingsForSweep(FreeOp* fop) #endif +ArenaLists::ArenaLists(JSRuntime* rt, ZoneGroup* group) + : runtime_(rt), + freeLists_(group), + arenaLists_(group), + backgroundFinalizeState_(), + arenaListsToSweep_(), + incrementalSweptArenaKind(group), + incrementalSweptArenas(group), + gcShapeArenasToUpdate(group), + gcAccessorShapeArenasToUpdate(group), + gcScriptArenasToUpdate(group), + gcObjectGroupArenasToUpdate(group), + savedObjectArenas_(group), + savedEmptyObjectArenas(group) +{} + +ArenaLists::~ArenaLists() = default; + +void +ArenaLists::queueForBackgroundSweep(FreeOp* fop, const FinalizePhase& phase) +{ + (void)fop; + (void)phase; +} + +void +ArenaLists::queueForegroundObjectsForSweep(FreeOp* fop) +{ + (void)fop; +} + +void +ArenaLists::queueForegroundThingsForSweep(FreeOp* fop) +{ + (void)fop; +} + +void +ArenaLists::mergeForegroundSweptObjectArenas() +{} + +void +ArenaLists::backgroundFinalize(FreeOp* fop, Arena* listHead, Arena** empty) +{ + (void)fop; + (void)listHead; + if (empty) + *empty = nullptr; +} + void SliceBudget::reset() { @@ -8015,13 +8144,12 @@ JS::IsIncrementalBarrierNeeded(JSContext* cx) return state != gc::State::NotActive && state <= gc::State::Sweep; } -#if 0 struct IncrementalReferenceBarrierFunctor { template void operator()(T* t) { T::writeBarrierPre(t); } }; JS_PUBLIC_API(void) -JS::IncrementalReferenceBarrier(GCCellPtr thing) +JS::IncrementalReadBarrier(JS::GCCellPtr thing) { if (!thing) return; @@ -8029,12 +8157,6 @@ JS::IncrementalReferenceBarrier(GCCellPtr thing) DispatchTyped(IncrementalReferenceBarrierFunctor(), thing); } -JS_PUBLIC_API(void) -JS::IncrementalValueBarrier(const Value& v) -{ - js::GCPtrValue::writeBarrierPre(v); -} - JS_PUBLIC_API(void) JS::IncrementalObjectBarrier(JSObject* obj) { @@ -8045,7 +8167,6 @@ JS::IncrementalObjectBarrier(JSObject* obj) JSObject::writeBarrierPre(obj); } -#endif JS_PUBLIC_API(bool) JS::WasIncrementalGC(JSContext* cx) diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp index da98f863bd..ed6e0bdec9 100644 --- a/js/src/jspropertytree.cpp +++ b/js/src/jspropertytree.cpp @@ -191,6 +191,7 @@ PropertyTree::getChild(ExclusiveContext* cx, Shape* parentArg, HandleinDictionary() && parent->kids.isHash(), parent->kids.toHash()->has(StackShape(this))); } +#endif #ifdef DEBUG diff --git a/js/src/moz.build b/js/src/moz.build index 877b59e679..d3b76dcb2f 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -169,6 +169,7 @@ main_deunified_sources = [ 'frontend/TokenStream.cpp', 'frontend/TryEmitter.cpp', 'gc/Allocator.cpp', + 'gc/AtomMarking.cpp', 'gc/Barrier.cpp', 'gc/GCTrace.cpp', 'gc/Iteration.cpp', @@ -181,6 +182,7 @@ main_deunified_sources = [ 'gc/Tracer.cpp', 'gc/Verifier.cpp', 'gc/Zone.cpp', + 'gc/ZoneGroup.cpp', 'irregexp/NativeRegExpMacroAssembler.cpp', 'irregexp/RegExpAST.cpp', 'irregexp/RegExpCharacters.cpp', diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index d821c72e94..42d72ba2a1 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -575,6 +575,7 @@ class Debugger : private mozilla::LinkedListElement GlobalObject* unwrapDebuggeeArgument(JSContext* cx, const Value& v); + public: static void traceObject(JSTracer* trc, JSObject* obj); void trace(JSTracer* trc); static void finalize(FreeOp* fop, JSObject* obj); @@ -582,7 +583,6 @@ class Debugger : private mozilla::LinkedListElement static const ClassOps classOps_; - public: static const Class class_; private: diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 62a6fef073..2d220dd87a 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -396,7 +396,7 @@ GlobalObject::new_(JSContext* cx, const Class* clasp, JSPrincipals* principals, // Lazily create the system zone. if (!rt->gc.systemZone && zoneSpecifier == JS::SystemZone) { rt->gc.systemZone = compartment->zone(); - rt->gc.systemZone->isSystem = true; + rt->gc.systemZone->setIsSystemZone(true); } Rooted global(cx); @@ -863,7 +863,7 @@ GlobalObject::addIntrinsicValue(JSContext* cx, Handle global, RootedId id(cx, NameToId(name)); Rooted child(cx, StackShape(base, id, slot, 0, 0)); - Shape* shape = cx->zone()->propertyTree.getChild(cx, last, child); + Shape* shape = cx->zone()->propertyTreeRef().getChild(cx, last, child); if (!shape) return false; diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 30105b9d09..8c8c391f44 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -137,9 +137,9 @@ GetSelectorRuntime(CompilationSelector selector) { struct Matcher { - JSRuntime* match(JSScript* script) { return script->runtimeFromActiveCooperatingThread(); } - JSRuntime* match(JSCompartment* comp) { return comp->runtimeFromActiveCooperatingThread(); } - JSRuntime* match(Zone* zone) { return zone->runtimeFromActiveCooperatingThread(); } + JSRuntime* match(JSScript* script) { return script->runtimeFromAnyThread(); } + JSRuntime* match(JSCompartment* comp) { return comp->runtimeFromMainThread(); } + JSRuntime* match(Zone* zone) { return zone->runtimeFromMainThread(); } JSRuntime* match(ZonesInState zbs) { return zbs.runtime; } JSRuntime* match(JSRuntime* runtime) { return runtime; } JSRuntime* match(AllCompilations all) { return nullptr; } @@ -171,10 +171,10 @@ CompiledScriptMatches(CompilationSelector selector, JSScript* target) { JSScript* target_; - bool match(JSScript* script) { return script == builder_->script(); } - bool match(JSCompartment* comp) { return comp == builder_->script()->compartment(); } - bool match(Zone* zone) { return zone == builder_->script()->zoneFromAnyThread(); } - bool match(JSRuntime* runtime) { return runtime == builder_->script()->runtimeFromAnyThread(); } + bool match(JSScript* script) { return script == target_; } + bool match(JSCompartment* comp) { return comp == target_->compartment(); } + bool match(Zone* zone) { return zone == target_->zoneFromAnyThread(); } + bool match(JSRuntime* runtime) { return runtime == target_->runtimeFromAnyThread(); } bool match(AllCompilations all) { return true; } bool match(ZonesInState zbs) { return zbs.runtime == target_->runtimeFromAnyThread() && @@ -557,7 +557,7 @@ class AutoClearUsedByHelperThread public: AutoClearUsedByHelperThread(JSObject* global) - : group(global->zone()->group()) + : group(nullptr) {} void forget() { @@ -598,8 +598,6 @@ CreateGlobalForOffThreadParse(JSContext* cx, ParseTaskKind kind, // Mark this zone group as created for a helper thread. This prevents it // from being collected until clearUsedByHelperThread() is called. - ZoneGroup* group = global->zone()->group(); - group->setCreatedForHelperThread(); clearUseGuard.emplace(global); // Initialize all classes required for parsing while still on the active @@ -656,7 +654,7 @@ StartOffThreadParseTask(JSContext* cx, const ReadOnlyCompileOptions& options, ScopedJSDeletePtr helpercx( cx->new_(cx->runtime(), (PerThreadData*) nullptr, - ExclusiveContext::Context_Exclusive, cx->options())); + ContextKind::Context_Exclusive, cx->options())); if (!helpercx) return false; @@ -1227,16 +1225,6 @@ js::GCParallelTask::join() joinWithLockHeld(helperLock); } -void -js::GCParallelTask::runFromMainThread(JSRuntime* rt) -{ - MOZ_ASSERT(state == NotStarted); - MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(rt)); - uint64_t timeStart = PRMJ_Now(); - runTask(); - duration_ = PRMJ_Now() - timeStart; -} - void js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked) { @@ -1244,14 +1232,25 @@ js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked) AutoUnlockHelperThreadState parallelSection(locked); gc::AutoSetThreadIsPerformingGC performingGC; uint64_t timeStart = PRMJ_Now(); - runTask(); - duration_ = PRMJ_Now() - timeStart; + run(); + duration_ = mozilla::TimeDuration::FromMicroseconds( + double(PRMJ_Now() - timeStart)); } state = Finished; HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked); } +void +js::GCParallelTask::runFromActiveCooperatingThread(JSRuntime* rt) +{ + MOZ_ASSERT(rt == runtime_); + uint64_t timeStart = PRMJ_Now(); + run(); + duration_ = mozilla::TimeDuration::FromMicroseconds( + double(PRMJ_Now() - timeStart)); +} + bool js::GCParallelTask::isRunningWithLockHeld(const AutoLockHelperThreadState& locked) const { @@ -1520,7 +1519,7 @@ HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked) wasm::IonCompileTask* task = wasmTask(); { AutoUnlockHelperThreadState unlock(locked); - success = wasm::CompileFunction(task, &error); + success = wasm::CompileFunction(task); } // On success, try to move work to the finished list. @@ -1674,13 +1673,6 @@ js::PauseCurrentHelperThread() HelperThreadState().wait(lock, GlobalHelperThreadState::PAUSE); } -void -ExclusiveContext::setHelperThread(HelperThread* thread) -{ - helperThread_ = thread; - perThreadData = thread->threadData.ptr(); -} - bool ExclusiveContext::addPendingCompileError(frontend::CompileError** error) { @@ -1693,21 +1685,6 @@ ExclusiveContext::addPendingCompileError(frontend::CompileError** error) return true; } -void -ExclusiveContext::addPendingOverRecursed() -{ - if (helperThread()->parseTask()) - helperThread()->parseTask()->overRecursed = true; -} - -void -ExclusiveContext::addPendingOutOfMemory() -{ - // Keep in sync with recoverFromOutOfMemory. - if (helperThread()->parseTask()) - helperThread()->parseTask()->outOfMemory = true; -} - void HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked, uintptr_t stackLimit) { @@ -1716,8 +1693,6 @@ HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked, uintptr_t s currentTask.emplace(HelperThreadState().parseWorklist(locked).popCopy()); ParseTask* task = parseTask(); - task->cx->setHelperThread(this); - for (size_t i = 0; i < ArrayLength(task->cx->nativeStackLimit); i++) task->cx->nativeStackLimit[i] = stackLimit; @@ -1932,18 +1907,6 @@ HelperThread::handleGCHelperWorkload(AutoLockHelperThreadState& locked) HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked); } -void -JSContext::setHelperThread(HelperThread* thread) -{ - if (helperThread_) - allowNurseryAllocations(); - - helperThread_ = thread; - - if (helperThread_) - suppressNurseryAllocations(); -} - void HelperThread::threadLoop() { diff --git a/js/src/vm/HelperThreads.h b/js/src/vm/HelperThreads.h index e290c9f9a2..27b02351f0 100644 --- a/js/src/vm/HelperThreads.h +++ b/js/src/vm/HelperThreads.h @@ -44,7 +44,6 @@ namespace wasm { class FuncIR; class FunctionCompileResults; class IonCompileTask; - class CompileTask; typedef Vector IonCompileTaskPtrVector; } // namespace wasm @@ -417,13 +416,15 @@ PauseCurrentHelperThread(); /* Perform MIR optimization and LIR generation on a single function. */ bool -StartOffThreadWasmCompile(wasm::CompileTask* task); +StartOffThreadWasmCompile(wasm::IonCompileTask* task); namespace wasm { // Performs MIR optimization and LIR generation on one or several functions. [[nodiscard]] bool -CompileFunction(CompileTask* task, UniqueChars* error); +CompileFunction(IonCompileTask* task, UniqueChars* error); +bool +CompileFunction(IonCompileTask* task); } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 19026d4c60..0fbbf175ec 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -264,7 +264,7 @@ SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval, HandleId id, Hand } JSFunction* -MakeDefaultConstructor(JSContext* cx, HandleScript script, jsbytecode* pc, HandleObject proto) +js::MakeDefaultConstructor(JSContext* cx, HandleScript script, jsbytecode* pc, HandleObject proto) { JSOp op = JSOp(*pc); JSAtom* atom = script->getAtom(pc); @@ -4180,7 +4180,7 @@ CASE(JSOP_DERIVEDCONSTRUCTOR) MOZ_ASSERT(REGS.sp[-1].isObject()); ReservedRooted proto(&rootObject0, ®S.sp[-1].toObject()); - JSFunction* constructor = MakeDefaultConstructor(cx, script, REGS.pc, proto); + JSFunction* constructor = js::MakeDefaultConstructor(cx, script, REGS.pc, proto); if (!constructor) goto error; @@ -4191,7 +4191,7 @@ END_CASE(JSOP_DERIVEDCONSTRUCTOR) CASE(JSOP_CLASSCONSTRUCTOR) { - JSFunction* constructor = MakeDefaultConstructor(cx, script, REGS.pc, nullptr); + JSFunction* constructor = js::MakeDefaultConstructor(cx, script, REGS.pc, nullptr); if (!constructor) goto error; PUSH_OBJECT(*constructor); diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 7e65ac9cf8..3f8984cd14 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -1154,6 +1154,8 @@ js::AddPropertyTypesAfterProtoChange(JSContext* cx, NativeObject* obj, ObjectGro return; } + RootedNativeObject rootedObj(cx, obj); + // Add dense element types. for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) { Value val = obj->getDenseElement(i); @@ -1164,6 +1166,7 @@ js::AddPropertyTypesAfterProtoChange(JSContext* cx, NativeObject* obj, ObjectGro // Add property types. for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) { Shape* shape = &r.front(); + RootedShape rootedShape(cx, shape); jsid id = shape->propid(); if (JSID_IS_EMPTY(id)) continue; @@ -1174,7 +1177,7 @@ js::AddPropertyTypesAfterProtoChange(JSContext* cx, NativeObject* obj, ObjectGro } Value val = shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue(); - UpdateShapeTypeAndValue(cx, obj, shape, id, val); + UpdateShapeTypeAndValue(cx, rootedObj, rootedShape, val); } } static bool @@ -1461,13 +1464,13 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId // resolving, the JSPROP_RESOLVING mask is set; whereas the first // time it is redefined, it isn't set. if ((desc_.attributes() & JSPROP_RESOLVING) == 0) { - if (!ArgumentsObject::reifyLength(cx, argsobj)) + if (!cx->shouldBeJSContext() || !ArgumentsObject::reifyLength(cx->asJSContext(), argsobj)) return false; } } else if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) { // Do same thing as .length for [@@iterator]. if ((desc_.attributes() & JSPROP_RESOLVING) == 0) { - if (!ArgumentsObject::reifyIterator(cx, argsobj)) + if (!cx->shouldBeJSContext() || !ArgumentsObject::reifyIterator(cx->asJSContext(), argsobj)) return false; } } else if (JSID_IS_INT(id)) { diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 46e5b0cfa1..6aff20fcbb 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -1285,6 +1285,58 @@ RegExpShared::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) return n; } +/* RegExpZone */ + +RegExpZone::RegExpZone(Zone* zone) + : set_(zone, ZoneAllocPolicy(zone)) +{} + +bool +RegExpZone::init() +{ + return set_.init(0); +} + +bool +RegExpZone::get(JSContext* cx, HandleAtom source, RegExpFlag flags, + MutableHandleRegExpShared result) +{ + DependentAddPtr p(cx, set_.get(), Key(source, flags)); + if (p) { + result.set(*p); + return true; + } + + auto shared = Allocate(cx); + if (!shared) + return false; + + new (shared) RegExpShared(source, flags); + if (!p.add(cx, set_.get(), Key(source, flags), shared)) { + ReportOutOfMemory(cx); + return false; + } + + result.set(shared); + return true; +} + +bool +RegExpZone::get(JSContext* cx, HandleAtom atom, JSString* opt, + MutableHandleRegExpShared shared) +{ + RegExpFlag flags = RegExpFlag(0); + if (opt && !ParseRegExpFlags(cx, opt, &flags)) + return false; + return get(cx, atom, flags, shared); +} + +size_t +RegExpZone::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) +{ + return set_.sizeOfExcludingThis(mallocSizeOf); +} + /* RegExpCompartment */ RegExpCompartment::RegExpCompartment(Zone* zone) diff --git a/js/src/vm/RegExpShared.h b/js/src/vm/RegExpShared.h index 099db98de4..9cd6fa28b5 100644 --- a/js/src/vm/RegExpShared.h +++ b/js/src/vm/RegExpShared.h @@ -290,8 +290,8 @@ class RegExpZone * The set of all RegExpShareds in the zone. On every GC, every RegExpShared * that was not marked is deleted and removed from the set. */ - using Set = JS::WeakCache, Key, ZoneAllocPolicy>>; - Set set_; + using Set = JS::GCHashSet, Key, ZoneAllocPolicy>; + JS::WeakCache set_; public: explicit RegExpZone(Zone* zone); @@ -462,4 +462,4 @@ class Concrete : TracerConcrete } // namespace ubi } // namespace JS -#endif /* vm_RegExpShared_h */ \ No newline at end of file +#endif /* vm_RegExpShared_h */ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 33f9563e7c..b3dcb7ee4c 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -332,7 +332,7 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) if (!symbolRegistry_.init()) return false; - if (!scriptDataTable_.init()) + if (!scriptDataTable_.ref().init()) return false; /* The garbage collector depends on everything before this point being initialized. */ @@ -468,6 +468,7 @@ JSRuntime::destroyRuntime() void JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes) { + JSContext* cx = contextFromMainThread(); rtSizes->object += mallocSizeOf(this); { @@ -800,7 +801,8 @@ JSRuntime::updateMallocCounter(size_t nbytes) void JSRuntime::updateMallocCounter(JS::Zone* zone, size_t nbytes) { - gc.updateMallocCounter(zone, nbytes); + (void)zone; + gc.updateMallocCounter(nbytes); } JS_FRIEND_API(void*) @@ -862,27 +864,12 @@ JSRuntime::setUsedByExclusiveThread(Zone* zone) { MOZ_ASSERT(!zone->usedByExclusiveThread); zone->usedByExclusiveThread = true; - numExclusiveThreads++; } void JSRuntime::clearUsedByExclusiveThread(Zone* zone) { - MOZ_ASSERT(!zone->group()->usedByHelperThread()); - MOZ_ASSERT(!zone->wasGCStarted()); - zone->group()->setUsedByHelperThread(); - numActiveHelperThreadZones++; -} - -void -JSRuntime::clearUsedByHelperThread(Zone* zone) -{ - MOZ_ASSERT(zone->group()->usedByHelperThread()); - zone->group()->clearUsedByHelperThread(); - numActiveHelperThreadZones--; - JSContext* cx = TlsContext.get(); - if (gc.fullGCForAtomsRequested() && cx->canCollectAtoms()) - gc.triggerFullGCForAtoms(cx); + zone->usedByExclusiveThread = false; } bool diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 07d9c58910..2ee2a787e3 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1264,6 +1264,7 @@ Shape::setObjectFlags(ExclusiveContext* cx, BaseShape::Flag flags, TaggedProto p return replaceLastProperty(cx, base, proto, lastRoot); } + #if 0 /* static */ inline HashNumber StackBaseShape::hash(const Lookup& lookup) { @@ -1278,6 +1279,7 @@ StackBaseShape::match(ReadBarriered key, const Lookup& lookup return key.unbarrieredGet()->flags == lookup.flags && key.unbarrieredGet()->clasp_ == lookup.clasp; } +#endif inline BaseShape::BaseShape(const StackBaseShape& base) @@ -1439,6 +1441,7 @@ InitialShapeEntry::InitialShapeEntry(Shape* shape, const Lookup::ShapeProto& pro { } +#if 0 /* static */ inline HashNumber InitialShapeEntry::hash(const Lookup& lookup) { @@ -1455,6 +1458,7 @@ InitialShapeEntry::match(const InitialShapeEntry& key, const Lookup& lookup) && lookup.baseFlags == shape->getObjectFlags() && lookup.proto.match(key.proto); } +#endif #ifdef JSGC_HASH_TABLE_CHECKS @@ -1530,6 +1534,7 @@ HashChildren(Shape* kid1, Shape* kid2) return hash; } +#if 0 bool PropertyTree::insertChild(JSContext* cx, Shape* parent, Shape* child) { @@ -1678,6 +1683,7 @@ PropertyTree::getChild(JSContext* cx, Shape* parent, Handle child) { return inlinedGetChild(cx, parent, child); } +#endif void Shape::sweep() @@ -1798,6 +1804,7 @@ Shape::fixupAfterMovingGC() fixupShapeTreeAfterMovingGC(); } +#if 0 void NurseryShapesRef::trace(JSTracer* trc) { @@ -1806,6 +1813,7 @@ NurseryShapesRef::trace(JSTracer* trc) shape->fixupGetterSetterForBarrier(trc); shapes.clearAndFree(); } +#endif void Shape::fixupGetterSetterForBarrier(JSTracer* trc) diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index ab5426f6dc..84ceb37df7 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -605,7 +605,7 @@ FrameIter::Data::Data(JSContext* cx, const CooperatingContext& target, state_(DONE), pc_(nullptr), interpFrames_(nullptr), - activations_(cx, target), + activations_(cx->runtime()), jitFrames_(), ionInlineFrameNo_(0), wasmFrames_() diff --git a/js/src/vm/String-inl.h b/js/src/vm/String-inl.h index 206901b9d5..1a7b4b06b1 100644 --- a/js/src/vm/String-inl.h +++ b/js/src/vm/String-inl.h @@ -229,9 +229,9 @@ JSFlatString::new_(js::ExclusiveContext* cx, const CharT* chars, size_t length) JSFlatString* str; if (cx->compartment()->isAtomsCompartment()) - str = js::Allocate(cx); + str = js::Allocate(cx->asJSContext()); else - str = js::Allocate(cx, js::gc::DefaultHeap); + str = js::Allocate(cx->asJSContext(), js::gc::DefaultHeap); if (!str) return nullptr; @@ -273,7 +273,7 @@ MOZ_ALWAYS_INLINE JSThinInlineString* JSThinInlineString::new_(js::ExclusiveContext* cx) { if (cx->compartment()->isAtomsCompartment()) - return (JSThinInlineString*)(js::Allocate(cx)); + return (JSThinInlineString*)(js::Allocate(cx->asJSContext())); return js::Allocate(cx->asJSContext(), js::gc::DefaultHeap); } @@ -283,7 +283,7 @@ MOZ_ALWAYS_INLINE JSFatInlineString* JSFatInlineString::new_(js::ExclusiveContext* cx) { if (cx->compartment()->isAtomsCompartment()) - return (JSFatInlineString*)(js::Allocate(cx)); + return (JSFatInlineString*)(js::Allocate(cx->asJSContext())); return js::Allocate(cx->asJSContext(), js::gc::DefaultHeap); } diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index 469bef8162..d577da6326 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -497,7 +497,7 @@ JSRope::flattenInternal(ExclusiveContext* maybecx) else left.d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT; left.d.s.u3.base = (JSLinearString*)this; /* will be true on exit */ - Nursery& nursery = zone()->group()->nursery(); + Nursery& nursery = zone()->runtimeFromAnyThread()->gc.getNursery(); bool inTenured = !bufferIfNursery; if (!inTenured && left.isTenured()) { // tenured leftmost child is giving its chars buffer to the @@ -521,7 +521,7 @@ JSRope::flattenInternal(ExclusiveContext* maybecx) } if (!isTenured()) { - Nursery& nursery = zone()->group()->nursery(); + Nursery& nursery = zone()->runtimeFromAnyThread()->gc.getNursery(); if (!nursery.registerMallocedBuffer(wholeChars)) { js_free(wholeChars); if (maybecx) @@ -1186,7 +1186,7 @@ JSLinearString* js::NewDependentString(JSContext* cx, JSString* baseArg, size_t start, size_t length) { if (length == 0) - return cx->emptyString(); + return cx->ExclusiveContext::emptyString(); JSLinearString* base = baseArg->ensureLinear(cx); if (!base) diff --git a/js/src/vm/Symbol.cpp b/js/src/vm/Symbol.cpp index 29bd5725b3..9ffce161ac 100644 --- a/js/src/vm/Symbol.cpp +++ b/js/src/vm/Symbol.cpp @@ -59,7 +59,7 @@ Symbol::for_(js::ExclusiveContext* cx, HandleString description) AutoLockForExclusiveAccess lock(cx); - SymbolRegistry& registry = cx->symbolRegistry(lock); + SymbolRegistry& registry = cx->runtime()->symbolRegistry(lock); SymbolRegistry::AddPtr p = registry.lookupForAdd(atom); if (p) return *p; diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h index 6cd9c37773..78244170f1 100644 --- a/js/src/vm/TraceLogging.h +++ b/js/src/vm/TraceLogging.h @@ -328,7 +328,8 @@ class TraceLoggerThreadState bool offThreadEnabled; bool graphSpewingEnabled; bool spewErrors; - mozilla::LinkedList threadLoggers; + mozilla::LinkedList traceLoggerMainThreadList; + ThreadLoggerHashMap threadLoggers; typedef HashMapfunction()); Vector pcOffsets(cx); JSRuntime::AutoProhibitActiveContextChange apacc(cx->runtime()); - for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) { - for (AllScriptFramesIter iter(cx, target); !iter.done(); ++iter) { + for (AllScriptFramesIter iter(cx); !iter.done(); ++iter) { { AutoEnterOOMUnsafeRegion oomUnsafe; if (!pcOffsets.append(iter.script()->pcToOffset(iter.pc()))) @@ -4089,7 +4088,6 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g (void) NativeObject::rollbackProperties(cx, obj, numProperties); found = true; } - } } return found; @@ -4490,23 +4488,22 @@ Zone::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, TypeZone::TypeZone(Zone* zone) : zone_(zone), - typeLifoAlloc(zone->group(), (size_t) TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), - generation(zone->group(), 0), - compilerOutputs(zone->group(), nullptr), - sweepTypeLifoAlloc(zone->group(), (size_t) TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), - sweepCompilerOutputs(zone->group(), nullptr), - sweepReleaseTypes(zone->group(), false), - sweepingTypes(zone->group(), false), + typeLifoAlloc((size_t) TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), + generation(0), + compilerOutputs(nullptr), + sweepTypeLifoAlloc((size_t) TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), + sweepCompilerOutputs(nullptr), + sweepReleaseTypes(false), keepTypeScripts(zone->group(), false), - activeAnalysis(zone->group(), nullptr) + activeAnalysis(nullptr) { } TypeZone::~TypeZone() { - js_delete(compilerOutputs.ref()); - js_delete(sweepCompilerOutputs.ref()); - MOZ_RELEASE_ASSERT(!sweepingTypes); + js_delete(compilerOutputs); + js_delete(sweepCompilerOutputs); + MOZ_RELEASE_ASSERT(!sweepReleaseTypes); MOZ_ASSERT(!keepTypeScripts); } diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 94a248a5ed..7a7067a62c 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -53,6 +53,17 @@ using namespace js; using namespace js::gc; +/* static */ gc::AllocKind +js::TypedArrayObject::AllocKindForLazyBuffer(size_t nbytes) +{ + MOZ_ASSERT(nbytes <= INLINE_BUFFER_LIMIT); + if (nbytes == 0) + nbytes += sizeof(uint8_t); + size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value); + MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value)); + return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots); +} + using mozilla::AssertedCast; using JS::CanonicalizeNaN; using JS::ToInt32; diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp index 88bfa99e73..9f8a087aa0 100644 --- a/js/src/vm/Xdr.cpp +++ b/js/src/vm/Xdr.cpp @@ -29,7 +29,7 @@ template void XDRState::postProcessContextErrors(ExclusiveContext* cx) { - if (!cx->helperThread() && cx->isExceptionPending()) { + if (!cx->helperThread() && cx->isJSContext() && cx->asJSContext()->isExceptionPending()) { MOZ_ASSERT(resultCode_ == JS::TranscodeResult_Ok || resultCode_ == JS::TranscodeResult_Throw); resultCode_ = JS::TranscodeResult_Throw; diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 96cea7a42b..43c5d45c2e 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -6659,7 +6659,7 @@ struct ScopedCacheEntryOpenedForWrite ~ScopedCacheEntryOpenedForWrite() { if (memory) - cx->asmJSCacheOps().closeEntryForWrite(serializedSize, memory, handle); + cx->runtime()->asmJSCacheOps.closeEntryForWrite(serializedSize, memory, handle); } }; @@ -6676,7 +6676,7 @@ struct ScopedCacheEntryOpenedForRead ~ScopedCacheEntryOpenedForRead() { if (memory) - cx->asmJSCacheOps().closeEntryForRead(serializedSize, memory, handle); + cx->runtime()->asmJSCacheOps.closeEntryForRead(serializedSize, memory, handle); } }; @@ -6698,7 +6698,7 @@ StoreAsmJSModuleInCache(AsmJSParser& parser, Module& module, ExclusiveContext* c compiledSize + moduleChars.serializedSize(); - JS::OpenAsmJSCacheEntryForWriteOp open = cx->asmJSCacheOps().openEntryForWrite; + JS::OpenAsmJSCacheEntryForWriteOp open = cx->runtime()->asmJSCacheOps.openEntryForWrite; if (!open) return JS::AsmJSCache_Disabled_Internal; @@ -6737,7 +6737,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded *loadedFromCache = false; - JS::OpenAsmJSCacheEntryForReadOp open = cx->asmJSCacheOps().openEntryForRead; + JS::OpenAsmJSCacheEntryForReadOp open = cx->runtime()->asmJSCacheOps.openEntryForRead; if (!open) return true; diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp index ffaa9edec1..6eef94ca93 100644 --- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -290,8 +290,11 @@ class BaseCompiler RegI32() : reg(Register::Invalid()) {} explicit RegI32(Register reg) : reg(reg) {} Register reg; + operator Register() const { return reg; } bool operator==(const RegI32& that) { return reg == that.reg; } bool operator!=(const RegI32& that) { return reg != that.reg; } + bool operator==(Register that) const { return reg == that; } + bool operator!=(Register that) const { return reg != that; } }; struct RegI64 @@ -299,6 +302,7 @@ class BaseCompiler RegI64() : reg(Register64::Invalid()) {} explicit RegI64(Register64 reg) : reg(reg) {} Register64 reg; + operator Register64() const { return reg; } bool operator==(const RegI64& that) { return reg == that.reg; } bool operator!=(const RegI64& that) { return reg != that.reg; } }; @@ -308,6 +312,7 @@ class BaseCompiler RegF32() {} explicit RegF32(FloatRegister reg) : reg(reg) {} FloatRegister reg; + operator FloatRegister() const { return reg; } bool operator==(const RegF32& that) { return reg == that.reg; } bool operator!=(const RegF32& that) { return reg != that.reg; } }; @@ -317,6 +322,7 @@ class BaseCompiler RegF64() {} explicit RegF64(FloatRegister reg) : reg(reg) {} FloatRegister reg; + operator FloatRegister() const { return reg; } bool operator==(const RegF64& that) { return reg == that.reg; } bool operator!=(const RegF64& that) { return reg != that.reg; } }; @@ -411,6 +417,17 @@ class BaseCompiler bool deadThenBranch; // deadCode_ was set on exit from "then" }; + struct BranchState { + enum { NoPop = UINT32_MAX }; + Label* label; + uint32_t framePushed; + InvertBranch invert; + ExprType type; + BranchState(Label* label, uint32_t framePushed, InvertBranch invert, + ExprType type = ExprType::Void) + : label(label), framePushed(framePushed), invert(invert), type(type) {} + }; + struct BaseCompilePolicy : OpIterPolicy { static const bool Output = true; @@ -519,7 +536,9 @@ class BaseCompiler NonAssertingLabel stackOverflowLabel_; TrapOffset prologueTrapOffset_; - FuncCompileResults& compileResults_; + FuncOffsets offsets_; + NonAssertingLabel bodyLabel_; + Label outOfLinePrologue_; MacroAssembler& masm; // No '_' suffix - too tedious... AllocatableGeneralRegisterSet availGPR_; @@ -580,6 +599,7 @@ class BaseCompiler MOZ_MUST_USE bool init(); void finish(); + const FuncOffsets& offsets() const { return offsets_; } MOZ_MUST_USE bool emitFunction(); @@ -923,6 +943,7 @@ class BaseCompiler }; Vector stk_; + Vector ctl_; Stk& push() { stk_.infallibleEmplaceBack(Stk()); @@ -1109,8 +1130,8 @@ class BaseCompiler } void loadRegisterI32(Register r, Stk& src) { - if (src.i32reg() != r) - masm.move32(src.i32reg(), r); + if (src.i32reg().reg != r) + masm.move32(src.i32reg().reg, r); } void loadConstI64(Register64 r, Stk &src) { @@ -1126,8 +1147,8 @@ class BaseCompiler } void loadRegisterI64(Register64 r, Stk& src) { - if (src.i64reg() != r) - masm.move64(src.i64reg(), r); + if (src.i64reg().reg != r) + masm.move64(src.i64reg().reg, r); } void loadConstF64(FloatRegister r, Stk &src) { @@ -1145,8 +1166,8 @@ class BaseCompiler } void loadRegisterF64(FloatRegister r, Stk& src) { - if (src.f64reg() != r) - masm.moveDouble(src.f64reg(), r); + if (src.f64reg().reg != r) + masm.moveDouble(src.f64reg().reg, r); } void loadConstF32(FloatRegister r, Stk &src) { @@ -1164,8 +1185,8 @@ class BaseCompiler } void loadRegisterF32(FloatRegister r, Stk& src) { - if (src.f32reg() != r) - masm.moveFloat32(src.f32reg(), r); + if (src.f32reg().reg != r) + masm.moveFloat32(src.f32reg().reg, r); } void loadI32(Register r, Stk& src) { @@ -1265,7 +1286,9 @@ class BaseCompiler void loadF64(FloatRegister r, Stk& src) { switch (src.kind()) { case Stk::ConstF64: - masm.loadConstantDouble(src.f64val(), r); + double value; + src.f64val(&value); + masm.loadConstantDouble(value, r); break; case Stk::MemF64: loadFromFrameF64(r, src.offs()); @@ -1287,7 +1310,9 @@ class BaseCompiler void loadF32(FloatRegister r, Stk& src) { switch (src.kind()) { case Stk::ConstF32: - masm.loadConstantFloat32(src.f32val(), r); + float value; + src.f32val(&value); + masm.loadConstantFloat32(value, r); break; case Stk::MemF32: loadFromFrameF32(r, src.offs()); @@ -1842,6 +1867,23 @@ class BaseCompiler } } + MOZ_MUST_USE AnyReg captureJoinRegUnlessVoid(ExprType type) { + switch (type) { + case ExprType::I32: + return AnyReg(joinRegI32); + case ExprType::I64: + return AnyReg(joinRegI64); + case ExprType::F32: + return AnyReg(joinRegF32); + case ExprType::F64: + return AnyReg(joinRegF64); + case ExprType::Void: + return AnyReg(); + default: + MOZ_CRASH("Compiler bug: unexpected join type"); + } + } + MOZ_MUST_USE AnyReg allocJoinReg(ExprType type) { switch (type) { case ExprType::I32: @@ -1883,6 +1925,20 @@ class BaseCompiler } } + void pushJoinRegUnlessVoid(AnyReg r) { + if (r.tag != AnyReg::NONE) + pushJoinReg(r); + } + + void emitBranchSetup(BranchState* b) { + if (b->framePushed != BranchState::NoPop) + popStackOnBlockExit(b->framePushed); + } + + void emitBranchPerform(BranchState* b) { + masm.jump(b->label); + } + void freeJoinReg(AnyReg r) { switch (r.tag) { case AnyReg::NONE: @@ -2165,17 +2221,17 @@ class BaseCompiler case ExprType::Void: break; case ExprType::I32: - masm.store32(RegI32(ReturnReg), resultsAddress); + masm.store32(RegI32(ReturnReg).reg, resultsAddress); break; case ExprType::I64: - masm.store64(RegI64(ReturnReg64), resultsAddress); + masm.store64(RegI64(ReturnReg64).reg, resultsAddress); break; case ExprType::F64: - masm.storeDouble(RegF64(ReturnDoubleReg), resultsAddress); + masm.storeDouble(RegF64(ReturnDoubleReg).reg, resultsAddress); break; case ExprType::F32: - masm.storeFloat32(RegF32(ReturnFloat32Reg), resultsAddress); + masm.storeFloat32(RegF32(ReturnFloat32Reg).reg, resultsAddress); break; default: MOZ_CRASH("Function return type"); @@ -2251,7 +2307,7 @@ class BaseCompiler // Restore the TLS register in case it was overwritten by the function. loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); - GenerateFunctionEpilogue(masm, localSize_, &compileResults_.offsets()); + GenerateFunctionEpilogue(masm, localSize_, &offsets_); #if defined(JS_ION_PERF) // FIXME - profiling code missing. Bug 1286948. @@ -2265,7 +2321,7 @@ class BaseCompiler masm.wasmEmitTrapOutOfLineCode(); - compileResults_.offsets().end = masm.currentOffset(); + offsets_.end = masm.currentOffset(); // A frame greater than 256KB is implausible, probably an attack, // so fail the compilation. @@ -2683,7 +2739,7 @@ class BaseCompiler return rv; } - void returnCleanup(bool popStack) { + void returnCleanup(bool popStack = false) { if (popStack) popStackBeforeBranch(controlOutermost().framePushed); masm.jump(&returnLabel_); @@ -5528,6 +5584,7 @@ BaseCompiler::emitIf() if (!iter_.readIf(&unused_cond)) return false; + RegI32 rc; BranchState b(&controlItem().otherLabel, BranchState::NoPop, InvertBranch(true)); if (!deadCode_) { rc = popI32(); @@ -5537,7 +5594,7 @@ BaseCompiler::emitIf() initControl(controlItem()); if (!deadCode_) { - masm.branch32(Assembler::Equal, rc.reg, Imm32(0), controlItem(0).otherLabel); + masm.branch32(Assembler::Equal, rc.reg, Imm32(0), &controlItem(0).otherLabel); freeI32(rc); } @@ -6483,7 +6540,7 @@ BaseCompiler::emitSetGlobal() { uint32_t id; Nothing unused_value; - if (!iter_.readSetGlobal(mg_.globals, &id, &unused_value)) + if (!iter_.readSetGlobal(env_.globals, &id, &unused_value)) return false; if (deadCode_) @@ -6523,6 +6580,7 @@ BaseCompiler::emitSetGlobal() return true; } +#if 0 bool BaseCompiler::emitSetGlobal() { @@ -6533,6 +6591,7 @@ BaseCompiler::emitSetGlobal() return emitSetOrTeeGlobal(id); } +#endif bool BaseCompiler::emitTeeGlobal() @@ -6545,7 +6604,7 @@ BaseCompiler::emitTeeGlobal() if (deadCode_) return true; - const GlobalDesc& global = mg_.globals[id]; + const GlobalDesc& global = env_.globals[id]; switch (global.type()) { case ValType::I32: { @@ -6788,7 +6847,7 @@ BaseCompiler::emitTeeStore(ValType resultType, Scalar::Type viewType) MemoryAccessDesc access(viewType, addr.align, addr.offset, trapIfNotAsmJS()); - size_t temps = loadStoreTemps(access); + size_t temps = storeTemps(access); RegI32 tmp1 = temps >= 1 ? needI32() : invalidI32(); RegI32 tmp2 = temps >= 2 ? needI32() : invalidI32(); @@ -6796,7 +6855,7 @@ BaseCompiler::emitTeeStore(ValType resultType, Scalar::Type viewType) case ValType::I32: { RegI32 rp, rv; pop2xI32(&rp, &rv); - if (!store(access, rp, AnyReg(rv), tmp1, tmp2)) + if (!store(access, rp, false, AnyReg(rv), tmp1)) return false; freeI32(rp); pushI32(rv); @@ -6805,7 +6864,7 @@ BaseCompiler::emitTeeStore(ValType resultType, Scalar::Type viewType) case ValType::I64: { RegI64 rv = popI64(); RegI32 rp = popI32(); - if (!store(access, rp, AnyReg(rv), tmp1, tmp2)) + if (!store(access, rp, false, AnyReg(rv), tmp1)) return false; freeI32(rp); pushI64(rv); @@ -6814,7 +6873,7 @@ BaseCompiler::emitTeeStore(ValType resultType, Scalar::Type viewType) case ValType::F32: { RegF32 rv = popF32(); RegI32 rp = popI32(); - if (!store(access, rp, AnyReg(rv), tmp1, tmp2)) + if (!store(access, rp, false, AnyReg(rv), tmp1)) return false; freeI32(rp); pushF32(rv); @@ -6823,7 +6882,7 @@ BaseCompiler::emitTeeStore(ValType resultType, Scalar::Type viewType) case ValType::F64: { RegF64 rv = popF64(); RegI32 rp = popI32(); - if (!store(access, rp, AnyReg(rv), tmp1, tmp2)) + if (!store(access, rp, false, AnyReg(rv), tmp1)) return false; freeI32(rp); pushF64(rv); @@ -8037,7 +8096,7 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env, iter_(decoder, func.lineOrBytecode()), func_(func), lastReadCallSite_(0), - alloc_(compileResults.alloc()), + alloc_(*alloc), locals_(locals), localSize_(0), varLow_(0), @@ -8046,8 +8105,7 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env, deadCode_(false), debugEnabled_(debugEnabled), prologueTrapOffset_(trapOffset()), - compileResults_(compileResults), - masm(compileResults_.masm()), + masm(*masm), availGPR_(GeneralRegisterSet::All()), availFPU_(FloatRegisterSet::All()), #ifdef DEBUG @@ -8248,7 +8306,7 @@ js::wasm::BaselineCanCompile(const FunctionGenerator* fg) } bool -js::wasm::BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars *error) +js::wasm::BaselineCompileFunction(IonCompileTask* task, FuncCompileUnit* unit, UniqueChars *error) { MOZ_ASSERT(task->mode() == IonCompileTask::CompileMode::Baseline); @@ -8272,7 +8330,7 @@ js::wasm::BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit, Uniq // The MacroAssembler will sometimes access the jitContext. - JitContext jitContext(&results.alloc()); + JitContext jitContext(&task->alloc()); // One-pass baseline compilation. @@ -8285,6 +8343,8 @@ js::wasm::BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit, Uniq f.finish(); + unit->finish(f.offsets()); + return true; } diff --git a/js/src/wasm/WasmBaselineCompile.h b/js/src/wasm/WasmBaselineCompile.h index 99d701fedf..7c04f28d38 100644 --- a/js/src/wasm/WasmBaselineCompile.h +++ b/js/src/wasm/WasmBaselineCompile.h @@ -19,6 +19,7 @@ #define asmjs_wasm_baseline_compile_h #include "wasm/WasmTypes.h" +#include "wasm/WasmGenerator.h" namespace js { namespace wasm { @@ -39,7 +40,7 @@ BaselineCanCompile(const FunctionGenerator* fg); // Generate adequate code quickly. bool -BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars* error); +BaselineCompileFunction(IonCompileTask* task, FuncCompileUnit* unit, UniqueChars* error); } // namespace wasm } // namespace js diff --git a/js/src/wasm/WasmCode.cpp b/js/src/wasm/WasmCode.cpp index 5b3bb73345..54b48f2378 100644 --- a/js/src/wasm/WasmCode.cpp +++ b/js/src/wasm/WasmCode.cpp @@ -72,8 +72,9 @@ AllocateCodeSegment(JSContext* cx, uint32_t codeLength) // to purge all memory (which, in gecko, does a purging GC/CC/GC), do that // then retry the allocation. if (!p) { - if (OnLargeAllocationFailure) { - OnLargeAllocationFailure(); + JSRuntime* rt = cx->runtime(); + if (rt->largeAllocationFailureCallback) { + rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData); p = AllocateExecutableMemory(codeLength, ProtectionSetting::Writable); } } diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp index a30933028b..8e59bb4b7c 100644 --- a/js/src/wasm/WasmGenerator.cpp +++ b/js/src/wasm/WasmGenerator.cpp @@ -428,13 +428,12 @@ bool ModuleGenerator::finishTask(IonCompileTask* task) { const FuncBytes& func = task->func(); - FuncCompileResults& results = task->results(); masm_.haltingAlign(CodeAlignment); // Before merging in the new function's code, if calls in a prior function // body might go out of range, insert far jumps to extend the range. - if ((masm_.size() - startOfUnpatchedCallsites_) + results.masm().size() > JumpRange()) { + if ((masm_.size() - startOfUnpatchedCallsites_) + task->masm().size() > JumpRange()) { startOfUnpatchedCallsites_ = masm_.size(); if (!patchCallSites()) return false; @@ -443,11 +442,12 @@ ModuleGenerator::finishTask(IonCompileTask* task) // Offset the recorded FuncOffsets by the offset of the function in the // whole module's code segment. uint32_t offsetInWhole = masm_.size(); - results.offsets().offsetBy(offsetInWhole); + FuncOffsets offsets = task->units().back().offsets(); + offsets.offsetBy(offsetInWhole); // Add the CodeRange for this function. uint32_t funcCodeRangeIndex = metadata_->codeRanges.length(); - if (!metadata_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), results.offsets())) + if (!metadata_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), offsets)) return false; MOZ_ASSERT(!funcIsCompiled(func.index())); @@ -455,9 +455,9 @@ ModuleGenerator::finishTask(IonCompileTask* task) // Merge the compiled results into the whole-module masm. mozilla::DebugOnly sizeBefore = masm_.size(); - if (!masm_.asmMergeWith(results.masm())) + if (!masm_.asmMergeWith(task->masm())) return false; - MOZ_ASSERT(masm_.size() == offsetInWhole + results.masm().size()); + MOZ_ASSERT(masm_.size() == offsetInWhole + task->masm().size()); freeTasks_.infallibleAppend(task); return true; @@ -934,11 +934,11 @@ ModuleGenerator::finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg) if (!func) return false; - CompileMode mode; + IonCompileTask::CompileMode mode; if ((alwaysBaseline_ || debugEnabled_) && BaselineCanCompile(fg)) { - mode = CompileMode::Baseline; + mode = IonCompileTask::CompileMode::Baseline; } else { - mode = CompileMode::Ion; + mode = IonCompileTask::CompileMode::Ion; // Ion does not support debugging -- reset debugEnabled_ flags to avoid // turning debugging for wasm::Code. debugEnabled_ = false; @@ -1177,7 +1177,7 @@ ModuleGenerator::finish(const ShareableBytes& bytecode) } bool -wasm::CompileFunction(CompileTask* task, UniqueChars* error) +wasm::CompileFunction(IonCompileTask* task, UniqueChars* error) { TraceLoggerThread* logger = TraceLoggerForCurrentThread(); AutoTraceLog logCompile(logger, TraceLogger_WasmCompilation); diff --git a/js/src/wasm/WasmGenerator.h b/js/src/wasm/WasmGenerator.h index 22afb5e73a..19d7289469 100644 --- a/js/src/wasm/WasmGenerator.h +++ b/js/src/wasm/WasmGenerator.h @@ -54,6 +54,15 @@ class FuncBytes lineOrBytecode_(UINT32_MAX) {} + FuncBytes(Bytes bytes, uint32_t index, const SigWithId& sig, + uint32_t lineOrBytecode, Uint32Vector callSiteLineNums) + : bytes_(Move(bytes)), + index_(index), + sig_(&sig), + lineOrBytecode_(lineOrBytecode), + callSiteLineNums_(Move(callSiteLineNums)) + {} + Bytes& bytes() { return bytes_; } @@ -137,8 +146,12 @@ typedef Vector FuncCompileUnitVector; // finally sent back to the validation thread. To save time allocating and // freeing memory, CompileTasks are reset() and reused. -class CompileTask +class IonCompileTask { + public: + enum class CompileMode { None, Baseline, Ion }; + + private: const ModuleEnvironment& env_; LifoAlloc lifo_; Maybe alloc_; @@ -146,8 +159,8 @@ class CompileTask FuncCompileUnitVector units_; bool debugEnabled_; - CompileTask(const CompileTask&) = delete; - CompileTask& operator=(const CompileTask&) = delete; + IonCompileTask(const IonCompileTask&) = delete; + IonCompileTask& operator=(const IonCompileTask&) = delete; void init() { alloc_.emplace(&lifo_); @@ -156,7 +169,7 @@ class CompileTask } public: - CompileTask(const ModuleEnvironment& env, size_t defaultChunkSize) + IonCompileTask(const ModuleEnvironment& env, size_t defaultChunkSize) : env_(env), lifo_(defaultChunkSize) { @@ -177,12 +190,38 @@ class CompileTask FuncCompileUnitVector& units() { return units_; } + const FuncBytes& func() const { + MOZ_ASSERT(!units_.empty()); + return units_[0].func(); + } + CompileMode mode() const { + if (units_.empty()) + return CompileMode::None; + return units_[0].mode() == ::js::wasm::CompileMode::Baseline + ? CompileMode::Baseline + : CompileMode::Ion; + } bool debugEnabled() const { return debugEnabled_; } void setDebugEnabled(bool enabled) { debugEnabled_ = enabled; } + void init(UniqueFuncBytes func, CompileMode mode) { + units_.infallibleEmplaceBack(Move(func), + mode == CompileMode::Baseline + ? ::js::wasm::CompileMode::Baseline + : ::js::wasm::CompileMode::Ion); + } + bool reset(Bytes* unused) { + (void)unused; + units_.clear(); + masm_.reset(); + alloc_.reset(); + lifo_.releaseAll(); + init(); + return true; + } bool reset(UniqueFuncBytesVector* freeFuncBytes) { for (FuncCompileUnit& unit : units_) { if (!freeFuncBytes->emplaceBack(Move(unit.recycle()))) @@ -240,6 +279,8 @@ class MOZ_STACK_CLASS ModuleGenerator uint32_t outstanding_; IonCompileTaskVector tasks_; IonCompileTaskPtrVector freeTasks_; + IonCompileTask* currentTask_ = nullptr; + size_t batchedBytecode_ = 0; // Assertions DebugOnly activeFuncDef_; @@ -254,7 +295,7 @@ public: private: [[nodiscard]] bool patchCallSites(TrapExitOffsetArray* maybeTrapExits = nullptr); [[nodiscard]] bool patchFarJumps(const TrapExitOffsetArray& trapExits, const Offsets& debugTrapStub); - [[nodiscard]] bool finishTask(CompileTask* task); + [[nodiscard]] bool finishTask(IonCompileTask* task); [[nodiscard]] bool finishOutstandingTask(); [[nodiscard]] bool finishFuncExports(); [[nodiscard]] bool finishCodegen(); diff --git a/js/src/wasm/WasmInstance.cpp b/js/src/wasm/WasmInstance.cpp index 8b2cc9fad7..18f134ce66 100644 --- a/js/src/wasm/WasmInstance.cpp +++ b/js/src/wasm/WasmInstance.cpp @@ -327,7 +327,7 @@ Instance::Instance(JSContext* cx, tlsData()->instance = this; tlsData()->globalData = globals_->globalData(); tlsData()->memoryBase = memory ? memory->buffer().dataPointerEither().unwrap() : nullptr; - tlsData()->stackLimit = *(void**)cx->stackLimitAddressForJitCode(JS::StackForUntrustedScript); + tlsData()->stackLimit = *(void**)cx->stackLimitAddressForJitCode(js::StackForUntrustedScript); for (size_t i = 0; i < metadata().funcImports.length(); i++) { HandleFunction f = funcImports[i]; diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp index b64c13df37..3e0beb342c 100644 --- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -166,8 +166,6 @@ class FunctionCompiler uint32_t blockDepth_; ControlFlowPatchsVector blockPatches_; - FuncCompileResults& compileResults_; - // TLS pointer argument to the current function. MWasmParameter* tlsPointer_; @@ -190,14 +188,12 @@ class FunctionCompiler maxStackArgBytes_(0), loopDepth_(0), blockDepth_(0), - compileResults_(compileResults), tlsPointer_(nullptr) {} const ModuleEnvironment& env() const { return env_; } IonOpIter& iter() { return iter_; } TempAllocator& alloc() const { return alloc_; } - MacroAssembler& masm() const { return compileResults_.masm(); } const Sig& sig() const { return func_.sig(); } TrapOffset trapOffset() const { @@ -2891,7 +2887,7 @@ EmitExpr(FunctionCompiler& f) } bool -wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars* error) +wasm::IonCompileFunction(IonCompileTask* task, FuncCompileUnit* unit, UniqueChars* error) { MOZ_ASSERT(task->mode() == IonCompileTask::CompileMode::Ion); @@ -2919,11 +2915,11 @@ wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars* // Set up for Ion compilation. - JitContext jitContext(&results.alloc()); + JitContext jitContext(&task->alloc()); const JitCompileOptions options; - MIRGraph graph(&results.alloc()); + MIRGraph graph(&task->alloc()); CompileInfo compileInfo(locals.length()); - MIRGenerator mir(nullptr, options, &results.alloc(), &graph, &compileInfo, + MIRGenerator mir(nullptr, options, &task->alloc(), &graph, &compileInfo, IonOptimizations.get(OptimizationLevel::Wasm)); mir.initMinWasmHeapLength(env.minMemoryLength); @@ -2975,9 +2971,11 @@ wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars* SigIdDesc sigId = env.funcSigs[func.index()]->id; - CodeGenerator codegen(&mir, lir, &results.masm()); - if (!codegen.generateWasm(sigId, prologueTrapOffset, &results.offsets())) + CodeGenerator codegen(&mir, lir, &task->masm()); + FuncOffsets offsets; + if (!codegen.generateWasm(sigId, prologueTrapOffset, &offsets)) return false; + unit->finish(offsets); } return true; @@ -2986,17 +2984,18 @@ wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars* bool wasm::CompileFunction(IonCompileTask* task) { - TraceLoggerThread* logger = TraceLoggerForCurrentThread(); - AutoTraceLog logCompile(logger, TraceLogger_WasmCompilation); - - switch (task->mode()) { - case wasm::IonCompileTask::CompileMode::Ion: - return wasm::IonCompileFunction(task); - case wasm::IonCompileTask::CompileMode::Baseline: - return wasm::BaselineCompileFunction(task); - case wasm::IonCompileTask::CompileMode::None: - break; + UniqueChars error; + for (FuncCompileUnit& unit : task->units()) { + switch (unit.mode()) { + case CompileMode::Ion: + if (!IonCompileFunction(task, &unit, &error)) + return false; + break; + case CompileMode::Baseline: + if (!BaselineCompileFunction(task, &unit, &error)) + return false; + break; + } } - - MOZ_CRASH("Uninitialized task"); + return true; } diff --git a/js/src/wasm/WasmIonCompile.h b/js/src/wasm/WasmIonCompile.h index 340f24887e..1eda464cbb 100644 --- a/js/src/wasm/WasmIonCompile.h +++ b/js/src/wasm/WasmIonCompile.h @@ -19,21 +19,13 @@ #define wasm_ion_compile_h #include "jit/MacroAssembler.h" -#include "wasm/WasmTypes.h" - -#include "wasm/WasmTypes.h" +#include "wasm/WasmGenerator.h" namespace js { namespace wasm { -struct ModuleGeneratorData; - -typedef Vector MIRTypeVector; -typedef jit::ABIArgIter ABIArgMIRTypeIter; -typedef jit::ABIArgIter ABIArgValTypeIter; - [[nodiscard]] bool -IonCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars* error); +IonCompileFunction(IonCompileTask* task, FuncCompileUnit* unit, UniqueChars* error); } // namespace wasm } // namespace js diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 36b49f3a6c..80fe4ab0e6 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -57,7 +57,7 @@ wasm::HasCompilerSupport(ExclusiveContext* cx) if (!cx->jitSupportsFloatingPoint()) return false; - if (!cx->jitSupportsUnalignedAccesses()) + if (!cx->runtime()->jitSupportsUnalignedAccesses) return false; if (!wasm::HaveSignalHandlers()) diff --git a/js/src/wasm/WasmTypes.cpp b/js/src/wasm/WasmTypes.cpp index 0bca947732..65c762405a 100644 --- a/js/src/wasm/WasmTypes.cpp +++ b/js/src/wasm/WasmTypes.cpp @@ -22,6 +22,7 @@ #include "fdlibm.h" +#include "gc/Zone.h" #include "jslibmath.h" #include "jsmath.h" @@ -359,9 +360,9 @@ wasm::AddressOf(SymbolicAddress imm, ExclusiveContext* cx) { switch (imm) { case SymbolicAddress::Context: - return cx->contextAddressForJit(); + return cx->zone()->group()->addressOfOwnerContext(); case SymbolicAddress::InterruptUint32: - return cx->runtimeAddressOfInterruptUint32(); + return cx->runtime()->addressOfInterruptUint32(); case SymbolicAddress::ReportOverRecursed: return FuncCast(WasmReportOverRecursed, Args_General0); case SymbolicAddress::HandleExecutionInterrupt: From 333f72e353ae0196c5f999a378726b986d876951 Mon Sep 17 00:00:00 2001 From: wuggy Date: Sun, 6 Sep 2026 09:20:22 -0700 Subject: [PATCH 2/3] fix linking errors pt 2 --- js/src/gc/ZoneGroup.cpp | 7 +++++++ js/src/gc/ZoneGroup.h | 2 +- js/src/jscntxt.cpp | 5 +++++ js/src/jsgc.cpp | 10 ++++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/js/src/gc/ZoneGroup.cpp b/js/src/gc/ZoneGroup.cpp index 03c3ac89dc..11f388768a 100644 --- a/js/src/gc/ZoneGroup.cpp +++ b/js/src/gc/ZoneGroup.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gc/ZoneGroup.h" +#include "gc/Nursery.h" #include "jscntxt.h" @@ -15,6 +16,12 @@ using namespace js; namespace js { +Nursery& +ZoneGroup::nursery() +{ + return runtime->gc.getNursery(); +} + ZoneGroup::ZoneGroup(JSRuntime* runtime) : runtime(runtime), ownerContext_(TlsContext.get()), diff --git a/js/src/gc/ZoneGroup.h b/js/src/gc/ZoneGroup.h index 976683215d..2f47436b73 100644 --- a/js/src/gc/ZoneGroup.h +++ b/js/src/gc/ZoneGroup.h @@ -111,7 +111,7 @@ class ZoneGroup bool init(); - inline Nursery& nursery(); + Nursery& nursery(); inline gc::StoreBuffer& storeBuffer(); inline bool isCollecting(); diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index c48b68ae20..6d1b8616ab 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -54,6 +54,11 @@ #include "vm/Stack-inl.h" +// The execution context is stored in thread-local storage and is declared in +// jscntxt.h. Keep the single definition here so every user of the GC and +// zone-group code links against the same TLS slot. +MOZ_THREAD_LOCAL(JSContext*) js::TlsContext; + using namespace js; using namespace js::gc; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index d5a0f639b1..e1101e698b 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -8144,6 +8144,16 @@ JS::IsIncrementalBarrierNeeded(JSContext* cx) return state != gc::State::NotActive && state <= gc::State::Sweep; } +JS_PUBLIC_API(void) +js::gc::MarkGCThingAsLive(JSRuntime* rt, JS::GCCellPtr thing) +{ + if (!thing || js::gc::IsInsideNursery(thing.asCell())) + return; + + MOZ_ASSERT(thing.asCell()->runtimeFromAnyThread() == rt); + thing.asCell()->asTenured().markIfUnmarked(js::gc::MarkColor::Black); +} + struct IncrementalReferenceBarrierFunctor { template void operator()(T* t) { T::writeBarrierPre(t); } }; From 094c27b33bd6078b8a00b419b9df09afb0c67ba6 Mon Sep 17 00:00:00 2001 From: wuggy Date: Sun, 6 Sep 2026 09:53:06 -0700 Subject: [PATCH 3/3] Fix runtime error pt.1 --- js/src/jsapi.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 6b36c5dd82..8358adfc89 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4617,15 +4617,19 @@ extern JS_PUBLIC_API(bool) JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, const char* bytes, size_t length, MutableHandleValue rval) { - char16_t* chars; + // Keep the converted source owned by this stack frame for the entire + // compilation. SourceBufferHolder only borrows it; transferring + // ownership here can leave the parser reading freed/poisoned memory when + // self-hosted code is initialized. + UniqueTwoByteChars chars; if (options.utf8) - chars = UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(bytes, length), &length).get(); + chars.reset(UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(bytes, length), &length).get()); else - chars = InflateString(cx, bytes, &length); + chars.reset(InflateString(cx, bytes, &length)); if (!chars) return false; - SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership); + SourceBufferHolder srcBuf(chars.get(), length, SourceBufferHolder::NoOwnership); RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment()); bool ok = ::Evaluate(cx, ScopeKind::Global, globalLexical, options, srcBuf, rval); return ok;