Implement try/catch in the DFG.
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGOSRExitCompiler64.cpp
1 /*
2  * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "DFGOSRExitCompiler.h"
28
29 #if ENABLE(DFG_JIT) && USE(JSVALUE64)
30
31 #include "DFGOperations.h"
32 #include "DFGOSRExitCompilerCommon.h"
33 #include "DFGSpeculativeJIT.h"
34 #include "JSCInlines.h"
35 #include "VirtualRegister.h"
36
37 #include <wtf/DataLog.h>
38
39 namespace JSC { namespace DFG {
40
41 void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecovery>& operands, SpeculationRecovery* recovery)
42 {
43     m_jit.jitAssertTagsInPlace();
44
45     // Pro-forma stuff.
46     if (Options::printEachOSRExit()) {
47         SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo;
48         debugInfo->codeBlock = m_jit.codeBlock();
49         debugInfo->kind = exit.m_kind;
50         debugInfo->bytecodeOffset = exit.m_codeOrigin.bytecodeIndex;
51         
52         m_jit.debugCall(debugOperationPrintSpeculationFailure, debugInfo);
53     }
54     
55     // Perform speculation recovery. This only comes into play when an operation
56     // starts mutating state before verifying the speculation it has already made.
57     
58     if (recovery) {
59         switch (recovery->type()) {
60         case SpeculativeAdd:
61             m_jit.sub32(recovery->src(), recovery->dest());
62             m_jit.or64(GPRInfo::tagTypeNumberRegister, recovery->dest());
63             break;
64             
65         case BooleanSpeculationCheck:
66             m_jit.xor64(AssemblyHelpers::TrustedImm32(static_cast<int32_t>(ValueFalse)), recovery->dest());
67             break;
68             
69         default:
70             break;
71         }
72     }
73
74     // Refine some array and/or value profile, if appropriate.
75     
76     if (!!exit.m_jsValueSource) {
77         if (exit.m_kind == BadCache || exit.m_kind == BadIndexingType) {
78             // If the instruction that this originated from has an array profile, then
79             // refine it. If it doesn't, then do nothing. The latter could happen for
80             // hoisted checks, or checks emitted for operations that didn't have array
81             // profiling - either ops that aren't array accesses at all, or weren't
82             // known to be array acceses in the bytecode. The latter case is a FIXME
83             // while the former case is an outcome of a CheckStructure not knowing why
84             // it was emitted (could be either due to an inline cache of a property
85             // property access, or due to an array profile).
86             
87             CodeOrigin codeOrigin = exit.m_codeOriginForExitProfile;
88             if (ArrayProfile* arrayProfile = m_jit.baselineCodeBlockFor(codeOrigin)->getArrayProfile(codeOrigin.bytecodeIndex)) {
89                 GPRReg usedRegister;
90                 if (exit.m_jsValueSource.isAddress())
91                     usedRegister = exit.m_jsValueSource.base();
92                 else
93                     usedRegister = exit.m_jsValueSource.gpr();
94                 
95                 GPRReg scratch1;
96                 GPRReg scratch2;
97                 scratch1 = AssemblyHelpers::selectScratchGPR(usedRegister);
98                 scratch2 = AssemblyHelpers::selectScratchGPR(usedRegister, scratch1);
99                 
100                 if (isARM64()) {
101                     m_jit.pushToSave(scratch1);
102                     m_jit.pushToSave(scratch2);
103                 } else {
104                     m_jit.push(scratch1);
105                     m_jit.push(scratch2);
106                 }
107                 
108                 GPRReg value;
109                 if (exit.m_jsValueSource.isAddress()) {
110                     value = scratch1;
111                     m_jit.loadPtr(AssemblyHelpers::Address(exit.m_jsValueSource.asAddress()), value);
112                 } else
113                     value = exit.m_jsValueSource.gpr();
114                 
115                 m_jit.load32(AssemblyHelpers::Address(value, JSCell::structureIDOffset()), scratch1);
116                 m_jit.store32(scratch1, arrayProfile->addressOfLastSeenStructureID());
117                 m_jit.load8(AssemblyHelpers::Address(value, JSCell::indexingTypeOffset()), scratch1);
118                 m_jit.move(AssemblyHelpers::TrustedImm32(1), scratch2);
119                 m_jit.lshift32(scratch1, scratch2);
120                 m_jit.or32(scratch2, AssemblyHelpers::AbsoluteAddress(arrayProfile->addressOfArrayModes()));
121                 
122                 if (isARM64()) {
123                     m_jit.popToRestore(scratch2);
124                     m_jit.popToRestore(scratch1);
125                 } else {
126                     m_jit.pop(scratch2);
127                     m_jit.pop(scratch1);
128                 }
129             }
130         }
131         
132         if (!!exit.m_valueProfile) {
133             EncodedJSValue* bucket = exit.m_valueProfile.getSpecFailBucket(0);
134             
135             if (exit.m_jsValueSource.isAddress()) {
136                 // We can't be sure that we have a spare register. So use the tagTypeNumberRegister,
137                 // since we know how to restore it.
138                 m_jit.load64(AssemblyHelpers::Address(exit.m_jsValueSource.asAddress()), GPRInfo::tagTypeNumberRegister);
139                 m_jit.store64(GPRInfo::tagTypeNumberRegister, bucket);
140                 m_jit.move(AssemblyHelpers::TrustedImm64(TagTypeNumber), GPRInfo::tagTypeNumberRegister);
141             } else
142                 m_jit.store64(exit.m_jsValueSource.gpr(), bucket);
143         }
144     }
145     
146     // What follows is an intentionally simple OSR exit implementation that generates
147     // fairly poor code but is very easy to hack. In particular, it dumps all state that
148     // needs conversion into a scratch buffer so that in step 6, where we actually do the
149     // conversions, we know that all temp registers are free to use and the variable is
150     // definitely in a well-known spot in the scratch buffer regardless of whether it had
151     // originally been in a register or spilled. This allows us to decouple "where was
152     // the variable" from "how was it represented". Consider that the
153     // Int32DisplacedInJSStack recovery: it tells us that the value is in a
154     // particular place and that that place holds an unboxed int32. We have two different
155     // places that a value could be (displaced, register) and a bunch of different
156     // ways of representing a value. The number of recoveries is two * a bunch. The code
157     // below means that we have to have two + a bunch cases rather than two * a bunch.
158     // Once we have loaded the value from wherever it was, the reboxing is the same
159     // regardless of its location. Likewise, before we do the reboxing, the way we get to
160     // the value (i.e. where we load it from) is the same regardless of its type. Because
161     // the code below always dumps everything into a scratch buffer first, the two
162     // questions become orthogonal, which simplifies adding new types and adding new
163     // locations.
164     //
165     // This raises the question: does using such a suboptimal implementation of OSR exit,
166     // where we always emit code to dump all state into a scratch buffer only to then
167     // dump it right back into the stack, hurt us in any way? The asnwer is that OSR exits
168     // are rare. Our tiering strategy ensures this. This is because if an OSR exit is
169     // taken more than ~100 times, we jettison the DFG code block along with all of its
170     // exits. It is impossible for an OSR exit - i.e. the code we compile below - to
171     // execute frequently enough for the codegen to matter that much. It probably matters
172     // enough that we don't want to turn this into some super-slow function call, but so
173     // long as we're generating straight-line code, that code can be pretty bad. Also
174     // because we tend to exit only along one OSR exit from any DFG code block - that's an
175     // empirical result that we're extremely confident about - the code size of this
176     // doesn't matter much. Hence any attempt to optimize the codegen here is just purely
177     // harmful to the system: it probably won't reduce either net memory usage or net
178     // execution time. It will only prevent us from cleanly decoupling "where was the
179     // variable" from "how was it represented", which will make it more difficult to add
180     // features in the future and it will make it harder to reason about bugs.
181
182     // Save all state from GPRs into the scratch buffer.
183     
184     ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(sizeof(EncodedJSValue) * operands.size());
185     EncodedJSValue* scratch = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
186     
187     for (size_t index = 0; index < operands.size(); ++index) {
188         const ValueRecovery& recovery = operands[index];
189         
190         switch (recovery.technique()) {
191         case InGPR:
192         case UnboxedInt32InGPR:
193         case UnboxedInt52InGPR:
194         case UnboxedStrictInt52InGPR:
195         case UnboxedCellInGPR:
196             m_jit.store64(recovery.gpr(), scratch + index);
197             break;
198             
199         default:
200             break;
201         }
202     }
203     
204     // And voila, all GPRs are free to reuse.
205
206     // Save all state from FPRs into the scratch buffer.
207     
208     for (size_t index = 0; index < operands.size(); ++index) {
209         const ValueRecovery& recovery = operands[index];
210         
211         switch (recovery.technique()) {
212         case UnboxedDoubleInFPR:
213         case InFPR:
214             m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
215             m_jit.storeDouble(recovery.fpr(), MacroAssembler::Address(GPRInfo::regT0));
216             break;
217             
218         default:
219             break;
220         }
221     }
222     
223     // Now, all FPRs are also free.
224     
225     // Save all state from the stack into the scratch buffer. For simplicity we
226     // do this even for state that's already in the right place on the stack.
227     // It makes things simpler later.
228
229     for (size_t index = 0; index < operands.size(); ++index) {
230         const ValueRecovery& recovery = operands[index];
231         
232         switch (recovery.technique()) {
233         case DisplacedInJSStack:
234         case CellDisplacedInJSStack:
235         case BooleanDisplacedInJSStack:
236         case Int32DisplacedInJSStack:
237         case DoubleDisplacedInJSStack:
238         case Int52DisplacedInJSStack:
239         case StrictInt52DisplacedInJSStack:
240             m_jit.load64(AssemblyHelpers::addressFor(recovery.virtualRegister()), GPRInfo::regT0);
241             m_jit.store64(GPRInfo::regT0, scratch + index);
242             break;
243             
244         default:
245             break;
246         }
247     }
248
249     // Need to ensure that the stack pointer accounts for the worst-case stack usage at exit. This
250     // could toast some stack that the DFG used. We need to do it before storing to stack offsets
251     // used by baseline.
252     m_jit.addPtr(
253         CCallHelpers::TrustedImm32(
254             -m_jit.codeBlock()->jitCode()->dfgCommon()->requiredRegisterCountForExit * sizeof(Register)),
255         CCallHelpers::framePointerRegister, CCallHelpers::stackPointerRegister);
256     
257     // Restore the DFG callee saves and then save the ones the baseline JIT uses.
258     m_jit.emitRestoreCalleeSaves();
259     m_jit.emitSaveCalleeSavesFor(m_jit.baselineCodeBlock());
260
261     // The tag registers are needed to materialize recoveries below.
262     m_jit.emitMaterializeTagCheckRegisters();
263
264     // Do all data format conversions and store the results into the stack.
265     
266     for (size_t index = 0; index < operands.size(); ++index) {
267         const ValueRecovery& recovery = operands[index];
268         VirtualRegister reg = operands.virtualRegisterForIndex(index);
269
270         if (reg.isLocal() && reg.toLocal() < static_cast<int>(m_jit.baselineCodeBlock()->calleeSaveSpaceAsVirtualRegisters()))
271             continue;
272
273         int operand = reg.offset();
274
275         switch (recovery.technique()) {
276         case InGPR:
277         case UnboxedCellInGPR:
278         case DisplacedInJSStack:
279         case CellDisplacedInJSStack:
280         case BooleanDisplacedInJSStack:
281         case InFPR:
282             m_jit.load64(scratch + index, GPRInfo::regT0);
283             m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
284             break;
285             
286         case UnboxedInt32InGPR:
287         case Int32DisplacedInJSStack:
288             m_jit.load64(scratch + index, GPRInfo::regT0);
289             m_jit.zeroExtend32ToPtr(GPRInfo::regT0, GPRInfo::regT0);
290             m_jit.or64(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
291             m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
292             break;
293             
294         case UnboxedInt52InGPR:
295         case Int52DisplacedInJSStack:
296             m_jit.load64(scratch + index, GPRInfo::regT0);
297             m_jit.rshift64(
298                 AssemblyHelpers::TrustedImm32(JSValue::int52ShiftAmount), GPRInfo::regT0);
299             m_jit.boxInt52(GPRInfo::regT0, GPRInfo::regT0, GPRInfo::regT1, FPRInfo::fpRegT0);
300             m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
301             break;
302             
303         case UnboxedStrictInt52InGPR:
304         case StrictInt52DisplacedInJSStack:
305             m_jit.load64(scratch + index, GPRInfo::regT0);
306             m_jit.boxInt52(GPRInfo::regT0, GPRInfo::regT0, GPRInfo::regT1, FPRInfo::fpRegT0);
307             m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
308             break;
309             
310         case UnboxedDoubleInFPR:
311         case DoubleDisplacedInJSStack:
312             m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
313             m_jit.loadDouble(MacroAssembler::Address(GPRInfo::regT0), FPRInfo::fpRegT0);
314             m_jit.purifyNaN(FPRInfo::fpRegT0);
315             m_jit.boxDouble(FPRInfo::fpRegT0, GPRInfo::regT0);
316             m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
317             break;
318             
319         case Constant:
320             m_jit.store64(
321                 AssemblyHelpers::TrustedImm64(JSValue::encode(recovery.constant())),
322                 AssemblyHelpers::addressFor(operand));
323             break;
324             
325         case DirectArgumentsThatWereNotCreated:
326         case ClonedArgumentsThatWereNotCreated:
327             // Don't do this, yet.
328             break;
329             
330         default:
331             RELEASE_ASSERT_NOT_REACHED();
332             break;
333         }
334     }
335
336     // Now that things on the stack are recovered, do the arguments recovery. We assume that arguments
337     // recoveries don't recursively refer to each other. But, we don't try to assume that they only
338     // refer to certain ranges of locals. Hence why we need to do this here, once the stack is sensible.
339     // Note that we also roughly assume that the arguments might still be materialized outside of its
340     // inline call frame scope - but for now the DFG wouldn't do that.
341     
342     emitRestoreArguments(operands);
343     
344     // Adjust the old JIT's execute counter. Since we are exiting OSR, we know
345     // that all new calls into this code will go to the new JIT, so the execute
346     // counter only affects call frames that performed OSR exit and call frames
347     // that were still executing the old JIT at the time of another call frame's
348     // OSR exit. We want to ensure that the following is true:
349     //
350     // (a) Code the performs an OSR exit gets a chance to reenter optimized
351     //     code eventually, since optimized code is faster. But we don't
352     //     want to do such reentery too aggressively (see (c) below).
353     //
354     // (b) If there is code on the call stack that is still running the old
355     //     JIT's code and has never OSR'd, then it should get a chance to
356     //     perform OSR entry despite the fact that we've exited.
357     //
358     // (c) Code the performs an OSR exit should not immediately retry OSR
359     //     entry, since both forms of OSR are expensive. OSR entry is
360     //     particularly expensive.
361     //
362     // (d) Frequent OSR failures, even those that do not result in the code
363     //     running in a hot loop, result in recompilation getting triggered.
364     //
365     // To ensure (c), we'd like to set the execute counter to
366     // counterValueForOptimizeAfterWarmUp(). This seems like it would endanger
367     // (a) and (b), since then every OSR exit would delay the opportunity for
368     // every call frame to perform OSR entry. Essentially, if OSR exit happens
369     // frequently and the function has few loops, then the counter will never
370     // become non-negative and OSR entry will never be triggered. OSR entry
371     // will only happen if a loop gets hot in the old JIT, which does a pretty
372     // good job of ensuring (a) and (b). But that doesn't take care of (d),
373     // since each speculation failure would reset the execute counter.
374     // So we check here if the number of speculation failures is significantly
375     // larger than the number of successes (we want 90% success rate), and if
376     // there have been a large enough number of failures. If so, we set the
377     // counter to 0; otherwise we set the counter to
378     // counterValueForOptimizeAfterWarmUp().
379     
380     handleExitCounts(m_jit, exit);
381     
382     // Reify inlined call frames.
383     
384     reifyInlinedCallFrames(m_jit, exit);
385
386     // And finish.
387     adjustAndJumpToTarget(m_jit, exit, exit.m_isExceptionHandler);
388 }
389
390 } } // namespace JSC::DFG
391
392 #endif // ENABLE(DFG_JIT) && USE(JSVALUE64)