From b8bd87e7c42dcf79257b309bb6b5f67528ca5739 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20Bargull?= Date: Tue, 27 Feb 2024 13:27:53 +0000 Subject: [PATCH] Bug 1842999 - Part 26: Support storing elements into resizable TypedArrays. r=jandem Differential Revision: https://phabricator.services.mozilla.com/D200666 --- .../resizable-typedarray-set-elem-with-sab.js | 54 ++++++++++++++++++++++ .../typedarray/resizable-typedarray-set-elem.js | 54 ++++++++++++++++++++++ js/src/jit/CacheIR.cpp | 10 ++-- js/src/jit/CacheIRCompiler.cpp | 14 +++--- js/src/jit/CacheIROps.yaml | 1 + js/src/jit/WarpCacheIRTranspiler.cpp | 11 ++--- 6 files changed, 125 insertions(+), 19 deletions(-) create mode 100644 js/src/jit-test/tests/typedarray/resizable-typedarray-set-elem-with-sab.js create mode 100644 js/src/jit-test/tests/typedarray/resizable-typedarray-set-elem.js diff --git a/js/src/jit-test/tests/typedarray/resizable-typedarray-set-elem-with-sab.js b/js/src/jit-test/tests/typedarray/resizable-typedarray-set-elem-with-sab.js new file mode 100644 index 000000000000..67a15e77147e --- /dev/null +++ b/js/src/jit-test/tests/typedarray/resizable-typedarray-set-elem-with-sab.js @@ -0,0 +1,54 @@ +// |jit-test| --enable-arraybuffer-resizable; skip-if: !ArrayBuffer.prototype.resize||!this.SharedArrayBuffer + +const TypedArrays = [ + Int8Array, + Uint8Array, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Uint8ClampedArray, + Float32Array, + Float64Array, + BigInt64Array, + BigUint64Array, +]; + +function test(TA) { + const length = 4; + const byteLength = length * TA.BYTES_PER_ELEMENT; + + let rab = new SharedArrayBuffer(byteLength, {maxByteLength: byteLength}); + let actual = new TA(rab); + let expected = new TA(length); + let type = expected[0].constructor; + + // In-bounds access + for (let i = 0; i < 200; ++i) { + let index = i % length; + + let v = type(i); + actual[index] = v; + expected[index] = v; + + assertEq(actual[index], expected[index]); + } + + // Out-of-bounds access + for (let i = 0; i < 200; ++i) { + let index = i % (length + 4); + + let v = type(i); + actual[index] = v; + expected[index] = v; + + assertEq(actual[index], expected[index]); + } +} + +for (let TA of TypedArrays) { + // Copy test function to ensure monomorphic ICs. + let copy = Function(`return ${test}`)(); + + copy(TA); +} diff --git a/js/src/jit-test/tests/typedarray/resizable-typedarray-set-elem.js b/js/src/jit-test/tests/typedarray/resizable-typedarray-set-elem.js new file mode 100644 index 000000000000..91f5c7b048d6 --- /dev/null +++ b/js/src/jit-test/tests/typedarray/resizable-typedarray-set-elem.js @@ -0,0 +1,54 @@ +// |jit-test| --enable-arraybuffer-resizable; skip-if: !ArrayBuffer.prototype.resize + +const TypedArrays = [ + Int8Array, + Uint8Array, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Uint8ClampedArray, + Float32Array, + Float64Array, + BigInt64Array, + BigUint64Array, +]; + +function test(TA) { + const length = 4; + const byteLength = length * TA.BYTES_PER_ELEMENT; + + let rab = new ArrayBuffer(byteLength, {maxByteLength: byteLength}); + let actual = new TA(rab); + let expected = new TA(length); + let type = expected[0].constructor; + + // In-bounds access + for (let i = 0; i < 200; ++i) { + let index = i % length; + + let v = type(i); + actual[index] = v; + expected[index] = v; + + assertEq(actual[index], expected[index]); + } + + // Out-of-bounds access + for (let i = 0; i < 200; ++i) { + let index = i % (length + 4); + + let v = type(i); + actual[index] = v; + expected[index] = v; + + assertEq(actual[index], expected[index]); + } +} + +for (let TA of TypedArrays) { + // Copy test function to ensure monomorphic ICs. + let copy = Function(`return ${test}`)(); + + copy(TA); +} diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 4b6bb2e7d7ae..2d1e642fbeaf 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -5031,15 +5031,14 @@ AttachDecision SetPropIRGenerator::tryAttachAddOrUpdateSparseElement( AttachDecision SetPropIRGenerator::tryAttachSetTypedArrayElement( HandleObject obj, ObjOperandId objId, ValOperandId rhsId) { - // TODO: Support resizable typed arrays. (bug 1842999) - if (!obj->is()) { + if (!obj->is()) { return AttachDecision::NoAction; } if (!idVal_.isNumber()) { return AttachDecision::NoAction; } - auto* tarr = &obj->as(); + auto* tarr = &obj->as(); Scalar::Type elementType = tarr->type(); // Don't attach if the input type doesn't match the guard added below. @@ -5050,7 +5049,7 @@ AttachDecision SetPropIRGenerator::tryAttachSetTypedArrayElement( bool handleOOB = false; int64_t indexInt64; if (!ValueIsInt64Index(idVal_, &indexInt64) || indexInt64 < 0 || - uint64_t(indexInt64) >= tarr->length()) { + uint64_t(indexInt64) >= tarr->length().valueOr(0)) { handleOOB = true; } @@ -5071,8 +5070,9 @@ AttachDecision SetPropIRGenerator::tryAttachSetTypedArrayElement( ValOperandId keyId = setElemKeyValueId(); IntPtrOperandId indexId = guardToIntPtrIndex(idVal_, keyId, handleOOB); + auto viewKind = ToArrayBufferViewKind(tarr); writer.storeTypedArrayElement(objId, elementType, indexId, rhsValId, - handleOOB); + handleOOB, viewKind); writer.returnFromIC(); trackAttached(handleOOB ? "SetTypedElementOOB" : "SetTypedElement"); diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp index 97b3959fc8ab..ac46891ac4e8 100644 --- a/js/src/jit/CacheIRCompiler.cpp +++ b/js/src/jit/CacheIRCompiler.cpp @@ -6523,8 +6523,8 @@ bool CacheIRCompiler::emitArrayPush(ObjOperandId objId, ValOperandId rhsId) { bool CacheIRCompiler::emitStoreTypedArrayElement(ObjOperandId objId, Scalar::Type elementType, IntPtrOperandId indexId, - uint32_t rhsId, - bool handleOOB) { + uint32_t rhsId, bool handleOOB, + ArrayBufferViewKind viewKind) { JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); Register obj = allocator.useRegister(masm, objId); Register index = allocator.useRegister(masm, indexId); @@ -6564,7 +6564,8 @@ bool CacheIRCompiler::emitStoreTypedArrayElement(ObjOperandId objId, AutoScratchRegister scratch1(allocator, masm); Maybe scratch2; Maybe spectreScratch; - if (Scalar::isBigIntType(elementType)) { + if (Scalar::isBigIntType(elementType) || + viewKind == ArrayBufferViewKind::Resizable) { scratch2.emplace(allocator, masm); } else { spectreScratch.emplace(allocator, masm); @@ -6579,10 +6580,9 @@ bool CacheIRCompiler::emitStoreTypedArrayElement(ObjOperandId objId, // Bounds check. Label done; - Register spectreTemp = scratch2 ? scratch2->get() : spectreScratch->get(); - masm.loadArrayBufferViewLengthIntPtr(obj, scratch1); - masm.spectreBoundsCheckPtr(index, scratch1, spectreTemp, - handleOOB ? &done : failure->label()); + emitTypedArrayBoundsCheck(viewKind, obj, index, scratch1, scratch2, + spectreScratch, + handleOOB ? &done : failure->label()); // Load the elements vector. masm.loadPtr(Address(obj, ArrayBufferViewObject::dataOffset()), scratch1); diff --git a/js/src/jit/CacheIROps.yaml b/js/src/jit/CacheIROps.yaml index 7eece3773783..8b37fce7ee9a 100644 --- a/js/src/jit/CacheIROps.yaml +++ b/js/src/jit/CacheIROps.yaml @@ -1716,6 +1716,7 @@ index: IntPtrId rhs: RawId handleOOB: BoolImm + viewKind: ArrayBufferViewKindImm - name: AtomicsCompareExchangeResult shared: true diff --git a/js/src/jit/WarpCacheIRTranspiler.cpp b/js/src/jit/WarpCacheIRTranspiler.cpp index c17b118452e5..3531235c6cc7 100644 --- a/js/src/jit/WarpCacheIRTranspiler.cpp +++ b/js/src/jit/WarpCacheIRTranspiler.cpp @@ -2768,17 +2768,14 @@ bool WarpCacheIRTranspiler::emitStoreDenseElementHole(ObjOperandId objId, return resumeAfter(store); } -bool WarpCacheIRTranspiler::emitStoreTypedArrayElement(ObjOperandId objId, - Scalar::Type elementType, - IntPtrOperandId indexId, - uint32_t rhsId, - bool handleOOB) { +bool WarpCacheIRTranspiler::emitStoreTypedArrayElement( + ObjOperandId objId, Scalar::Type elementType, IntPtrOperandId indexId, + uint32_t rhsId, bool handleOOB, ArrayBufferViewKind viewKind) { MDefinition* obj = getOperand(objId); MDefinition* index = getOperand(indexId); MDefinition* rhs = getOperand(ValOperandId(rhsId)); - auto* length = MArrayBufferViewLength::New(alloc(), obj); - add(length); + auto* length = emitTypedArrayLength(viewKind, obj); if (!handleOOB) { // MStoreTypedArrayElementHole does the bounds checking. -- 2.11.4.GIT