tor-browser

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

commit 1f17646b88e61773e6977d42facf191e4a7940be
parent 7b9ab846a3f373798772e13f9fd6e35453726d77
Author: André Bargull <andre.bargull@gmail.com>
Date:   Tue, 21 Oct 2025 07:05:40 +0000

Bug 1991402 - Part 5: Inline natives in super-get accesses. r=jandem

Passing the receiver-value to `InlinableNativeIRGenerator` as the this-value
allows to support inlining through native accessor functions in `GetPropSuper`
and `GetElemSuper` operations.

Drive-by change:
- Change some MutableHandleValue to just HandleValue.

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

Diffstat:
Ajs/src/jit-test/tests/cacheir/inlinable-native-accessor-5.js | 31+++++++++++++++++++++++++++++++
Mjs/src/jit/BaselineIC.cpp | 18++++++++++--------
Mjs/src/jit/BaselineIC.h | 5++---
Mjs/src/jit/CacheIR.cpp | 15+++++++--------
Mjs/src/jit/CacheIRGenerator.h | 8+++++---
Mjs/src/jit/IonIC.cpp | 4++--
Mjs/src/vm/PortableBaselineInterpret.cpp | 4++--
7 files changed, 59 insertions(+), 26 deletions(-)

diff --git a/js/src/jit-test/tests/cacheir/inlinable-native-accessor-5.js b/js/src/jit-test/tests/cacheir/inlinable-native-accessor-5.js @@ -0,0 +1,31 @@ +// Test calling an inlinable native accessor through a Get{Prop,Elem}Super operation. + +class MySet extends Set { + get size() { + return super.size; + } +} + +function testWithClass() { + var sets = [ + new MySet(), + new MySet([1, 2, 3, 4]), + ]; + for (var i = 0; i < 100; ++i) { + var set = sets[i & 1]; + assertEq(set.size, (i & 1) * 4); + } +} +testWithClass(); + +function testWithReflect() { + var sets = [ + new Set(), + new Set([1, 2, 3, 4]), + ]; + for (var i = 0; i < 100; ++i) { + var set = sets[i & 1]; + assertEq(Reflect.get(Set.prototype, "size", set), (i & 1) * 4); + } +} +testWithReflect(); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp @@ -718,7 +718,7 @@ bool DoGetElemFallback(JSContext* cx, BaselineFrame* frame, #endif TryAttachStub<GetPropIRGenerator>("GetElem", cx, frame, stub, - CacheKind::GetElem, lhs, rhs); + CacheKind::GetElem, lhs, rhs, lhs); if (!GetElementOperation(cx, lhs, rhs, res)) { return false; @@ -752,7 +752,8 @@ bool DoGetElemSuperFallback(JSContext* cx, BaselineFrame* frame, } TryAttachStub<GetPropIRGenerator>("GetElemSuper", cx, frame, stub, - CacheKind::GetElemSuper, lhs, rhs); + CacheKind::GetElemSuper, lhs, rhs, + receiver); return GetObjectElementOperation(cx, op, lhsObj, receiver, rhs, res); } @@ -1288,7 +1289,7 @@ bool FallbackICCodeCompiler::emit_LazyConstant() { // bool DoGetPropFallback(JSContext* cx, BaselineFrame* frame, - ICFallbackStub* stub, MutableHandleValue val, + ICFallbackStub* stub, HandleValue val, MutableHandleValue res) { stub->incrementEnteredCount(); MaybeNotifyWarp(frame->outerScript(), stub); @@ -1304,7 +1305,7 @@ bool DoGetPropFallback(JSContext* cx, BaselineFrame* frame, RootedValue idVal(cx, StringValue(name)); TryAttachStub<GetPropIRGenerator>("GetProp", cx, frame, stub, - CacheKind::GetProp, val, idVal); + CacheKind::GetProp, val, idVal, val); if (op == JSOp::GetBoundName) { RootedObject env(cx, &val.toObject()); @@ -1322,7 +1323,7 @@ bool DoGetPropFallback(JSContext* cx, BaselineFrame* frame, bool DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub, HandleValue receiver, - MutableHandleValue val, MutableHandleValue res) { + HandleValue val, MutableHandleValue res) { stub->incrementEnteredCount(); MaybeNotifyWarp(frame->outerScript(), stub); @@ -1346,7 +1347,8 @@ bool DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame, } TryAttachStub<GetPropIRGenerator>("GetPropSuper", cx, frame, stub, - CacheKind::GetPropSuper, val, idVal); + CacheKind::GetPropSuper, val, idVal, + receiver); if (!GetProperty(cx, valObj, receiver, name, res)) { return false; @@ -1369,7 +1371,7 @@ bool FallbackICCodeCompiler::emitGetProp(bool hasReceiver) { masm.pushBaselineFramePtr(FramePointer, R0.scratchReg()); using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, - HandleValue, MutableHandleValue, MutableHandleValue); + HandleValue, HandleValue, MutableHandleValue); if (!tailCallVM<Fn, DoGetPropSuperFallback>(masm)) { return false; } @@ -1383,7 +1385,7 @@ bool FallbackICCodeCompiler::emitGetProp(bool hasReceiver) { masm.pushBaselineFramePtr(FramePointer, R0.scratchReg()); using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, - MutableHandleValue, MutableHandleValue); + HandleValue, MutableHandleValue); if (!tailCallVM<Fn, DoGetPropFallback>(masm)) { return false; } diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h @@ -391,13 +391,12 @@ extern bool DoLazyConstantFallback(JSContext* cx, BaselineFrame* frame, MutableHandleValue res); extern bool DoGetPropFallback(JSContext* cx, BaselineFrame* frame, - ICFallbackStub* stub, MutableHandleValue val, + ICFallbackStub* stub, HandleValue val, MutableHandleValue res); extern bool DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub, HandleValue receiver, - MutableHandleValue val, - MutableHandleValue res); + HandleValue val, MutableHandleValue res); extern bool DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub, Value* stack, diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp @@ -300,8 +300,12 @@ gc::AllocSite* IRGenerator::maybeCreateAllocSite() { GetPropIRGenerator::GetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState state, CacheKind cacheKind, HandleValue val, - HandleValue idVal) - : IRGenerator(cx, script, pc, cacheKind, state), val_(val), idVal_(idVal) {} + HandleValue idVal, + HandleValue receiverVal) + : IRGenerator(cx, script, pc, cacheKind, state), + val_(val), + idVal_(idVal), + receiverVal_(receiverVal) {} static void EmitLoadSlotResult(CacheIRWriter& writer, ObjOperandId holderId, NativeObject* holder, PropertyInfo prop) { @@ -2446,15 +2450,10 @@ AttachDecision GetPropIRGenerator::tryAttachInlinableNativeGetter( Handle<NativeObject*> holder, PropertyInfo prop, ValOperandId receiverId) { MOZ_ASSERT(mode_ == ICState::Mode::Specialized); - // Receiver should be the object. - if (isSuper()) { - return AttachDecision::NoAction; - } - Rooted<JSFunction*> target(cx_, &holder->getGetter(prop)->as<JSFunction>()); MOZ_ASSERT(target->isNativeWithoutJitEntry()); - Handle<Value> thisValue = val_; + Handle<Value> thisValue = receiverVal_; bool isSpread = false; bool isSameRealm = cx_->realm() == target->realm(); diff --git a/js/src/jit/CacheIRGenerator.h b/js/src/jit/CacheIRGenerator.h @@ -165,6 +165,7 @@ class MOZ_RAII IRGenerator { class MOZ_RAII GetPropIRGenerator : public IRGenerator { HandleValue val_; HandleValue idVal_; + HandleValue receiverVal_; friend class InlinableNativeIRGenerator; @@ -298,7 +299,7 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator { public: GetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState state, CacheKind cacheKind, HandleValue val, - HandleValue idVal); + HandleValue idVal, HandleValue receiverVal); AttachDecision tryAttachStub(); }; @@ -679,7 +680,7 @@ class MOZ_RAII InlinableNativeIRGenerator { JSOp op() const { return generator_.jsop(); } uint32_t stackArgc() const { return stackArgc_; } - // Inlined native accessor for GetProp or GetElem operations. + // Inlined native accessor for GetProp(Super) or GetElem(Super) operations. bool isAccessorOp() const { return !IsInvokeOp(op()); } bool isCalleeBoundFunction() const; @@ -1133,7 +1134,8 @@ inline bool BytecodeCallOpCanHaveInlinableNative(JSOp op) { // Returns true for bytecode get ops that can use InlinableNativeIRGenerator. inline bool BytecodeGetOpCanHaveInlinableNative(JSOp op) { - return op == JSOp::GetProp || op == JSOp::GetElem; + return op == JSOp::GetProp || op == JSOp::GetElem || + op == JSOp::GetPropSuper || op == JSOp::GetElemSuper; } inline bool BytecodeOpCanHaveAllocSite(JSOp op) { diff --git a/js/src/jit/IonIC.cpp b/js/src/jit/IonIC.cpp @@ -174,7 +174,7 @@ bool IonGetPropertyIC::update(JSContext* cx, HandleScript outerScript, MOZ_ASSERT(!val.isMagic()); TryAttachIonStub<GetPropIRGenerator>(cx, ic, ionScript, ic->kind(), val, - idVal); + idVal, val); if (ic->kind() == CacheKind::GetProp) { Rooted<PropertyName*> name(cx, idVal.toString()->asAtom().asPropertyName()); @@ -219,7 +219,7 @@ bool IonGetPropSuperIC::update(JSContext* cx, HandleScript outerScript, RootedValue val(cx, ObjectValue(*obj)); TryAttachIonStub<GetPropIRGenerator>(cx, ic, ionScript, ic->kind(), val, - idVal); + idVal, receiver); if (ic->kind() == CacheKind::GetPropSuper) { Rooted<PropertyName*> name(cx, idVal.toString()->asAtom().asPropertyName()); diff --git a/js/src/vm/PortableBaselineInterpret.cpp b/js/src/vm/PortableBaselineInterpret.cpp @@ -5601,7 +5601,7 @@ DEFINE_IC(NewObject, 0, { DEFINE_IC(GetProp, 1, { IC_LOAD_VAL(value0, 0); PUSH_FALLBACK_IC_FRAME(); - if (!DoGetPropFallback(cx, ctx.frame, fallback, &value0, &ctx.state.res)) { + if (!DoGetPropFallback(cx, ctx.frame, fallback, value0, &ctx.state.res)) { goto error; } }); @@ -5610,7 +5610,7 @@ DEFINE_IC(GetPropSuper, 2, { IC_LOAD_VAL(value0, 1); IC_LOAD_VAL(value1, 0); PUSH_FALLBACK_IC_FRAME(); - if (!DoGetPropSuperFallback(cx, ctx.frame, fallback, value0, &value1, + if (!DoGetPropSuperFallback(cx, ctx.frame, fallback, value0, value1, &ctx.state.res)) { goto error; }