summaryrefslogtreecommitdiffstats
path: root/js/src/jit/MacroAssembler.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
commit40a355a42d4a9444dc753c04c6608dade2f06a23 (patch)
tree871fc667d2de662f171103ce5ec067014ef85e61 /js/src/jit/MacroAssembler.cpp
parentAdding upstream version 124.0.1. (diff)
downloadfirefox-upstream/125.0.1.tar.xz
firefox-upstream/125.0.1.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.cpp255
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);
}