12016-07-20 Saam Barati <sbarati@apple.com>
2
3 op_add/ValueAdd should be an IC in all JIT tiers
4 https://bugs.webkit.org/show_bug.cgi?id=159649
5
6 Reviewed by NOBODY (OOPS!).
7
8 This patch makes Add an IC inside all JIT tiers. It does so in a
9 simple, but effective, way. We will try to generate an int+int add
10 that will repatch itself if its type checks fail. Sometimes though,
11 we have runtime type data saying that the add won't be int+int.
12 In those cases, we will just generate a full snippet that doesn't patch itself.
13 Other times, we may generate no inline code and defer to making a C call. A lot
14 of this patch is just refactoring ResultProfile into what we're now calling ArithProfile.
15 ArithProfile does everything ResultProfile used to do, and more. It records simple type
16 data about the LHS/RHS operands it sees. This allows us to determine if an op_add
17 has only seen int+int operands, etc. ArithProfile will also contain the ResultType
18 for the LHS/RHS that the parser feeds into op_add. ArithProfile now fits into 32-bits.
19 This means instead of having a side table like we did for ResultProfile, we just
20 inject the ArithProfile into the bytecode instruction stream. This makes asking
21 for ArithProfile faster; we no longer need to lock around this operation.
22
23 The size of an Add has gone down on average, but we can still do better.
24 We still generate a lot of code because we generate calls to the slow path.
25 I think we can make this better by moving the slow path to a shared thunk
26 system. This patch mostly lays the foundation for future improvements to Add,
27 and a framework to move all other arithmetic operations to be typed-based ICs.
28
29 Here is some data I took on the average op_add/ValueAdd size on various benchmarks:
30 | JetStream | Speedometer | Unity 3D |
31 ------| -------------|-----------------------------
32 Old | 189 bytes | 169 bytes | 192 bytes |
33 ------| -------------|-----------------------------
34 New | 148 bytes | 124 bytes | 143 bytes |
35 ---------------------------------------------------
36
37 Making an arithmetic IC is now easy. The JITMathIC class will hold a snippet
38 generator as a member variable. To make a snippet an IC, you need to implement
39 a generateInline(.) method, which generates the inline IC. Then, you need to
40 generate the IC where you used to generate the snippet. When generating the
41 IC, we need to inform JITMathIC of various data like we do with StructureStubInfo.
42 We need to tell it about where the slow path starts, where the slow path call is, etc.
43 When generating a JITMathIC, it may tell you that it didn't generate any code inline.
44 This is a request to the user of JITMathIC to just generate a C call along the
45 fast path. JITMathIC may also have the snippet tell it to just generate the full
46 snippet instead of the int+int path along the fast path.
47
48 In subsequent patches, we can improve upon how we decide to generate int+int or
49 the full snippet. I tried to get clever by having double+double, double+int, int+double,
50 fast paths, but they didn't work out nearly as well as the int+int fast path. I ended up
51 generating a lot of code when I did this and ended up using more memory than just generating
52 the full snippet. There is probably some way we can be clever and generate specialized fast
53 paths that are more successful than what I tried implementing, but I think that's worth doing
54 this in follow up patches once the JITMathIC foundation has landed.
55
56 This patch also fixes a bug inside the slow path lambdas in the DFG.
57 Before, it was not legal to emit an exception check inside them. Now,
58 it is. So it's now easy to define arbitrary late paths using the DFG
59 slow path lambda API.
60
61 * CMakeLists.txt:
62 * JavaScriptCore.xcodeproj/project.pbxproj:
63 * bytecode/ArithProfile.cpp: Added.
64 (JSC::ArithProfile::emitDetectNumericness):
65 (JSC::ArithProfile::shouldEmitSetDouble):
66 (JSC::ArithProfile::emitSetDouble):
67 (JSC::ArithProfile::shouldEmitSetNonNumber):
68 (JSC::ArithProfile::emitSetNonNumber):
69 (WTF::printInternal):
70 * bytecode/ArithProfile.h: Added.
71 (JSC::ObservedType::ObservedType):
72 (JSC::ObservedType::sawInt32):
73 (JSC::ObservedType::isOnlyInt32):
74 (JSC::ObservedType::sawNumber):
75 (JSC::ObservedType::isOnlyNumber):
76 (JSC::ObservedType::sawNonNumber):
77 (JSC::ObservedType::isOnlyNonNumber):
78 (JSC::ObservedType::isEmpty):
79 (JSC::ObservedType::bits):
80 (JSC::ObservedType::withInt32):
81 (JSC::ObservedType::withNumber):
82 (JSC::ObservedType::withNonNumber):
83 (JSC::ObservedType::withoutNonNumber):
84 (JSC::ObservedType::operator==):
85 (JSC::ArithProfile::ArithProfile):
86 (JSC::ArithProfile::fromInt):
87 (JSC::ArithProfile::lhsResultType):
88 (JSC::ArithProfile::rhsResultType):
89 (JSC::ArithProfile::lhsObservedType):
90 (JSC::ArithProfile::rhsObservedType):
91 (JSC::ArithProfile::setLhsObservedType):
92 (JSC::ArithProfile::setRhsObservedType):
93 (JSC::ArithProfile::tookSpecialFastPath):
94 (JSC::ArithProfile::didObserveNonInt32):
95 (JSC::ArithProfile::didObserveDouble):
96 (JSC::ArithProfile::didObserveNonNegZeroDouble):
97 (JSC::ArithProfile::didObserveNegZeroDouble):
98 (JSC::ArithProfile::didObserveNonNumber):
99 (JSC::ArithProfile::didObserveInt32Overflow):
100 (JSC::ArithProfile::didObserveInt52Overflow):
101 (JSC::ArithProfile::setObservedNonNegZeroDouble):
102 (JSC::ArithProfile::setObservedNegZeroDouble):
103 (JSC::ArithProfile::setObservedNonNumber):
104 (JSC::ArithProfile::setObservedInt32Overflow):
105 (JSC::ArithProfile::setObservedInt52Overflow):
106 (JSC::ArithProfile::addressOfBits):
107 (JSC::ArithProfile::detectNumericness):
108 (JSC::ArithProfile::lhsSawInt32):
109 (JSC::ArithProfile::lhsSawNumber):
110 (JSC::ArithProfile::lhsSawNonNumber):
111 (JSC::ArithProfile::rhsSawInt32):
112 (JSC::ArithProfile::rhsSawNumber):
113 (JSC::ArithProfile::rhsSawNonNumber):
114 (JSC::ArithProfile::observeLHSAndRHS):
115 (JSC::ArithProfile::bits):
116 (JSC::ArithProfile::hasBits):
117 (JSC::ArithProfile::setBit):
118 * bytecode/CodeBlock.cpp:
119 (JSC::CodeBlock::dumpRareCaseProfile):
120 (JSC::CodeBlock::dumpArithProfile):
121 (JSC::CodeBlock::dumpBytecode):
122 (JSC::CodeBlock::addStubInfo):
123 (JSC::CodeBlock::addJITAddIC):
124 (JSC::CodeBlock::findStubInfo):
125 (JSC::CodeBlock::resetJITData):
126 (JSC::CodeBlock::shrinkToFit):
127 (JSC::CodeBlock::dumpValueProfiles):
128 (JSC::CodeBlock::rareCaseProfileCountForBytecodeOffset):
129 (JSC::CodeBlock::arithProfileForBytecodeOffset):
130 (JSC::CodeBlock::arithProfileForPC):
131 (JSC::CodeBlock::couldTakeSpecialFastCase):
132 (JSC::CodeBlock::dumpResultProfile): Deleted.
133 (JSC::CodeBlock::resultProfileForBytecodeOffset): Deleted.
134 (JSC::CodeBlock::specialFastCaseProfileCountForBytecodeOffset): Deleted.
135 (JSC::CodeBlock::ensureResultProfile): Deleted.
136 * bytecode/CodeBlock.h:
137 (JSC::CodeBlock::stubInfoBegin):
138 (JSC::CodeBlock::stubInfoEnd):
139 (JSC::CodeBlock::couldTakeSlowCase):
140 (JSC::CodeBlock::numberOfResultProfiles): Deleted.
141 * bytecode/MethodOfGettingAValueProfile.cpp:
142 (JSC::MethodOfGettingAValueProfile::emitReportValue):
143 * bytecode/MethodOfGettingAValueProfile.h:
144 (JSC::MethodOfGettingAValueProfile::MethodOfGettingAValueProfile):
145 * bytecode/ValueProfile.cpp:
146 (JSC::ResultProfile::emitDetectNumericness): Deleted.
147 (JSC::ResultProfile::emitSetDouble): Deleted.
148 (JSC::ResultProfile::emitSetNonNumber): Deleted.
149 (WTF::printInternal): Deleted.
150 * bytecode/ValueProfile.h:
151 (JSC::getRareCaseProfileBytecodeOffset):
152 (JSC::ResultProfile::ResultProfile): Deleted.
153 (JSC::ResultProfile::bytecodeOffset): Deleted.
154 (JSC::ResultProfile::specialFastPathCount): Deleted.
155 (JSC::ResultProfile::didObserveNonInt32): Deleted.
156 (JSC::ResultProfile::didObserveDouble): Deleted.
157 (JSC::ResultProfile::didObserveNonNegZeroDouble): Deleted.
158 (JSC::ResultProfile::didObserveNegZeroDouble): Deleted.
159 (JSC::ResultProfile::didObserveNonNumber): Deleted.
160 (JSC::ResultProfile::didObserveInt32Overflow): Deleted.
161 (JSC::ResultProfile::didObserveInt52Overflow): Deleted.
162 (JSC::ResultProfile::setObservedNonNegZeroDouble): Deleted.
163 (JSC::ResultProfile::setObservedNegZeroDouble): Deleted.
164 (JSC::ResultProfile::setObservedNonNumber): Deleted.
165 (JSC::ResultProfile::setObservedInt32Overflow): Deleted.
166 (JSC::ResultProfile::setObservedInt52Overflow): Deleted.
167 (JSC::ResultProfile::addressOfFlags): Deleted.
168 (JSC::ResultProfile::addressOfSpecialFastPathCount): Deleted.
169 (JSC::ResultProfile::detectNumericness): Deleted.
170 (JSC::ResultProfile::hasBits): Deleted.
171 (JSC::ResultProfile::setBit): Deleted.
172 (JSC::getResultProfileBytecodeOffset): Deleted.
173 * bytecompiler/BytecodeGenerator.cpp:
174 (JSC::BytecodeGenerator::emitBinaryOp):
175 * dfg/DFGByteCodeParser.cpp:
176 (JSC::DFG::ByteCodeParser::makeSafe):
177 * dfg/DFGGraph.cpp:
178 (JSC::DFG::Graph::methodOfGettingAValueProfileFor):
179 * dfg/DFGJITCompiler.cpp:
180 (JSC::DFG::JITCompiler::exceptionCheck):
181 * dfg/DFGSlowPathGenerator.h:
182 (JSC::DFG::SlowPathGenerator::generate):
183 * dfg/DFGSpeculativeJIT.cpp:
184 (JSC::DFG::SpeculativeJIT::addSlowPathGenerator):
185 (JSC::DFG::SpeculativeJIT::runSlowPathGenerators):
186 (JSC::DFG::SpeculativeJIT::compileValueAdd):
187 * dfg/DFGSpeculativeJIT.h:
188 (JSC::DFG::SpeculativeJIT::silentSpillAllRegistersImpl):
189 (JSC::DFG::SpeculativeJIT::silentSpillAllRegisters):
190 (JSC::DFG::SpeculativeJIT::callOperation):
191 * ftl/FTLLowerDFGToB3.cpp:
192 (JSC::FTL::DFG::LowerDFGToB3::compileValueAdd):
193 (JSC::FTL::DFG::LowerDFGToB3::compileStrCat):
194 (JSC::FTL::DFG::LowerDFGToB3::emitBinarySnippet):
195 (JSC::FTL::DFG::LowerDFGToB3::emitAddSnippet):
196 (JSC::FTL::DFG::LowerDFGToB3::emitBinaryBitOpSnippet):
197 * jit/CCallHelpers.h:
198 (JSC::CCallHelpers::setupArgumentsWithExecState):
199 (JSC::CCallHelpers::setupArguments):
200 * jit/JIT.h:
201 * jit/JITAddGenerator.cpp:
202 (JSC::JITAddGenerator::generateInline):
203 (JSC::JITAddGenerator::generateFastPath):
204 * jit/JITAddGenerator.h:
205 (JSC::JITAddGenerator::JITAddGenerator):
206 (JSC::JITAddGenerator::didEmitFastPath): Deleted.
207 (JSC::JITAddGenerator::endJumpList): Deleted.
208 (JSC::JITAddGenerator::slowPathJumpList): Deleted.
209 * jit/JITArithmetic.cpp:
210 (JSC::JIT::emit_op_jless):
211 (JSC::JIT::emitSlow_op_urshift):
212 (JSC::getOperandTypes):
213 (JSC::JIT::emit_op_add):
214 (JSC::JIT::emitSlow_op_add):
215 (JSC::JIT::emit_op_div):
216 (JSC::JIT::emit_op_mul):
217 (JSC::JIT::emitSlow_op_mul):
218 (JSC::JIT::emit_op_sub):
219 (JSC::JIT::emitSlow_op_sub):
220 * jit/JITDivGenerator.cpp:
221 (JSC::JITDivGenerator::generateFastPath):
222 * jit/JITDivGenerator.h:
223 (JSC::JITDivGenerator::JITDivGenerator):
224 * jit/JITInlines.h:
225 (JSC::JIT::callOperation):
226 * jit/JITMathIC.h: Added.
227 (JSC::JITMathIC::doneLocation):
228 (JSC::JITMathIC::slowPathStartLocation):
229 (JSC::JITMathIC::slowPathCallLocation):
230 (JSC::JITMathIC::generateInline):
231 (JSC::JITMathIC::generateOutOfLine):
232 (JSC::JITMathIC::finalizeInlineCode):
233 * jit/JITMathICForwards.h: Added.
234 * jit/JITMathICInlineResult.h: Added.
235 * jit/JITMulGenerator.cpp:
236 (JSC::JITMulGenerator::generateFastPath):
237 * jit/JITMulGenerator.h:
238 (JSC::JITMulGenerator::JITMulGenerator):
239 * jit/JITOperations.cpp:
240 * jit/JITOperations.h:
241 * jit/JITSubGenerator.cpp:
242 (JSC::JITSubGenerator::generateFastPath):
243 * jit/JITSubGenerator.h:
244 (JSC::JITSubGenerator::JITSubGenerator):
245 * jit/Repatch.cpp:
246 (JSC::readCallTarget):
247 (JSC::ftlThunkAwareRepatchCall):
248 (JSC::tryCacheGetByID):
249 (JSC::repatchGetByID):
250 (JSC::appropriateGenericPutByIdFunction):
251 (JSC::tryCachePutByID):
252 (JSC::repatchPutByID):
253 (JSC::tryRepatchIn):
254 (JSC::repatchIn):
255 (JSC::linkSlowFor):
256 (JSC::resetGetByID):
257 (JSC::resetPutByID):
258 (JSC::repatchCall): Deleted.
259 * jit/Repatch.h:
260 * llint/LLIntData.cpp:
261 (JSC::LLInt::Data::performAssertions):
262 * llint/LowLevelInterpreter.asm:
263 * llint/LowLevelInterpreter32_64.asm:
264 * llint/LowLevelInterpreter64.asm:
265 * parser/ResultType.h:
266 (JSC::ResultType::ResultType):
267 (JSC::ResultType::isInt32):
268 (JSC::ResultType::definitelyIsNumber):
269 (JSC::ResultType::definitelyIsString):
270 (JSC::ResultType::definitelyIsBoolean):
271 (JSC::ResultType::mightBeNumber):
272 (JSC::ResultType::isNotNumber):
273 (JSC::ResultType::forBitOp):
274 (JSC::ResultType::bits):
275 (JSC::OperandTypes::OperandTypes):
276 * runtime/CommonSlowPaths.cpp:
277 (JSC::SLOW_PATH_DECL):
278 (JSC::updateArithProfileForBinaryArithOp):
279 (JSC::updateResultProfileForBinaryArithOp): Deleted.
280 * tests/stress/op-add-exceptions.js: Added.
281 (assert):
282 (f1):
283 (f2):
284 (f3):
285 (let.oException.valueOf):
286 (foo):
287 (ident):
288 (bar):
289