Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 2e1efe6

Browse files
committed
Bug 1966355 - Part 16: Update CacheIR for immutable typed arrays. r=spidermonkey-reviewers,jandem
Differential Revision: https://phabricator.services.mozilla.com/D249409
1 parent 23a85b6 commit 2e1efe6

10 files changed

Lines changed: 291 additions & 4 deletions
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// |jit-test| --enable-arraybuffer-immutable; skip-if: !ArrayBuffer.prototype.transferToImmutable
2+
3+
function testImmutableArrayBuffer() {
4+
for (let i = 0; i < 4; ++i) {
5+
let ab = new ArrayBuffer(i).transferToImmutable();
6+
let ta = new Int8Array(ab, 0, i);
7+
for (let j = 0; j < 100; ++j) {
8+
assertEq(ta.byteLength, i);
9+
}
10+
}
11+
}
12+
for (let i = 0; i < 2; ++i) testImmutableArrayBuffer();
13+
14+
function testImmutableArrayBufferDefaultLength() {
15+
for (let i = 0; i < 4; ++i) {
16+
let ab = new ArrayBuffer(i).transferToImmutable();
17+
let ta = new Int8Array(ab);
18+
for (let j = 0; j < 100; ++j) {
19+
assertEq(ta.byteLength, i);
20+
}
21+
}
22+
}
23+
for (let i = 0; i < 2; ++i) testImmutableArrayBufferDefaultLength();
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// |jit-test| --enable-arraybuffer-immutable; skip-if: !ArrayBuffer.prototype.transferToImmutable
2+
3+
function testImmutableArrayBufferDefaultLength() {
4+
for (let i = 0; i < 4; ++i) {
5+
let ab = new ArrayBuffer(i).transferToImmutable();
6+
let ta = new Int8Array(ab);
7+
for (let j = 0; j < 100; ++j) {
8+
assertEq(ta.byteOffset, 0);
9+
}
10+
}
11+
}
12+
for (let i = 0; i < 2; ++i) testImmutableArrayBufferDefaultLength();
13+
14+
function testImmutableArrayBufferDefaultLengthNonZeroOffset() {
15+
for (let i = 1; i < 4 + 1; ++i) {
16+
let ab = new ArrayBuffer(i).transferToImmutable();
17+
let ta = new Int8Array(ab, 1);
18+
for (let j = 0; j < 100; ++j) {
19+
assertEq(ta.byteOffset, 1);
20+
}
21+
}
22+
}
23+
for (let i = 0; i < 2; ++i) testImmutableArrayBufferDefaultLengthNonZeroOffset();
24+
25+
function testImmutableArrayBufferNonZeroOffset() {
26+
for (let i = 2; i < 4 + 2; ++i) {
27+
let ab = new ArrayBuffer(i).transferToImmutable();
28+
let ta = new Int8Array(ab, 1, 1);
29+
for (let j = 0; j < 100; ++j) {
30+
assertEq(ta.byteOffset, 1);
31+
}
32+
}
33+
}
34+
for (let i = 0; i < 2; ++i) testImmutableArrayBufferNonZeroOffset();
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// |jit-test| --enable-arraybuffer-immutable; skip-if: !ArrayBuffer.prototype.transferToImmutable
2+
3+
const TypedArrays = [
4+
Int8Array,
5+
Uint8Array,
6+
Int16Array,
7+
Uint16Array,
8+
Int32Array,
9+
Uint32Array,
10+
Uint8ClampedArray,
11+
Float16Array,
12+
Float32Array,
13+
Float64Array,
14+
BigInt64Array,
15+
BigUint64Array,
16+
];
17+
18+
function test(TA) {
19+
const length = 4;
20+
21+
let expected = new TA(length);
22+
let type = expected[0].constructor;
23+
24+
for (let i = 0; i < length; ++i) {
25+
expected[i] = type(i * i);
26+
}
27+
28+
let actual = new TA(expected.buffer.sliceToImmutable());
29+
assertEq(actual.buffer.immutable, true);
30+
31+
// In-bounds access
32+
for (let i = 0; i < 200; ++i) {
33+
let index = i % length;
34+
assertEq(actual[index], expected[index]);
35+
}
36+
37+
// Out-of-bounds access
38+
for (let i = 0; i < 200; ++i) {
39+
let index = i % (length + 4);
40+
assertEq(actual[index], expected[index]);
41+
}
42+
}
43+
44+
for (let TA of TypedArrays) {
45+
// Copy test function to ensure monomorphic ICs.
46+
let copy = Function(`return ${test}`)();
47+
48+
copy(TA);
49+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// |jit-test| --enable-arraybuffer-immutable; skip-if: !ArrayBuffer.prototype.transferToImmutable
2+
3+
const TypedArrays = [
4+
Int8Array,
5+
Uint8Array,
6+
Int16Array,
7+
Uint16Array,
8+
Int32Array,
9+
Uint32Array,
10+
Uint8ClampedArray,
11+
Float16Array,
12+
Float32Array,
13+
Float64Array,
14+
BigInt64Array,
15+
BigUint64Array,
16+
];
17+
18+
function test(TA) {
19+
const length = 4;
20+
const byteLength = length * TA.BYTES_PER_ELEMENT;
21+
22+
let iab = new ArrayBuffer(byteLength).transferToImmutable();
23+
let actual = new TA(iab);
24+
let expected = new TA(length);
25+
26+
for (let i = 0; i < 200; ++i) {
27+
let index = (i % (length + 4));
28+
assertEq(index in actual, index in expected);
29+
}
30+
}
31+
32+
for (let TA of TypedArrays) {
33+
// Copy test function to ensure monomorphic ICs.
34+
let copy = Function(`return ${test}`)();
35+
36+
copy(TA);
37+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// |jit-test| --enable-arraybuffer-immutable; skip-if: !ArrayBuffer.prototype.transferToImmutable
2+
3+
const TypedArrayByteOffset = getSelfHostedValue("TypedArrayByteOffset");
4+
5+
function testTypedArrayByteOffset() {
6+
let ab = new ArrayBuffer(100).transferToImmutable();
7+
let typedArrays = [
8+
new Int8Array(ab),
9+
new Int8Array(ab, 1),
10+
new Int8Array(ab, 2),
11+
new Int8Array(ab, 3),
12+
];
13+
14+
for (let i = 0; i < 200; ++i) {
15+
let ta = typedArrays[i & 3];
16+
assertEq(TypedArrayByteOffset(ta), i & 3);
17+
}
18+
}
19+
testTypedArrayByteOffset();
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// |jit-test| --enable-arraybuffer-immutable; skip-if: !ArrayBuffer.prototype.transferToImmutable
2+
3+
load(libdir + "asserts.js");
4+
5+
const TypedArrayLength = getSelfHostedValue("TypedArrayLength");
6+
7+
function testTypedArrayLength() {
8+
let ab = new ArrayBuffer(100).transferToImmutable();
9+
let typedArrays = [
10+
new Int8Array(ab),
11+
new Int8Array(ab, 1),
12+
new Int8Array(ab, 2),
13+
new Int8Array(ab, 3),
14+
];
15+
16+
for (let i = 0; i < 200; ++i) {
17+
let ta = typedArrays[i & 3];
18+
assertEq(TypedArrayLength(ta), 100 - (i & 3));
19+
}
20+
}
21+
testTypedArrayLength();
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// |jit-test| --enable-arraybuffer-immutable; skip-if: !ArrayBuffer.prototype.transferToImmutable
2+
3+
load(libdir + "asserts.js");
4+
5+
const TypedArrayLengthZeroOnOutOfBounds = getSelfHostedValue("TypedArrayLengthZeroOnOutOfBounds");
6+
7+
function testTypedArrayLength() {
8+
let ab = new ArrayBuffer(100).transferToImmutable();
9+
let typedArrays = [
10+
new Int8Array(ab),
11+
new Int8Array(ab, 1),
12+
new Int8Array(ab, 2),
13+
new Int8Array(ab, 3),
14+
];
15+
16+
for (let i = 0; i < 200; ++i) {
17+
let ta = typedArrays[i & 3];
18+
assertEq(TypedArrayLengthZeroOnOutOfBounds(ta), 100 - (i & 3));
19+
}
20+
}
21+
testTypedArrayLength();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// |jit-test| --enable-arraybuffer-immutable; skip-if: !ArrayBuffer.prototype.transferToImmutable
2+
3+
function testImmutableArrayBuffer() {
4+
for (let i = 0; i < 4; ++i) {
5+
let ab = new ArrayBuffer(i).transferToImmutable();
6+
let ta = new Int8Array(ab, 0, i);
7+
for (let j = 0; j < 100; ++j) {
8+
assertEq(ta.length, i);
9+
}
10+
}
11+
}
12+
for (let i = 0; i < 2; ++i) testImmutableArrayBuffer();
13+
14+
function testImmutableArrayBufferDefaultLength() {
15+
for (let i = 0; i < 4; ++i) {
16+
let ab = new ArrayBuffer(i).transferToImmutable();
17+
let ta = new Int8Array(ab);
18+
for (let j = 0; j < 100; ++j) {
19+
assertEq(ta.length, i);
20+
}
21+
}
22+
}
23+
for (let i = 0; i < 2; ++i) testImmutableArrayBufferDefaultLength();
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// |jit-test| --enable-arraybuffer-immutable; skip-if: !ArrayBuffer.prototype.transferToImmutable
2+
3+
const TypedArrays = [
4+
Int8Array,
5+
Uint8Array,
6+
Int16Array,
7+
Uint16Array,
8+
Int32Array,
9+
Uint32Array,
10+
Uint8ClampedArray,
11+
Float16Array,
12+
Float32Array,
13+
Float64Array,
14+
BigInt64Array,
15+
BigUint64Array,
16+
];
17+
18+
function test(TA) {
19+
const length = 4;
20+
const byteLength = length * TA.BYTES_PER_ELEMENT;
21+
22+
let iab = new ArrayBuffer(byteLength).transferToImmutable();
23+
let actual = new TA(iab);
24+
let expected = new TA(length);
25+
let type = expected[0].constructor;
26+
27+
// In-bounds access
28+
for (let i = 0; i < 200; ++i) {
29+
let index = i % length;
30+
31+
actual[index] = type(i);
32+
33+
assertEq(actual[index], expected[index]);
34+
}
35+
36+
// Out-of-bounds access
37+
for (let i = 0; i < 200; ++i) {
38+
let index = i % (length + 4);
39+
40+
actual[index] = type(i);
41+
42+
assertEq(actual[index], expected[index]);
43+
}
44+
}
45+
46+
for (let TA of TypedArrays) {
47+
// Copy test function to ensure monomorphic ICs.
48+
let copy = Function(`return ${test}`)();
49+
50+
copy(TA);
51+
}

js/src/jit/CacheIR.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,7 +2254,7 @@ AttachDecision GetPropIRGenerator::tryAttachTypedArray(HandleObject obj,
22542254
EmitCallGetterResultGuards(writer, tarr, holder, id, *prop, objId, mode_);
22552255
if (isLength) {
22562256
size_t length = tarr->length().valueOr(0);
2257-
if (tarr->is<FixedLengthTypedArrayObject>()) {
2257+
if (!tarr->is<ResizableTypedArrayObject>()) {
22582258
if (length <= INT32_MAX) {
22592259
writer.loadArrayBufferViewLengthInt32Result(objId);
22602260
} else {
@@ -2280,7 +2280,7 @@ AttachDecision GetPropIRGenerator::tryAttachTypedArray(HandleObject obj,
22802280
trackAttached("GetProp.TypedArrayByteOffset");
22812281
} else {
22822282
size_t byteLength = tarr->byteLength().valueOr(0);
2283-
if (tarr->is<FixedLengthTypedArrayObject>()) {
2283+
if (!tarr->is<ResizableTypedArrayObject>()) {
22842284
if (byteLength <= INT32_MAX) {
22852285
writer.typedArrayByteLengthInt32Result(objId);
22862286
} else {
@@ -3261,6 +3261,10 @@ static ArrayBufferViewKind ToArrayBufferViewKind(const TypedArrayObject* obj) {
32613261
return ArrayBufferViewKind::FixedLength;
32623262
}
32633263

3264+
if (obj->is<ImmutableTypedArrayObject>()) {
3265+
return ArrayBufferViewKind::Immutable;
3266+
}
3267+
32643268
MOZ_ASSERT(obj->is<ResizableTypedArrayObject>());
32653269
return ArrayBufferViewKind::Resizable;
32663270
}
@@ -5219,6 +5223,11 @@ AttachDecision SetPropIRGenerator::tryAttachSetTypedArrayElement(
52195223
auto* tarr = &obj->as<TypedArrayObject>();
52205224
Scalar::Type elementType = tarr->type();
52215225

5226+
// Immutable TypedArrays can't be modified.
5227+
if (tarr->is<ImmutableTypedArrayObject>()) {
5228+
return AttachDecision::NoAction;
5229+
}
5230+
52225231
// Don't attach if the input type doesn't match the guard added below.
52235232
if (!ValueCanConvertToNumeric(elementType, rhsVal_)) {
52245233
return AttachDecision::NoAction;
@@ -11063,7 +11072,7 @@ AttachDecision InlinableNativeIRGenerator::tryAttachTypedArrayByteOffset() {
1106311072
EmitGuardTypedArray(writer, tarr, objArgId);
1106411073

1106511074
size_t byteOffset = tarr->byteOffsetMaybeOutOfBounds();
11066-
if (tarr->is<FixedLengthTypedArrayObject>()) {
11075+
if (!tarr->is<ResizableTypedArrayObject>()) {
1106711076
if (byteOffset <= INT32_MAX) {
1106811077
writer.arrayBufferViewByteOffsetInt32Result(objArgId);
1106911078
} else {
@@ -11146,7 +11155,7 @@ AttachDecision InlinableNativeIRGenerator::tryAttachTypedArrayLength(
1114611155

1114711156
EmitGuardTypedArray(writer, tarr, objArgId);
1114811157

11149-
if (tarr->is<FixedLengthTypedArrayObject>()) {
11158+
if (!tarr->is<ResizableTypedArrayObject>()) {
1115011159
if (length.valueOr(0) <= INT32_MAX) {
1115111160
writer.loadArrayBufferViewLengthInt32Result(objArgId);
1115211161
} else {

0 commit comments

Comments
 (0)