Skip to content

Commit 4130297

Browse files
committed
[JSC] Add TypedArray put-by-val fast path in LLInt
https://bugs.webkit.org/show_bug.cgi?id=326248 rdar://189120242 Reviewed by Yijia Huang. This patch adds integer TypedArray put-by-val fast path in LLInt. We have a fast path for get-by-val, but didn't have it in put-by-val, so this patch adds it. Tests: JSTests/stress/put-by-val-detached-typed-array-llint.js JSTests/stress/put-by-val-integer-typed-array-values.js * JSTests/stress/put-by-val-detached-typed-array-llint.js: Added. (shouldBe): (store): * JSTests/stress/put-by-val-integer-typed-array-values.js: Added. (shouldBe): (store): (i): * Source/JavaScriptCore/llint/LowLevelInterpreter.asm: * Source/JavaScriptCore/llint/LowLevelInterpreter64.asm: Canonical link: https://commits.webkit.org/322648@main
1 parent 88b4e9c commit 4130297

4 files changed

Lines changed: 133 additions & 21 deletions

File tree

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@ runDefault("--useJIT=0")
2+
3+
function shouldBe(actual, expected) {
4+
if (!Object.is(actual, expected))
5+
throw new Error('bad value: ' + actual + ' expected: ' + expected);
6+
}
7+
8+
function store(array, index, value) {
9+
array[index] = value;
10+
}
11+
12+
var constructors = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array];
13+
14+
for (var constructor of constructors) {
15+
var array = new constructor(new ArrayBuffer(8 * constructor.BYTES_PER_ELEMENT));
16+
for (var i = 0; i < 100; ++i) {
17+
if (i === 50) {
18+
transferArrayBuffer(array.buffer);
19+
shouldBe(array.length, 0);
20+
}
21+
var index = i & 7;
22+
store(array, index, 1);
23+
shouldBe(array[index], i < 50 ? 1 : undefined);
24+
}
25+
store(array, -1, 1);
26+
store(array, 0x7fffffff, 1);
27+
shouldBe(array.length, 0);
28+
29+
var valueOfCalls = 0;
30+
store(array, 0, { valueOf() { ++valueOfCalls; return 1; } });
31+
shouldBe(valueOfCalls, 1);
32+
shouldBe(array[0], undefined);
33+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
function shouldBe(actual, expected) {
2+
if (!Object.is(actual, expected))
3+
throw new Error('bad value: ' + actual + ' expected: ' + expected);
4+
}
5+
6+
function store(array, index, value) {
7+
array[index] = value;
8+
}
9+
10+
var values = [0, 1, -1, 127, 128, -128, -129, 255, 256, 32767, 32768, -32769, 65535, 65536, 0x7fffffff, -0x80000000, 1.5, -0.5, 300.5, NaN, "7", undefined];
11+
var constructors = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array];
12+
13+
for (var i = 0; i < testLoopCount / 8; ++i) {
14+
var index = i & 3;
15+
for (var constructor of constructors) {
16+
var array = new constructor(4);
17+
var expected = new constructor(4);
18+
for (var value of values) {
19+
store(array, index, value);
20+
Reflect.set(expected, index, value);
21+
shouldBe(array[index], expected[index]);
22+
}
23+
store(array, 4, 42);
24+
shouldBe(array[4], undefined);
25+
store(array, -1, 42);
26+
shouldBe(array[-1], undefined);
27+
}
28+
}
29+
30+
var resizable = new Uint8Array(new ArrayBuffer(4, { maxByteLength: 8 }));
31+
for (var i = 0; i < testLoopCount; ++i) {
32+
store(resizable, i & 3, 300);
33+
shouldBe(resizable[i & 3], 44);
34+
}
35+
resizable.buffer.resize(2);
36+
store(resizable, 3, 1);
37+
shouldBe(resizable[3], undefined);
38+
39+
var detached = new Int16Array(4);
40+
transferArrayBuffer(detached.buffer);
41+
store(detached, 0, 1);
42+
shouldBe(detached[0], undefined);

‎Source/JavaScriptCore/llint/LowLevelInterpreter.asm‎

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,33 +1305,29 @@ macro arrayProfile(offset, cell, metadata, scratch)
13051305
storei scratch, offset + ArrayProfile::m_lastSeenStructureID[metadata]
13061306
end
13071307

1308-
# Note that index is already sign-extended to be a register width.
1309-
macro getByValTypedArray(base, index, finishIntGetByVal, finishDoubleGetByVal, setLargeTypedArray, slowPath)
1310-
# First lets check if we even have a typed array. This lets us do some boilerplate up front.
1308+
# Index must already be sign-extended to register width. On success, t2 holds the array type minus
1309+
# FirstTypedArrayType, vector holds the caged data pointer, and base is clobbered.
1310+
macro loadTypedArrayVector(base, index, typeLimit, setLargeTypedArray, vector, slowPath)
13111311
loadb JSCell::m_type[base], t2
13121312
subi FirstTypedArrayType, t2
1313-
biaeq t2, NumberOfTypedArrayTypesExcludingBigIntArraysAndDataView, slowPath
1314-
1315-
# Sweet, now we know that we have a typed array. Do some basic things now.
1313+
biaeq t2, typeLimit, slowPath
13161314

13171315
btbnz JSArrayBufferView::m_mode[base], (constexpr isResizableOrGrowableSharedMode), slowPath
13181316
if LARGE_TYPED_ARRAYS
13191317
bqaeq index, JSArrayBufferView::m_length[base], slowPath
13201318
bqbeq index, SmallTypedArrayMaxLength, .smallTypedArray
1321-
setLargeTypedArray(t3)
1319+
setLargeTypedArray(vector)
13221320
.smallTypedArray:
13231321
else
13241322
biaeq index, JSArrayBufferView::m_length[base], slowPath
13251323
end
13261324

1327-
loadp JSArrayBufferView::m_vector[base], t3
1328-
# length and scratch are intentionally undefined on this branch because they are not used on other platforms.
1329-
if ARM64E
1330-
const length = t6
1331-
const scratch = t7
1332-
loadq JSArrayBufferView::m_length[base], length
1333-
end
1334-
cagedPrimitive(t3, length, base, scratch)
1325+
loadp JSArrayBufferView::m_vector[base], vector
1326+
cagedPrimitive(vector, base)
1327+
end
1328+
1329+
macro getByValTypedArray(base, index, finishIntGetByVal, finishDoubleGetByVal, setLargeTypedArray, slowPath)
1330+
loadTypedArrayVector(base, index, NumberOfTypedArrayTypesExcludingBigIntArraysAndDataView, setLargeTypedArray, t3, slowPath)
13351331

13361332
# Now bisect through the various types:
13371333
# Int8ArrayType,

‎Source/JavaScriptCore/llint/LowLevelInterpreter64.asm‎

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -534,10 +534,9 @@ macro cagePrimitive(basePtr, mask, ptr, scratch)
534534
end
535535
end
536536

537-
macro cagedPrimitive(ptr, length, scratch, scratch2)
538-
const source = ptr
537+
macro cagedPrimitive(ptr, scratch)
539538
if GIGACAGE_ENABLED
540-
cagePrimitive(GigacageConfig + Gigacage::Config::basePtrs + GigacagePrimitiveBasePtrOffset, constexpr Gigacage::primitiveGigacageMask, source, scratch)
539+
cagePrimitive(GigacageConfig + Gigacage::Config::basePtrs + GigacagePrimitiveBasePtrOffset, constexpr Gigacage::primitiveGigacageMask, ptr, scratch)
541540
end
542541
end
543542

@@ -2025,7 +2024,7 @@ llintOpWithMetadata(op_check_private_brand, OpCheckPrivateBrand, macro (size, ge
20252024
dispatch()
20262025
end)
20272026

2028-
macro putByValOp(opcodeName, opcodeStruct, osrExitPoint)
2027+
macro putByValOp(opcodeName, opcodeStruct, osrExitPoint, typedArrayPutByVal)
20292028
llintOpWithMetadata(op_%opcodeName%, opcodeStruct, macro (size, get, dispatch, metadata, return)
20302029
macro contiguousPutByVal(storeCallback)
20312030
biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .outOfBounds
@@ -2044,6 +2043,12 @@ macro putByValOp(opcodeName, opcodeStruct, osrExitPoint)
20442043
jmp .storeResult
20452044
end
20462045

2046+
macro setLargeTypedArray(scratch)
2047+
loadi %opcodeStruct%::Metadata::m_arrayProfile.m_arrayProfileFlags[t5], scratch
2048+
ori constexpr ArrayProfileFlag::MayBeLargeTypedArray, scratch
2049+
storei scratch, %opcodeStruct%::Metadata::m_arrayProfile.m_arrayProfileFlags[t5]
2050+
end
2051+
20472052
get(m_base, t0)
20482053
loadConstantOrVariableCell(size, t0, t1, .opPutByValSlow)
20492054
move t1, t2
@@ -2093,7 +2098,7 @@ macro putByValOp(opcodeName, opcodeStruct, osrExitPoint)
20932098
end)
20942099

20952100
.opPutByValNotContiguous:
2096-
bineq t2, ArrayStorageShape, .opPutByValSlow
2101+
bineq t2, ArrayStorageShape, .opPutByValNotArrayStorage
20972102
biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t0], .opPutByValOutOfBounds
20982103
btqz ArrayStorage::m_vector[t0, t3, 8], .opPutByValArrayStorageEmpty
20992104
.opPutByValArrayStorageStoreResult:
@@ -2113,6 +2118,9 @@ macro putByValOp(opcodeName, opcodeStruct, osrExitPoint)
21132118
storei t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0]
21142119
jmp .opPutByValArrayStorageStoreResult
21152120

2121+
.opPutByValNotArrayStorage:
2122+
typedArrayPutByVal(size, get, dispatch, setLargeTypedArray, .opPutByValSlow)
2123+
21162124
.opPutByValOutOfBounds:
21172125
loadi %opcodeStruct%::Metadata::m_arrayProfile.m_arrayProfileFlags[t5], t2
21182126
ori constexpr ArrayProfileFlag::OutOfBounds , t2
@@ -2126,16 +2134,49 @@ macro putByValOp(opcodeName, opcodeStruct, osrExitPoint)
21262134
end)
21272135
end
21282136

2137+
# Stores an int32 into an in-bounds element of an integer typed array. Expects the base cell in t1
2138+
# and the sign-extended index in t3.
2139+
macro putByValIntegerTypedArray(size, get, dispatch, setLargeTypedArray, slowPath)
2140+
loadTypedArrayVector(t1, t3, Uint32ArrayType - FirstTypedArrayType + 1, setLargeTypedArray, t0, slowPath)
2141+
2142+
get(m_value, t1)
2143+
loadConstantOrVariableInt32(size, t1, t6, slowPath)
2144+
2145+
bia t2, Uint8ClampedArrayType - FirstTypedArrayType, .aboveUint8ClampedArray
2146+
bineq t2, Uint8ClampedArrayType - FirstTypedArrayType, .store8
2147+
bibeq t6, 255, .store8
2148+
bilt t6, 0, .clampToZero
2149+
move 255, t6
2150+
jmp .store8
2151+
.clampToZero:
2152+
move 0, t6
2153+
.store8:
2154+
storeb t6, [t0, t3]
2155+
dispatch()
2156+
2157+
.aboveUint8ClampedArray:
2158+
bia t2, Uint16ArrayType - FirstTypedArrayType, .store32
2159+
storeh t6, [t0, t3, 2]
2160+
dispatch()
2161+
2162+
.store32:
2163+
storei t6, [t0, t3, 4]
2164+
dispatch()
2165+
end
2166+
21292167
putByValOp(put_by_val, OpPutByVal, macro (size, dispatch)
21302168
.osrReturnPoint:
21312169
getterSetterOSRExitReturnPoint(op_put_by_val, size)
21322170
dispatch()
2133-
end)
2171+
end, putByValIntegerTypedArray)
21342172

2173+
# Defining an indexed property of a typed array has different semantics, so leave it to the slow path.
21352174
putByValOp(put_by_val_direct, OpPutByValDirect, macro (size, dispatch)
21362175
.osrReturnPoint:
21372176
getterSetterOSRExitReturnPoint(op_put_by_val_direct, size)
21382177
dispatch()
2178+
end, macro (size, get, dispatch, setLargeTypedArray, slowPath)
2179+
jmp slowPath
21392180
end)
21402181

21412182
macro llintJumpTrueOrFalseOp(opcodeName, opcodeStruct, miscConditionOp, truthyCellConditionOp)

0 commit comments

Comments
 (0)