diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
commit | 40a355a42d4a9444dc753c04c6608dade2f06a23 (patch) | |
tree | 871fc667d2de662f171103ce5ec067014ef85e61 /js/src/jit/MacroAssembler.cpp | |
parent | Adding upstream version 124.0.1. (diff) | |
download | firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.tar.xz firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.zip |
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit/MacroAssembler.cpp')
-rw-r--r-- | js/src/jit/MacroAssembler.cpp | 255 |
1 files changed, 244 insertions, 11 deletions
diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 54da676014..3b094d49dc 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -2661,6 +2661,7 @@ void MacroAssembler::loadMegamorphicSetPropCache(Register dest) { void MacroAssembler::lookupStringInAtomCacheLastLookups(Register str, Register scratch, + Register output, Label* fail) { Label found; @@ -2680,7 +2681,7 @@ void MacroAssembler::lookupStringInAtomCacheLastLookups(Register str, // and jump back up to our usual atom handling code bind(&found); size_t atomOffset = StringToAtomCache::LastLookup::offsetOfAtom(); - loadPtr(Address(scratch, atomOffset), str); + loadPtr(Address(scratch, atomOffset), output); } void MacroAssembler::loadAtomHash(Register id, Register outHash, Label* done) { @@ -2740,7 +2741,7 @@ void MacroAssembler::loadAtomOrSymbolAndHash(ValueOperand value, Register outId, loadAtomHash(outId, outHash, &done); bind(&nonAtom); - lookupStringInAtomCacheLastLookups(outId, outHash, cacheMiss); + lookupStringInAtomCacheLastLookups(outId, outHash, outId, cacheMiss); jump(&atom); bind(&done); @@ -3255,6 +3256,95 @@ void MacroAssembler::loadArrayBufferViewLengthIntPtr(Register obj, loadPrivate(slotAddr, output); } +void MacroAssembler::loadGrowableSharedArrayBufferByteLengthIntPtr( + Synchronization sync, Register obj, Register output) { + // Load the SharedArrayRawBuffer. + loadPrivate(Address(obj, SharedArrayBufferObject::rawBufferOffset()), output); + + memoryBarrierBefore(sync); + + // Load the byteLength of the SharedArrayRawBuffer into |output|. + static_assert(sizeof(mozilla::Atomic<size_t>) == sizeof(size_t)); + loadPtr(Address(output, SharedArrayRawBuffer::offsetOfByteLength()), output); + + memoryBarrierAfter(sync); +} + +void MacroAssembler::loadResizableArrayBufferViewLengthIntPtr( + ResizableArrayBufferView view, Synchronization sync, Register obj, + Register output, Register scratch) { + // Inline implementation of ArrayBufferViewObject::length(), when the input is + // guaranteed to be a resizable arraybuffer view object. + + loadArrayBufferViewLengthIntPtr(obj, output); + + Label done; + branchPtr(Assembler::NotEqual, output, ImmWord(0), &done); + + // Load obj->elements in |scratch|. + loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch); + + // If backed by non-shared memory, detached and out-of-bounds both return + // zero, so we're done here. + branchTest32(Assembler::Zero, + Address(scratch, ObjectElements::offsetOfFlags()), + Imm32(ObjectElements::SHARED_MEMORY), &done); + + // Load the auto-length slot. + unboxBoolean(Address(obj, ArrayBufferViewObject::autoLengthOffset()), + scratch); + + // If non-auto length, there's nothing to do. + branchTest32(Assembler::Zero, scratch, scratch, &done); + + // Load bufferByteLength into |output|. + { + // Resizable TypedArrays are guaranteed to have an ArrayBuffer. + unboxObject(Address(obj, ArrayBufferViewObject::bufferOffset()), output); + + // Load the byte length from the raw-buffer of growable SharedArrayBuffers. + loadGrowableSharedArrayBufferByteLengthIntPtr(sync, output, output); + } + + // Load the byteOffset into |scratch|. + loadArrayBufferViewByteOffsetIntPtr(obj, scratch); + + // Compute the accessible byte length |bufferByteLength - byteOffset|. + subPtr(scratch, output); + + if (view == ResizableArrayBufferView::TypedArray) { + // Compute the array length from the byte length. + resizableTypedArrayElementShiftBy(obj, output, scratch); + } + + bind(&done); +} + +void MacroAssembler::loadResizableTypedArrayByteOffsetMaybeOutOfBoundsIntPtr( + Register obj, Register output, Register scratch) { + // Inline implementation of TypedArrayObject::byteOffsetMaybeOutOfBounds(), + // when the input is guaranteed to be a resizable typed array object. + + loadArrayBufferViewByteOffsetIntPtr(obj, output); + + // TypedArray is neither detached nor out-of-bounds when byteOffset non-zero. + Label done; + branchPtr(Assembler::NotEqual, output, ImmWord(0), &done); + + // We're done when the initial byteOffset is zero. + loadPrivate(Address(obj, ArrayBufferViewObject::initialByteOffsetOffset()), + output); + branchPtr(Assembler::Equal, output, ImmWord(0), &done); + + // If the buffer is attached, return initialByteOffset. + branchIfHasAttachedArrayBuffer(obj, scratch, &done); + + // Otherwise return zero to match the result for fixed-length TypedArrays. + movePtr(ImmWord(0), output); + + bind(&done); +} + void MacroAssembler::loadDOMExpandoValueGuardGeneration( Register obj, ValueOperand output, JS::ExpandoAndGeneration* expandoAndGeneration, uint64_t generation, @@ -7433,11 +7523,11 @@ void MacroAssembler::debugAssertCanonicalInt32(Register r) { } #endif -void MacroAssembler::memoryBarrierBefore(const Synchronization& sync) { +void MacroAssembler::memoryBarrierBefore(Synchronization sync) { memoryBarrier(sync.barrierBefore); } -void MacroAssembler::memoryBarrierAfter(const Synchronization& sync) { +void MacroAssembler::memoryBarrierAfter(Synchronization sync) { memoryBarrier(sync.barrierAfter); } @@ -7834,6 +7924,74 @@ void MacroAssembler::typedArrayElementSize(Register obj, Register output) { bind(&done); } +void MacroAssembler::resizableTypedArrayElementShiftBy(Register obj, + Register output, + Register scratch) { + loadObjClassUnsafe(obj, scratch); + +#ifdef DEBUG + Label invalidClass, validClass; + branchPtr(Assembler::Below, scratch, + ImmPtr(std::begin(TypedArrayObject::resizableClasses)), + &invalidClass); + branchPtr(Assembler::Below, scratch, + ImmPtr(std::end(TypedArrayObject::resizableClasses)), &validClass); + bind(&invalidClass); + assumeUnreachable("value isn't a valid ResizableLengthTypedArray class"); + bind(&validClass); +#endif + + auto classForType = [](Scalar::Type type) { + MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType); + return &TypedArrayObject::resizableClasses[type]; + }; + + Label zero, one, two, three; + + static_assert(ValidateSizeRange(Scalar::Int8, Scalar::Int16), + "element shift is zero in [Int8, Int16)"); + branchPtr(Assembler::Below, scratch, ImmPtr(classForType(Scalar::Int16)), + &zero); + + static_assert(ValidateSizeRange(Scalar::Int16, Scalar::Int32), + "element shift is one in [Int16, Int32)"); + branchPtr(Assembler::Below, scratch, ImmPtr(classForType(Scalar::Int32)), + &one); + + static_assert(ValidateSizeRange(Scalar::Int32, Scalar::Float64), + "element shift is two in [Int32, Float64)"); + branchPtr(Assembler::Below, scratch, ImmPtr(classForType(Scalar::Float64)), + &two); + + static_assert(ValidateSizeRange(Scalar::Float64, Scalar::Uint8Clamped), + "element shift is three in [Float64, Uint8Clamped)"); + branchPtr(Assembler::Below, scratch, + ImmPtr(classForType(Scalar::Uint8Clamped)), &three); + + static_assert(ValidateSizeRange(Scalar::Uint8Clamped, Scalar::BigInt64), + "element shift is zero in [Uint8Clamped, BigInt64)"); + branchPtr(Assembler::Below, scratch, ImmPtr(classForType(Scalar::BigInt64)), + &zero); + + static_assert( + ValidateSizeRange(Scalar::BigInt64, Scalar::MaxTypedArrayViewType), + "element shift is three in [BigInt64, MaxTypedArrayViewType)"); + // Fall through for BigInt64 and BigUint64 + + bind(&three); + rshiftPtr(Imm32(3), output); + jump(&zero); + + bind(&two); + rshiftPtr(Imm32(2), output); + jump(&zero); + + bind(&one); + rshiftPtr(Imm32(1), output); + + bind(&zero); +} + void MacroAssembler::branchIfClassIsNotTypedArray(Register clasp, Label* notTypedArray) { // Inline implementation of IsTypedArrayClass(). @@ -7867,28 +8025,103 @@ void MacroAssembler::branchIfClassIsNotFixedLengthTypedArray( notTypedArray); } -void MacroAssembler::branchIfHasDetachedArrayBuffer(Register obj, Register temp, +void MacroAssembler::branchIfClassIsNotResizableTypedArray( + Register clasp, Label* notTypedArray) { + // Inline implementation of IsResizableTypedArrayClass(). + + const auto* firstTypedArrayClass = + std::begin(TypedArrayObject::resizableClasses); + const auto* lastTypedArrayClass = + std::prev(std::end(TypedArrayObject::resizableClasses)); + + branchPtr(Assembler::Below, clasp, ImmPtr(firstTypedArrayClass), + notTypedArray); + branchPtr(Assembler::Above, clasp, ImmPtr(lastTypedArrayClass), + notTypedArray); +} + +void MacroAssembler::branchIfHasDetachedArrayBuffer(BranchIfDetached branchIf, + Register obj, Register temp, Label* label) { // Inline implementation of ArrayBufferViewObject::hasDetachedBuffer(). + // TODO: The data-slot of detached views is set to undefined, which would be + // a faster way to detect detached buffers. + + // auto cond = branchIf == BranchIfDetached::Yes ? Assembler::Equal + // : Assembler::NotEqual; + // branchTestUndefined(cond, Address(obj, + // ArrayBufferViewObject::dataOffset()), label); + + Label done; + Label* ifNotDetached = branchIf == BranchIfDetached::Yes ? &done : label; + Condition detachedCond = + branchIf == BranchIfDetached::Yes ? Assembler::NonZero : Assembler::Zero; + // Load obj->elements in temp. loadPtr(Address(obj, NativeObject::offsetOfElements()), temp); // Shared buffers can't be detached. - Label done; branchTest32(Assembler::NonZero, Address(temp, ObjectElements::offsetOfFlags()), - Imm32(ObjectElements::SHARED_MEMORY), &done); + Imm32(ObjectElements::SHARED_MEMORY), ifNotDetached); // An ArrayBufferView with a null/true buffer has never had its buffer // exposed, so nothing can possibly detach it. fallibleUnboxObject(Address(obj, ArrayBufferViewObject::bufferOffset()), temp, - &done); + ifNotDetached); - // Load the ArrayBuffer flags and branch if the detached flag is set. + // Load the ArrayBuffer flags and branch if the detached flag is (not) set. unboxInt32(Address(temp, ArrayBufferObject::offsetOfFlagsSlot()), temp); - branchTest32(Assembler::NonZero, temp, Imm32(ArrayBufferObject::DETACHED), - label); + branchTest32(detachedCond, temp, Imm32(ArrayBufferObject::DETACHED), label); + + if (branchIf == BranchIfDetached::Yes) { + bind(&done); + } +} + +void MacroAssembler::branchIfResizableArrayBufferViewOutOfBounds(Register obj, + Register temp, + Label* label) { + // Implementation of ArrayBufferViewObject::isOutOfBounds(). + + Label done; + + loadArrayBufferViewLengthIntPtr(obj, temp); + branchPtr(Assembler::NotEqual, temp, ImmWord(0), &done); + + loadArrayBufferViewByteOffsetIntPtr(obj, temp); + branchPtr(Assembler::NotEqual, temp, ImmWord(0), &done); + + loadPrivate(Address(obj, ArrayBufferViewObject::initialLengthOffset()), temp); + branchPtr(Assembler::NotEqual, temp, ImmWord(0), label); + + loadPrivate(Address(obj, ArrayBufferViewObject::initialByteOffsetOffset()), + temp); + branchPtr(Assembler::NotEqual, temp, ImmWord(0), label); + + bind(&done); +} + +void MacroAssembler::branchIfResizableArrayBufferViewInBounds(Register obj, + Register temp, + Label* label) { + // Implementation of ArrayBufferViewObject::isOutOfBounds(). + + Label done; + + loadArrayBufferViewLengthIntPtr(obj, temp); + branchPtr(Assembler::NotEqual, temp, ImmWord(0), label); + + loadArrayBufferViewByteOffsetIntPtr(obj, temp); + branchPtr(Assembler::NotEqual, temp, ImmWord(0), label); + + loadPrivate(Address(obj, ArrayBufferViewObject::initialLengthOffset()), temp); + branchPtr(Assembler::NotEqual, temp, ImmWord(0), &done); + + loadPrivate(Address(obj, ArrayBufferViewObject::initialByteOffsetOffset()), + temp); + branchPtr(Assembler::Equal, temp, ImmWord(0), label); bind(&done); } |