Skip to content

Commit f0f45f1

Browse files
committed
[JSC] TypedArraySet intrinsic should not be used again after an Uncountable exit
https://bugs.webkit.org/post_bug.cgi Reviewed by Yusuke Suzuki. When the offset is not Int32 in the graph (e.g. a value loaded from a Float64Array, or a constant undefined), Int32Use on TypedArraySet exits unconditionally with Uncountable. The same happens for CellUse when the source is proven not to be a cell. The parser did not check this exit kind, so every recompilation picked the intrinsic again and kept exiting. This patch checks Uncountable exit sites too, as CharCodeAt does. Test: JSTests/stress/typed-array-set-intrinsic-non-int32-argument.js * JSTests/stress/typed-array-set-intrinsic-non-int32-argument.js: Added. (shouldBe): (makeSet.const.set new): (makeSet): * Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::handleIntrinsicCall): Canonical link: https://commits.webkit.org/323905@main
1 parent 1411a8e commit f0f45f1

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//@ skip if not $jitTests
2+
//@ $skipModes << :lockdown
3+
4+
function shouldBe(actual, expected) {
5+
if (actual !== expected)
6+
throw new Error(`expected ${expected} but got ${actual}`);
7+
}
8+
9+
let functionCount = 0;
10+
11+
function makeSet(body) {
12+
const set = new Function("target", "source", "values", "i", `${body} // ${functionCount++}`);
13+
noInline(set);
14+
return set;
15+
}
16+
17+
function test(body, values, expectedOffset) {
18+
const set = makeSet(body);
19+
const source = new Uint8Array(3);
20+
const target = new Uint8Array(16);
21+
for (let i = 0; i < testLoopCount * 10; i++) {
22+
source[0] = i;
23+
source[2] = i + 2;
24+
set(target, source, values, i);
25+
const offset = expectedOffset(i);
26+
shouldBe(target[offset], i & 0xff);
27+
shouldBe(target[offset + 2], (i + 2) & 0xff);
28+
}
29+
shouldBe(numberOfDFGCompiles(set) <= 3, true);
30+
}
31+
32+
function testNumberSource(body, values) {
33+
const set = makeSet(body);
34+
const target = new Uint8Array(16);
35+
for (let i = 0; i < testLoopCount * 10; i++) {
36+
set(target, null, values, i);
37+
shouldBe(target[i & 15], 0);
38+
}
39+
shouldBe(numberOfDFGCompiles(set) <= 3, true);
40+
}
41+
42+
const doubles = new Float64Array([0, 1, 2, 3, 4, 5, 6, 7]);
43+
44+
test("target.set(source, values[i & 7]);", doubles, i => i & 7);
45+
test("target.set(source, (i & 7) * 0.5);", null, i => (i & 7) >> 1);
46+
test("for (let j = 0.5; j < 2; j++) target.set(source, j);", null, i => 1);
47+
test("target.set(source, undefined);", null, i => 0);
48+
test("target.set(source, null);", null, i => 0);
49+
test("target.set(source, 1.5);", null, i => 1);
50+
test("target.set(source, '2');", null, i => 2);
51+
testNumberSource("target.set(values[i & 7], 0);", doubles);
52+
testNumberSource("target.set(42, 0);", null);

‎Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3150,6 +3150,7 @@ auto ByteCodeParser::handleIntrinsicCall(Node* callee, Operand resultOperand, Ca
31503150

31513151
if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType)
31523152
|| m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)
3153+
|| m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Uncountable)
31533154
|| m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, OutOfBounds)
31543155
|| m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, UnexpectedResizableArrayBufferView))
31553156
return CallOptimizationResult::DidNothing;

0 commit comments

Comments
 (0)