tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit f82c81855d62f18927cdf8ba05f78d4355f68724
parent df4d7643944feb4612d77f6916455d05573dd922
Author: André Bargull <andre.bargull@gmail.com>
Date:   Mon, 13 Oct 2025 12:55:25 +0000

Bug 1990248 - Part 5: Add GuardRuntimeFuse CacheIR instruction. r=spidermonkey-reviewers,jandem

This is similar to `GuardRealmFuse`, except it guards on a runtime-wide fuse.

The two current runtime fuses are handled in "CodeGenerator.cpp", so we don't
actually have to support them for this new instruction or in
`WarpOracle::addFuseDependency`. The next part adds a new runtime fuse
which uses this new instruction, though.

Differential Revision: https://phabricator.services.mozilla.com/D265827

Diffstat:
Mjs/src/jit/CacheIRCompiler.cpp | 12++++++++++++
Mjs/src/jit/CacheIROps.yaml | 8++++++++
Mjs/src/jit/CacheIRReader.h | 3+++
Mjs/src/jit/CacheIRSpewer.cpp | 13+++++++++++++
Mjs/src/jit/CacheIRWriter.h | 6++++++
Mjs/src/jit/GenerateCacheIRFiles.py | 4++++
Mjs/src/jit/WarpCacheIRTranspiler.cpp | 7+++++++
Mjs/src/jit/WarpOracle.cpp | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mjs/src/jit/WarpOracle.h | 3+++
9 files changed, 128 insertions(+), 0 deletions(-)

diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp @@ -11430,6 +11430,18 @@ bool CacheIRCompiler::emitGuardFuse(RealmFuses::FuseIndex fuseIndex) { return true; } +bool CacheIRCompiler::emitGuardRuntimeFuse(RuntimeFuses::FuseIndex fuseIndex) { + JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); + + FailurePath* failure; + if (!addFailurePath(&failure)) { + return false; + } + + masm.guardRuntimeFuse(fuseIndex, failure->label()); + return true; +} + bool CacheIRCompiler::emitGuardObjectFuseProperty( ObjOperandId objId, uint32_t objFuseOwnerOffset, uint32_t objFuseOffset, uint32_t expectedGenerationOffset, uint32_t propIndexOffset, diff --git a/js/src/jit/CacheIROps.yaml b/js/src/jit/CacheIROps.yaml @@ -280,6 +280,14 @@ args: fuseWord: RealmFuseIndexImm +# Guard on a runtime fuse. +- name: GuardRuntimeFuse + shared: true + transpile: true + cost_estimate: 1 + args: + fuseWord: RuntimeFuseIndexImm + - name: GuardObjectFuseProperty shared: true transpile: true diff --git a/js/src/jit/CacheIRReader.h b/js/src/jit/CacheIRReader.h @@ -120,6 +120,9 @@ class MOZ_RAII CacheIRReader { RealmFuses::FuseIndex realmFuseIndex() { return RealmFuses::FuseIndex(buffer_.readByte()); } + RuntimeFuses::FuseIndex runtimeFuseIndex() { + return RuntimeFuses::FuseIndex(buffer_.readByte()); + } Scalar::Type scalarType() { return Scalar::Type(buffer_.readByte()); } JSWhyMagic whyMagic() { return JSWhyMagic(buffer_.readByte()); } diff --git a/js/src/jit/CacheIRSpewer.cpp b/js/src/jit/CacheIRSpewer.cpp @@ -127,6 +127,11 @@ class MOZ_RAII CacheIROpsJitSpewer { out_.printf("%s RealmFuseIndex(%u=%s)", name, unsigned(index), RealmFuses::getFuseName(index)); } + void spewRuntimeFuseIndexImm(const char* name, + RuntimeFuses::FuseIndex index) { + out_.printf("%s RuntimeFuseIndex(%u=%s)", name, unsigned(index), + RuntimeFuses::getFuseName(index)); + } public: CacheIROpsJitSpewer(GenericPrinter& out, const char* prefix) @@ -273,6 +278,9 @@ class MOZ_RAII CacheIROpsJSONSpewer { void spewRealmFuseIndexImm(const char* name, RealmFuses::FuseIndex kind) { spewArgImpl(name, "Imm", unsigned(kind)); } + void spewRuntimeFuseIndexImm(const char* name, RuntimeFuses::FuseIndex kind) { + spewArgImpl(name, "Imm", unsigned(kind)); + } void spewWasmValTypeImm(const char* name, wasm::ValType::Kind kind) { spewArgImpl(name, "Imm", unsigned(kind)); } @@ -638,6 +646,11 @@ class MOZ_RAII CacheIROpsAotSpewer { (void)name; out_.printf("REALMFUSE(%u)", unsigned(index)); } + void spewRuntimeFuseIndexImm(const char* name, + RuntimeFuses::FuseIndex index) { + (void)name; + out_.printf("RUNTIMEFUSE(%u)", unsigned(index)); + } public: CacheIROpsAotSpewer(GenericPrinter& out) : out_(out) {} diff --git a/js/src/jit/CacheIRWriter.h b/js/src/jit/CacheIRWriter.h @@ -42,6 +42,7 @@ #include "vm/List.h" #include "vm/Opcodes.h" #include "vm/RealmFuses.h" +#include "vm/RuntimeFuses.h" #include "vm/Shape.h" #include "vm/TypeofEqOperand.h" // TypeofEqOperand #include "wasm/WasmConstants.h" @@ -304,6 +305,11 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter { "RealmFuses::FuseIndex must fit in a byte"); buffer_.writeByte(uint8_t(realmFuseIndex)); } + void writeRuntimeFuseIndexImm(RuntimeFuses::FuseIndex runtimeFuseIndex) { + static_assert(sizeof(RuntimeFuses::FuseIndex) == sizeof(uint8_t), + "RuntimeFuses::FuseIndex must fit in a byte"); + buffer_.writeByte(uint8_t(runtimeFuseIndex)); + } void writeByteImm(uint32_t b) { MOZ_ASSERT(b <= UINT8_MAX); diff --git a/js/src/jit/GenerateCacheIRFiles.py b/js/src/jit/GenerateCacheIRFiles.py @@ -101,6 +101,7 @@ arg_writer_info = { "AllocKindImm": ("gc::AllocKind", "writeAllocKindImm"), "CompletionKindImm": ("CompletionKind", "writeCompletionKindImm"), "RealmFuseIndexImm": ("RealmFuses::FuseIndex", "writeRealmFuseIndexImm"), + "RuntimeFuseIndexImm": ("RuntimeFuses::FuseIndex", "writeRuntimeFuseIndexImm"), } @@ -210,6 +211,7 @@ arg_reader_info = { "AllocKindImm": ("gc::AllocKind", "", "reader.allocKind()"), "CompletionKindImm": ("CompletionKind", "", "reader.completionKind()"), "RealmFuseIndexImm": ("RealmFuses::FuseIndex", "", "reader.realmFuseIndex()"), + "RuntimeFuseIndexImm": ("RuntimeFuses::FuseIndex", "", "reader.runtimeFuseIndex()"), } @@ -350,6 +352,7 @@ arg_spewer_method = { "AllocKindImm": "spewAllocKindImm", "CompletionKindImm": "spewCompletionKindImm", "RealmFuseIndexImm": "spewRealmFuseIndexImm", + "RuntimeFuseIndexImm": "spewRuntimeFuseIndexImm", } @@ -492,6 +495,7 @@ arg_length = { "AllocKindImm": 1, "CompletionKindImm": 1, "RealmFuseIndexImm": 1, + "RuntimeFuseIndexImm": 1, } diff --git a/js/src/jit/WarpCacheIRTranspiler.cpp b/js/src/jit/WarpCacheIRTranspiler.cpp @@ -491,6 +491,13 @@ bool WarpCacheIRTranspiler::emitGuardFuse(RealmFuses::FuseIndex fuseIndex) { } } +bool WarpCacheIRTranspiler::emitGuardRuntimeFuse( + RuntimeFuses::FuseIndex fuseIndex) { + // This is a no-op because WarpOracle has added a compilation dependency. + MOZ_ASSERT(RuntimeFuses::isInvalidatingFuse(fuseIndex)); + return true; +} + bool WarpCacheIRTranspiler::emitGuardObjectFuseProperty( ObjOperandId objId, uint32_t objFuseOwnerOffset, uint32_t objFuseOffset, uint32_t expectedGenerationOffset, uint32_t propIndexOffset, diff --git a/js/src/jit/WarpOracle.cpp b/js/src/jit/WarpOracle.cpp @@ -874,6 +874,67 @@ bool WarpOracle::addFuseDependency(RealmFuses::FuseIndex fuseIndex, } } +template <auto FuseMember, CompilationDependency::Type DepType> +struct RuntimeFuseDependency final : public CompilationDependency { + explicit RuntimeFuseDependency() : CompilationDependency(DepType) {} + + bool registerDependency(JSContext* cx, + const IonScriptKey& ionScript) override { + MOZ_ASSERT(checkDependency(cx)); + return (cx->runtime()->runtimeFuses.ref().*FuseMember) + .addFuseDependency(cx, ionScript); + } + + CompilationDependency* clone(TempAllocator& alloc) const override { + return new (alloc.fallible()) RuntimeFuseDependency<FuseMember, DepType>(); + } + + bool checkDependency(JSContext* cx) const override { + return (cx->runtime()->runtimeFuses.ref().*FuseMember).intact(); + } + + HashNumber hash() const override { return mozilla::HashGeneric(type); } + + bool operator==(const CompilationDependency& dep) const override { + // Since this dependency is runtime wide, they are all equal. + return dep.type == type; + } +}; + +bool WarpOracle::addFuseDependency(RuntimeFuses::FuseIndex fuseIndex, + bool* stillValid) { + MOZ_ASSERT(RuntimeFuses::isInvalidatingFuse(fuseIndex), + "All current runtime fuses are invalidating"); + + auto addIfStillValid = [&](const auto& dep) { + if (!dep.checkDependency(cx_)) { + *stillValid = false; + return true; + } + *stillValid = true; + return mirGen().tracker.addDependency(alloc_, dep); + }; + + // Register a compilation dependency for all fuses that are still valid. + switch (fuseIndex) { + case RuntimeFuses::FuseIndex::HasSeenObjectEmulateUndefinedFuse: { + using Dependency = RuntimeFuseDependency< + &RuntimeFuses::hasSeenObjectEmulateUndefinedFuse, + CompilationDependency::Type::EmulatesUndefined>; + return addIfStillValid(Dependency()); + } + case RuntimeFuses::FuseIndex::HasSeenArrayExceedsInt32LengthFuse: { + using Dependency = RuntimeFuseDependency< + &RuntimeFuses::hasSeenArrayExceedsInt32LengthFuse, + CompilationDependency::Type::ArrayExceedsInt32Length>; + return addIfStillValid(Dependency()); + } + case RuntimeFuses::FuseIndex::LastFuseIndex: + break; + } + MOZ_CRASH("invalid runtime fuse index"); +} + class ObjectPropertyFuseDependency final : public CompilationDependency { ObjectFuse* fuse_; uint32_t expectedGeneration_; @@ -1106,6 +1167,17 @@ AbortReasonOr<Ok> WarpScriptOracle::maybeInlineIC(WarpOpSnapshotList& snapshots, } break; } + case CacheOp::GuardRuntimeFuse: { + auto [fuseIndex] = reader.argsForGuardRuntimeFuse(); + bool stillValid; + if (!oracle_->addFuseDependency(fuseIndex, &stillValid)) { + return abort(AbortReason::Alloc); + } + if (!stillValid) { + hasInvalidFuseGuard = true; + } + break; + } case CacheOp::GuardObjectFuseProperty: { auto args = reader.argsForGuardObjectFuseProperty(); ObjectFuse* fuse = reinterpret_cast<ObjectFuse*>( diff --git a/js/src/jit/WarpOracle.h b/js/src/jit/WarpOracle.h @@ -63,6 +63,9 @@ class MOZ_STACK_CLASS WarpOracle { [[nodiscard]] bool addFuseDependency(RealmFuses::FuseIndex fuseIndex, bool* stillValid); + [[nodiscard]] bool addFuseDependency(RuntimeFuses::FuseIndex fuseIndex, + bool* stillValid); + AbortReasonOr<WarpSnapshot*> createSnapshot(); mozilla::GenericErrorResult<AbortReason> abort(HandleScript script,