tor-browser

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

commit f75ff1ab1f97b6c92682f4ac49c70763a12bd67c
parent a0d144ed2675890e61a4263e963443715dcb1039
Author: André Bargull <andre.bargull@gmail.com>
Date:   Tue, 21 Oct 2025 07:05:44 +0000

Bug 1991402 - Part 18: Make ArrayJoinResult a shared CacheIR instruction. r=jandem

Use `AutoCallVM` to move the implementation into `CacheIRCompiler`.

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

Diffstat:
Mjs/src/jit-test/tests/cacheir/inlinable-native-accessor-6.js | 10++++++++++
Mjs/src/jit/BaselineCacheIRCompiler.cpp | 67-------------------------------------------------------------------
Mjs/src/jit/CacheIRCompiler.cpp | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mjs/src/jit/CacheIROps.yaml | 2+-
Mjs/src/jit/IonCacheIRCompiler.cpp | 5-----
5 files changed, 74 insertions(+), 73 deletions(-)

diff --git a/js/src/jit-test/tests/cacheir/inlinable-native-accessor-6.js b/js/src/jit-test/tests/cacheir/inlinable-native-accessor-6.js @@ -56,3 +56,13 @@ function testArraySliceArguments() { } } testArraySliceArguments(); + +function testArrayJoin() { + Object.defineProperty(Array.prototype, "joined", {get: Array.prototype.join}); + + for (var i = 0; i < 100; ++i) { + assertEq([].joined, ""); + assertEq(["a"].joined, "a"); + } +} +testArrayJoin(); diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp @@ -1040,73 +1040,6 @@ bool BaselineCacheIRCompiler::emitAllocateAndStoreDynamicSlot( newShapeOffset, mozilla::Some(numNewSlotsOffset), preserveWrapper); } -bool BaselineCacheIRCompiler::emitArrayJoinResult(ObjOperandId objId, - StringOperandId sepId) { - JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); - - AutoOutputRegister output(*this); - Register obj = allocator.useRegister(masm, objId); - Register sep = allocator.useRegister(masm, sepId); - AutoScratchRegisterMaybeOutput scratch(allocator, masm, output); - - allocator.discardStack(masm); - - // Load obj->elements in scratch. - masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch); - Address lengthAddr(scratch, ObjectElements::offsetOfLength()); - - // If array length is 0, return empty string. - Label finished; - - { - Label arrayNotEmpty; - masm.branch32(Assembler::NotEqual, lengthAddr, Imm32(0), &arrayNotEmpty); - masm.movePtr(ImmGCPtr(cx_->names().empty_), scratch); - masm.tagValue(JSVAL_TYPE_STRING, scratch, output.valueReg()); - masm.jump(&finished); - masm.bind(&arrayNotEmpty); - } - - Label vmCall; - - // Otherwise, handle array length 1 case. - masm.branch32(Assembler::NotEqual, lengthAddr, Imm32(1), &vmCall); - - // But only if initializedLength is also 1. - Address initLength(scratch, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::NotEqual, initLength, Imm32(1), &vmCall); - - // And only if elem0 is a string. - Address elementAddr(scratch, 0); - masm.branchTestString(Assembler::NotEqual, elementAddr, &vmCall); - - // Store the value. - masm.loadValue(elementAddr, output.valueReg()); - masm.jump(&finished); - - // Otherwise call into the VM. - { - masm.bind(&vmCall); - - AutoStubFrame stubFrame(*this); - stubFrame.enter(masm, scratch); - - masm.Push(sep); - masm.Push(obj); - - using Fn = JSString* (*)(JSContext*, HandleObject, HandleString); - callVM<Fn, jit::ArrayJoin>(masm); - - stubFrame.leave(masm); - - masm.tagValue(JSVAL_TYPE_STRING, ReturnReg, output.valueReg()); - } - - masm.bind(&finished); - - return true; -} - bool BaselineCacheIRCompiler::emitIsArrayResult(ValOperandId inputId) { JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp @@ -7390,6 +7390,69 @@ bool CacheIRCompiler::emitArgumentsSliceResult(uint32_t templateObjectOffset, return true; } +bool CacheIRCompiler::emitArrayJoinResult(ObjOperandId objId, + StringOperandId sepId) { + JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); + + AutoCallVM callvm(masm, this, allocator); + + Register obj = allocator.useRegister(masm, objId); + Register sep = allocator.useRegister(masm, sepId); + AutoScratchRegisterMaybeOutput scratch(allocator, masm, callvm.output()); + + // Discard the stack to ensure it's balanced when we skip the vm-call. + allocator.discardStack(masm); + + // Load obj->elements in scratch. + masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch); + Address lengthAddr(scratch, ObjectElements::offsetOfLength()); + + // If array length is 0, return empty string. + Label finished; + + { + Label arrayNotEmpty; + masm.branch32(Assembler::NotEqual, lengthAddr, Imm32(0), &arrayNotEmpty); + masm.movePtr(ImmGCPtr(cx_->names().empty_), scratch); + masm.tagValue(JSVAL_TYPE_STRING, scratch, callvm.outputValueReg()); + masm.jump(&finished); + masm.bind(&arrayNotEmpty); + } + + Label vmCall; + + // Otherwise, handle array length 1 case. + masm.branch32(Assembler::NotEqual, lengthAddr, Imm32(1), &vmCall); + + // But only if initializedLength is also 1. + Address initLength(scratch, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::NotEqual, initLength, Imm32(1), &vmCall); + + // And only if elem0 is a string. + Address elementAddr(scratch, 0); + masm.branchTestString(Assembler::NotEqual, elementAddr, &vmCall); + + // Store the value. + masm.loadValue(elementAddr, callvm.outputValueReg()); + masm.jump(&finished); + + // Otherwise call into the VM. + { + masm.bind(&vmCall); + + callvm.prepare(); + + masm.Push(sep); + masm.Push(obj); + + using Fn = JSString* (*)(JSContext*, HandleObject, HandleString); + callvm.call<Fn, jit::ArrayJoin>(); + } + + masm.bind(&finished); + return true; +} + bool CacheIRCompiler::emitStoreTypedArrayElement(ObjOperandId objId, Scalar::Type elementType, IntPtrOperandId indexId, diff --git a/js/src/jit/CacheIROps.yaml b/js/src/jit/CacheIROps.yaml @@ -1175,7 +1175,7 @@ rhs: ValId - name: ArrayJoinResult - shared: false + shared: true transpile: true cost_estimate: 5 args: diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp @@ -2330,11 +2330,6 @@ bool IonCacheIRCompiler::emitLoadArgumentDynamicSlot(ValOperandId resultId, MOZ_CRASH("Call ICs not used in ion"); } -bool IonCacheIRCompiler::emitArrayJoinResult(ObjOperandId objId, - StringOperandId sepId) { - MOZ_CRASH("Call ICs not used in ion"); -} - bool IonCacheIRCompiler::emitIsArrayResult(ValOperandId inputId) { MOZ_CRASH("Call ICs not used in ion"); }