tor-browser

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

commit ed55b76e9d66855ad187b4c9b43a071a879086f9
parent edaeec2a44db3552ff122004a05db13a2bddd6a6
Author: André Bargull <andre.bargull@gmail.com>
Date:   Mon, 20 Oct 2025 12:27:44 +0000

Bug 1991402 - Part 16: Support LoadStringAtResult in Ion ICs. r=jandem

This follows the baseline IC implementation.

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

Diffstat:
Mjs/src/jit-test/tests/cacheir/inlinable-native-accessor-6.js | 9+++++++++
Mjs/src/jit/IonCacheIRCompiler.cpp | 57+++++++++++++++++++++++++++++++++++++++++----------------
Mjs/src/jit/IonCacheIRCompiler.h | 4++++
3 files changed, 54 insertions(+), 16 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 @@ -29,3 +29,12 @@ function testNumberToString() { } } testNumberToString(); + +function testStringAt() { + Object.defineProperty(String.prototype, "at_", {get: String.prototype.at}); + + for (var i = 0; i < 100; ++i) { + assertEq("a".at_, "a"); + } +} +testStringAt(); diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp @@ -1564,9 +1564,9 @@ bool IonCacheIRCompiler::emitAllocateAndStoreDynamicSlot( newShapeOffset, mozilla::Some(numNewSlotsOffset), preserveWrapper); } -bool IonCacheIRCompiler::emitLoadStringCharResult(StringOperandId strId, - Int32OperandId indexId, - bool handleOOB) { +bool IonCacheIRCompiler::emitLoadStringCharResult( + StringOperandId strId, Int32OperandId indexId, + StringCharOutOfBounds outOfBounds) { JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); AutoOutputRegister output(*this); Register str = allocator.useRegister(masm, strId); @@ -1582,15 +1582,21 @@ bool IonCacheIRCompiler::emitLoadStringCharResult(StringOperandId strId, // Bounds check, load string char. Label done; + Label tagResult; Label loadFailed; - if (!handleOOB) { + if (outOfBounds == StringCharOutOfBounds::Failure) { masm.spectreBoundsCheck32(index, Address(str, JSString::offsetOfLength()), scratch1, failure->label()); masm.loadStringChar(str, index, scratch1, scratch2, scratch3, failure->label()); } else { - // Return the empty string for out-of-bounds access. - masm.movePtr(ImmGCPtr(cx_->runtime()->emptyString), scratch2); + if (outOfBounds == StringCharOutOfBounds::EmptyString) { + // Return the empty string for out-of-bounds access. + masm.movePtr(ImmGCPtr(cx_->runtime()->emptyString), scratch2); + } else { + // Return |undefined| for out-of-bounds access. + masm.moveValue(UndefinedValue(), output.valueReg()); + } // This CacheIR op is always preceded by |LinearizeForCharAccess|, so we're // guaranteed to see no nested ropes. @@ -1602,9 +1608,9 @@ bool IonCacheIRCompiler::emitLoadStringCharResult(StringOperandId strId, // Load StaticString for this char. For larger code units perform a VM call. Label vmCall; masm.lookupStaticString(scratch1, scratch2, cx_->staticStrings(), &vmCall); - masm.jump(&done); + masm.jump(&tagResult); - if (handleOOB) { + if (outOfBounds != StringCharOutOfBounds::Failure) { masm.bind(&loadFailed); masm.assumeUnreachable("loadStringChar can't fail for linear strings"); } @@ -1636,11 +1642,36 @@ bool IonCacheIRCompiler::emitLoadStringCharResult(StringOperandId strId, masm.branchPtr(Assembler::Equal, scratch2, ImmWord(0), failure->label()); } - masm.bind(&done); - masm.tagValue(JSVAL_TYPE_STRING, scratch2, output.valueReg()); + if (outOfBounds != StringCharOutOfBounds::UndefinedValue) { + masm.bind(&tagResult); + masm.bind(&done); + masm.tagValue(JSVAL_TYPE_STRING, scratch2, output.valueReg()); + } else { + masm.bind(&tagResult); + masm.tagValue(JSVAL_TYPE_STRING, scratch2, output.valueReg()); + masm.bind(&done); + } return true; } +bool IonCacheIRCompiler::emitLoadStringCharResult(StringOperandId strId, + Int32OperandId indexId, + bool handleOOB) { + JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); + auto outOfBounds = handleOOB ? StringCharOutOfBounds::EmptyString + : StringCharOutOfBounds::Failure; + return emitLoadStringCharResult(strId, indexId, outOfBounds); +} + +bool IonCacheIRCompiler::emitLoadStringAtResult(StringOperandId strId, + Int32OperandId indexId, + bool handleOOB) { + JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); + auto outOfBounds = handleOOB ? StringCharOutOfBounds::UndefinedValue + : StringCharOutOfBounds::Failure; + return emitLoadStringCharResult(strId, indexId, outOfBounds); +} + bool IonCacheIRCompiler::emitCallNativeSetter(ObjOperandId receiverId, uint32_t setterOffset, ValOperandId rhsId, @@ -2415,9 +2446,3 @@ bool IonCacheIRCompiler::emitRegExpHasCaptureGroupsResult( ObjOperandId regexpId, StringOperandId inputId) { MOZ_CRASH("Call ICs not used in ion"); } - -bool IonCacheIRCompiler::emitLoadStringAtResult(StringOperandId strId, - Int32OperandId indexId, - bool handleOOB) { - MOZ_CRASH("Call ICs not used in ion"); -} diff --git a/js/src/jit/IonCacheIRCompiler.h b/js/src/jit/IonCacheIRCompiler.h @@ -93,6 +93,10 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler { ValOperandId targetId, ObjOperandId receiverId, ObjOperandId handlerId, ObjOperandId trapId, IdType id, uint32_t nargsAndFlags); + enum class StringCharOutOfBounds { Failure, EmptyString, UndefinedValue }; + bool emitLoadStringCharResult(StringOperandId strId, Int32OperandId indexId, + StringCharOutOfBounds outOfBounds); + void pushStubCodePointer(); CACHE_IR_COMPILER_UNSHARED_GENERATED