Skip to content

Commit 41f15cd

Browse files
Benjamin Poulainwebkit-commit-queue
authored andcommitted
[JSC] Use an inline cache to generate op_negate
https://bugs.webkit.org/show_bug.cgi?id=162371 Patch by Benjamin Poulain <bpoulain@apple.com> on 2016-09-22 Reviewed by Saam Barati. JSTests: * stress/op-negate-inline-cache.js: Added. Source/JavaScriptCore: Use an inline cache to reduce the amount of code required to implement op_negate. For pure integer negate, the generated asm shrinks from 147 bytes to 125 bytes (14%). For double negate, the generated asm shrinks to 130 bytes (11%). The average size on Sunspider is 100bytes, this is due to the op_negates that are never executed and do not generate much. * bytecode/ArithProfile.h: (JSC::ArithProfile::ArithProfile): (JSC::ArithProfile::observeLHS): (JSC::ArithProfile::observeLHSAndRHS): * bytecode/BytecodeList.json: * bytecode/CodeBlock.cpp: (JSC::CodeBlock::addJITNegIC): * bytecode/CodeBlock.h: * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitUnaryOp): * bytecompiler/BytecodeGenerator.h: * bytecompiler/NodesCodegen.cpp: (JSC::UnaryOpNode::emitBytecode): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compileMathIC): * dfg/DFGSpeculativeJIT.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileMathIC): * jit/CCallHelpers.h: (JSC::CCallHelpers::setupArgumentsWithExecState): * jit/JIT.h: * jit/JITArithmetic.cpp: (JSC::JIT::emit_op_negate): (JSC::JIT::emitSlow_op_negate): (JSC::JIT::emitMathICFast): (JSC::JIT::emitMathICSlow): * jit/JITInlines.h: (JSC::JIT::callOperation): * jit/JITMathIC.h: (JSC::JITMathIC::generateInline): (JSC::canGenerateWithBinaryProfile): (JSC::canGenerateWithUnaryProfile): * jit/JITMathICForwards.h: * jit/JITNegGenerator.cpp: (JSC::JITNegGenerator::generateInline): (JSC::JITNegGenerator::generateFastPath): * jit/JITNegGenerator.h: (JSC::JITNegGenerator::JITNegGenerator): (JSC::JITNegGenerator::arithProfile): (JSC::JITNegGenerator::didEmitFastPath): Deleted. (JSC::JITNegGenerator::endJumpList): Deleted. (JSC::JITNegGenerator::slowPathJumpList): Deleted. * jit/JITOperations.cpp: * jit/JITOperations.h: * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CommonSlowPaths.cpp: (JSC::updateArithProfileForUnaryArithOp): (JSC::SLOW_PATH_DECL): Canonical link: https://commits.webkit.org/180426@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@206289 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent d64a2e8 commit 41f15cd

27 files changed

Lines changed: 875 additions & 116 deletions

‎JSTests/ChangeLog‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
2016-09-22 Benjamin Poulain <bpoulain@apple.com>
2+
3+
[JSC] Use an inline cache to generate op_negate
4+
https://bugs.webkit.org/show_bug.cgi?id=162371
5+
6+
Reviewed by Saam Barati.
7+
8+
* stress/op-negate-inline-cache.js: Added.
9+
110
2016-09-22 Mark Lam <mark.lam@apple.com>
211

312
Array.prototype.join should do overflow checks on string joins.
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
"use strict"
2+
3+
4+
function opaqueIdentity(arg) {
5+
return arg;
6+
}
7+
noInline(opaqueIdentity)
8+
function negateWithDoubleSub(arg) {
9+
// Implement integer negate as a double sub operation.
10+
return opaqueIdentity(6.4 - arg) - 6.4;
11+
}
12+
noInline(negateWithDoubleSub)
13+
14+
function opaqueNonZeroIntegerNegate(arg)
15+
{
16+
return -arg;
17+
}
18+
noInline(opaqueNonZeroIntegerNegate);
19+
20+
function testNonZeroInteger()
21+
{
22+
for (let i = 1; i < 1e4; ++i) {
23+
if (opaqueNonZeroIntegerNegate(i) !== negateWithDoubleSub(i)) {
24+
throw "Failed testNonZeroInteger() at i = " + i;
25+
}
26+
}
27+
}
28+
testNonZeroInteger();
29+
30+
31+
function opaqueDoubleNegate(arg)
32+
{
33+
return -arg;
34+
}
35+
noInline(opaqueDoubleNegate);
36+
37+
function testDouble()
38+
{
39+
for (let i = 0; i < 1e4; ++i) {
40+
if ((opaqueDoubleNegate(i + 0.5)) + 0.5 + i !== 0) {
41+
throw "Failed testDouble() at i = " + i;
42+
}
43+
}
44+
}
45+
testDouble();
46+
47+
48+
function opaqueObjectNegate(arg)
49+
{
50+
return -arg;
51+
}
52+
noInline(opaqueObjectNegate);
53+
54+
function testObject()
55+
{
56+
for (let i = 0; i < 1e4; ++i) {
57+
if ((opaqueObjectNegate({ valueOf: ()=>{ return i + 0.5 }})) + 0.5 + i !== 0) {
58+
throw "Failed testObject() at i = " + i;
59+
}
60+
}
61+
}
62+
testObject();
63+
64+
65+
function opaqueIntegerAndDoubleNegate(arg)
66+
{
67+
return -arg;
68+
}
69+
noInline(opaqueIntegerAndDoubleNegate);
70+
71+
function testIntegerAndDouble()
72+
{
73+
for (let i = 1; i < 1e4; ++i) {
74+
if ((opaqueIntegerAndDoubleNegate(i)) + i !== 0) {
75+
throw "Failed testIntegerAndDouble() on integers at i = " + i;
76+
}
77+
if ((opaqueIntegerAndDoubleNegate(i + 0.5)) + 0.5 + i !== 0) {
78+
throw "Failed testIntegerAndDouble() on double at i = " + i;
79+
}
80+
}
81+
}
82+
testIntegerAndDouble();
83+
84+
85+
function opaqueIntegerThenDoubleNegate(arg)
86+
{
87+
return -arg;
88+
}
89+
noInline(opaqueIntegerThenDoubleNegate);
90+
91+
function testIntegerThenDouble()
92+
{
93+
for (let i = 1; i < 1e4; ++i) {
94+
if ((opaqueIntegerThenDoubleNegate(i)) + i !== 0) {
95+
throw "Failed testIntegerThenDouble() on integers at i = " + i;
96+
}
97+
}
98+
for (let i = 1; i < 1e4; ++i) {
99+
if ((opaqueIntegerThenDoubleNegate(i + 0.5)) + 0.5 + i !== 0) {
100+
throw "Failed testIntegerThenDouble() on double at i = " + i;
101+
}
102+
}
103+
}
104+
testIntegerThenDouble();
105+
106+
107+
function opaqueDoubleThenIntegerNegate(arg)
108+
{
109+
return -arg;
110+
}
111+
noInline(opaqueDoubleThenIntegerNegate);
112+
113+
function testDoubleThenInteger()
114+
{
115+
for (let i = 1; i < 1e4; ++i) {
116+
if ((opaqueDoubleThenIntegerNegate(i + 0.5)) + 0.5 + i !== 0) {
117+
throw "Failed testDoubleThenInteger() on double at i = " + i;
118+
}
119+
}
120+
for (let i = 1; i < 1e4; ++i) {
121+
if ((opaqueDoubleThenIntegerNegate(i)) + i !== 0) {
122+
throw "Failed testDoubleThenInteger() on integers at i = " + i;
123+
}
124+
}
125+
}
126+
testDoubleThenInteger();
127+
128+
129+
function opaqueIntegerAndObjectNegate(arg)
130+
{
131+
return -arg;
132+
}
133+
noInline(opaqueIntegerAndObjectNegate);
134+
135+
function testIntegerAndObject()
136+
{
137+
for (let i = 1; i < 1e4; ++i) {
138+
if ((opaqueIntegerAndObjectNegate(i)) + i !== 0) {
139+
throw "Failed testIntegerAndObject() on integers at i = " + i;
140+
}
141+
if ((opaqueIntegerAndObjectNegate({ valueOf: ()=>{ return i + 0.5 }})) + 0.5 + i !== 0) {
142+
throw "Failed testIntegerAndObject() on double at i = " + i;
143+
}
144+
}
145+
}
146+
testIntegerAndObject();
147+
148+
149+
function opaqueDoubleAndObjectNegate(arg)
150+
{
151+
return -arg;
152+
}
153+
noInline(opaqueDoubleAndObjectNegate);
154+
155+
function testDoubleAndObject()
156+
{
157+
for (let i = 1; i < 1e4; ++i) {
158+
if ((opaqueDoubleAndObjectNegate(i + 0.5)) + i + 0.5 !== 0) {
159+
throw "Failed testDoubleAndObject() on integers at i = " + i;
160+
}
161+
if ((opaqueDoubleAndObjectNegate({ valueOf: ()=>{ return i }})) + i !== 0) {
162+
throw "Failed testDoubleAndObject() on double at i = " + i;
163+
}
164+
}
165+
}
166+
testDoubleAndObject();
167+
168+
169+
function opaqueIntegerThenObjectNegate(arg)
170+
{
171+
return -arg;
172+
}
173+
noInline(opaqueIntegerThenObjectNegate);
174+
175+
function testIntegerThenObject()
176+
{
177+
for (let i = 1; i < 1e4; ++i) {
178+
if ((opaqueIntegerThenObjectNegate(i)) + i !== 0) {
179+
throw "Failed testIntegerThenObject() on integers at i = " + i;
180+
}
181+
}
182+
for (let i = 1; i < 1e4; ++i) {
183+
if ((opaqueIntegerThenObjectNegate({ valueOf: ()=>{ return i + 0.5 }})) + 0.5 + i !== 0) {
184+
throw "Failed testIntegerThenObject() on double at i = " + i;
185+
}
186+
}
187+
}
188+
testIntegerThenObject();
189+
190+
191+
function opaqueDoubleThenObjectNegate(arg)
192+
{
193+
return -arg;
194+
}
195+
noInline(opaqueDoubleThenObjectNegate);
196+
197+
function testDoubleThenObject()
198+
{
199+
for (let i = 1; i < 1e4; ++i) {
200+
if ((opaqueDoubleThenObjectNegate(i + 0.5)) + i + 0.5 !== 0) {
201+
throw "Failed testDoubleThenObject() on integers at i = " + i;
202+
}
203+
}
204+
for (let i = 1; i < 1e4; ++i) {
205+
if ((opaqueDoubleThenObjectNegate(i + 0.5)) + i + 0.5 !== 0) {
206+
throw "Failed testDoubleThenObject() on integers at i = " + i;
207+
}
208+
}
209+
}
210+
testDoubleThenObject();
211+
212+
213+
function opaqueIntegerAndDoubleAndObjectNegate(arg)
214+
{
215+
return -arg;
216+
}
217+
noInline(opaqueIntegerAndDoubleAndObjectNegate);
218+
219+
function testIntegerAndDoubleAndObject()
220+
{
221+
for (let i = 1; i < 1e4; ++i) {
222+
if ((opaqueIntegerAndDoubleAndObjectNegate(i)) + i !== 0) {
223+
throw "Failed testIntegerAndDoubleAndObject() on integers at i = " + i;
224+
}
225+
if ((opaqueIntegerAndDoubleAndObjectNegate(i + 0.5)) + i + 0.5 !== 0) {
226+
throw "Failed testIntegerAndDoubleAndObject() on integers at i = " + i;
227+
}
228+
if ((opaqueIntegerAndDoubleAndObjectNegate({ valueOf: ()=>{ return i }})) + i !== 0) {
229+
throw "Failed testIntegerAndDoubleAndObject() on double at i = " + i;
230+
}
231+
}
232+
}
233+
testIntegerAndDoubleAndObject();
234+
235+
236+
function opaqueIntegerNegateOverflow(arg)
237+
{
238+
return -arg;
239+
}
240+
noInline(opaqueIntegerNegateOverflow);
241+
242+
function testIntegerNegateOverflow()
243+
{
244+
for (let i = 1; i < 1e4; ++i) {
245+
if (opaqueIntegerNegateOverflow(0x80000000|0) !== 2147483648) {
246+
throw "Failed opaqueIntegerNegateOverflow() at i = " + i;
247+
}
248+
}
249+
}
250+
testIntegerNegateOverflow();
251+
252+
253+
function opaqueIntegerNegateZero(arg)
254+
{
255+
return -arg;
256+
}
257+
noInline(opaqueIntegerNegateZero);
258+
259+
function testIntegerNegateZero()
260+
{
261+
for (let i = 1; i < 1e4; ++i) {
262+
if (1 / opaqueIntegerNegateZero(0) !== -Infinity) {
263+
throw "Failed testIntegerNegateZero() at i = " + i;
264+
}
265+
}
266+
}
267+
testIntegerNegateZero();
268+
269+
270+
function gatedNegate(selector, arg)
271+
{
272+
if (selector === 0) {
273+
return -arg;
274+
}
275+
if (selector == 42) {
276+
return -arg;
277+
}
278+
return arg;
279+
}
280+
noInline(gatedNegate);
281+
282+
function testUnusedNegate()
283+
{
284+
for (let i = 1; i < 1e2; ++i) {
285+
if (gatedNegate(Math.PI, i) !== i) {
286+
throw "Failed first phase of testUnusedNegate";
287+
}
288+
}
289+
for (let i = 1; i < 1e4; ++i) {
290+
if (gatedNegate(0, i) + i !== 0) {
291+
throw "Failed second phase of testUnusedNegate";
292+
}
293+
}
294+
for (let i = 1; i < 1e4; ++i) {
295+
if (gatedNegate(42, i + 0.5) + 0.5 + i !== 0) {
296+
throw "Failed third phase of testUnusedNegate";
297+
}
298+
}
299+
}
300+
testUnusedNegate();

‎Source/JavaScriptCore/ChangeLog‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,72 @@
1+
2016-09-22 Benjamin Poulain <bpoulain@apple.com>
2+
3+
[JSC] Use an inline cache to generate op_negate
4+
https://bugs.webkit.org/show_bug.cgi?id=162371
5+
6+
Reviewed by Saam Barati.
7+
8+
Use an inline cache to reduce the amount of code
9+
required to implement op_negate.
10+
11+
For pure integer negate, the generated asm shrinks
12+
from 147 bytes to 125 bytes (14%).
13+
For double negate, the generated asm shrinks
14+
to 130 bytes (11%).
15+
The average size on Sunspider is 100bytes, this is due
16+
to the op_negates that are never executed and do not
17+
generate much.
18+
19+
* bytecode/ArithProfile.h:
20+
(JSC::ArithProfile::ArithProfile):
21+
(JSC::ArithProfile::observeLHS):
22+
(JSC::ArithProfile::observeLHSAndRHS):
23+
* bytecode/BytecodeList.json:
24+
* bytecode/CodeBlock.cpp:
25+
(JSC::CodeBlock::addJITNegIC):
26+
* bytecode/CodeBlock.h:
27+
* bytecompiler/BytecodeGenerator.cpp:
28+
(JSC::BytecodeGenerator::emitUnaryOp):
29+
* bytecompiler/BytecodeGenerator.h:
30+
* bytecompiler/NodesCodegen.cpp:
31+
(JSC::UnaryOpNode::emitBytecode):
32+
* dfg/DFGSpeculativeJIT.cpp:
33+
(JSC::DFG::SpeculativeJIT::compileMathIC):
34+
* dfg/DFGSpeculativeJIT.h:
35+
* ftl/FTLLowerDFGToB3.cpp:
36+
(JSC::FTL::DFG::LowerDFGToB3::compileMathIC):
37+
* jit/CCallHelpers.h:
38+
(JSC::CCallHelpers::setupArgumentsWithExecState):
39+
* jit/JIT.h:
40+
* jit/JITArithmetic.cpp:
41+
(JSC::JIT::emit_op_negate):
42+
(JSC::JIT::emitSlow_op_negate):
43+
(JSC::JIT::emitMathICFast):
44+
(JSC::JIT::emitMathICSlow):
45+
* jit/JITInlines.h:
46+
(JSC::JIT::callOperation):
47+
* jit/JITMathIC.h:
48+
(JSC::JITMathIC::generateInline):
49+
(JSC::canGenerateWithBinaryProfile):
50+
(JSC::canGenerateWithUnaryProfile):
51+
* jit/JITMathICForwards.h:
52+
* jit/JITNegGenerator.cpp:
53+
(JSC::JITNegGenerator::generateInline):
54+
(JSC::JITNegGenerator::generateFastPath):
55+
* jit/JITNegGenerator.h:
56+
(JSC::JITNegGenerator::JITNegGenerator):
57+
(JSC::JITNegGenerator::arithProfile):
58+
(JSC::JITNegGenerator::didEmitFastPath): Deleted.
59+
(JSC::JITNegGenerator::endJumpList): Deleted.
60+
(JSC::JITNegGenerator::slowPathJumpList): Deleted.
61+
* jit/JITOperations.cpp:
62+
* jit/JITOperations.h:
63+
* llint/LowLevelInterpreter.asm:
64+
* llint/LowLevelInterpreter32_64.asm:
65+
* llint/LowLevelInterpreter64.asm:
66+
* runtime/CommonSlowPaths.cpp:
67+
(JSC::updateArithProfileForUnaryArithOp):
68+
(JSC::SLOW_PATH_DECL):
69+
170
2016-09-22 Mark Lam <mark.lam@apple.com>
271

372
Removed unused hasErrorInfo().

0 commit comments

Comments
 (0)