3f53216196cc7917257216523563633058c8f0ed
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGOSRExitCompiler.cpp
1 /*
2  * Copyright (C) 2011-2013, 2015-2016 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)
30
31 #include "CallFrame.h"
32 #include "DFGCommon.h"
33 #include "DFGJITCode.h"
34 #include "DFGOSRExitPreparation.h"
35 #include "LinkBuffer.h"
36 #include "OperandsInlines.h"
37 #include "JSCInlines.h"
38 #include <wtf/StringPrintStream.h>
39
40 namespace JSC { namespace DFG {
41
42 void OSRExitCompiler::emitRestoreArguments(const Operands<ValueRecovery>& operands)
43 {
44     HashMap<MinifiedID, int> alreadyAllocatedArguments; // Maps phantom arguments node ID to operand.
45     for (size_t index = 0; index < operands.size(); ++index) {
46         const ValueRecovery& recovery = operands[index];
47         int operand = operands.operandForIndex(index);
48         
49         if (recovery.technique() != DirectArgumentsThatWereNotCreated
50             && recovery.technique() != ClonedArgumentsThatWereNotCreated)
51             continue;
52         
53         MinifiedID id = recovery.nodeID();
54         auto iter = alreadyAllocatedArguments.find(id);
55         if (iter != alreadyAllocatedArguments.end()) {
56             JSValueRegs regs = JSValueRegs::withTwoAvailableRegs(GPRInfo::regT0, GPRInfo::regT1);
57             m_jit.loadValue(CCallHelpers::addressFor(iter->value), regs);
58             m_jit.storeValue(regs, CCallHelpers::addressFor(operand));
59             continue;
60         }
61         
62         InlineCallFrame* inlineCallFrame =
63             m_jit.codeBlock()->jitCode()->dfg()->minifiedDFG.at(id)->inlineCallFrame();
64
65         int stackOffset;
66         if (inlineCallFrame)
67             stackOffset = inlineCallFrame->stackOffset;
68         else
69             stackOffset = 0;
70         
71         if (!inlineCallFrame || inlineCallFrame->isClosureCall) {
72             m_jit.loadPtr(
73                 AssemblyHelpers::addressFor(stackOffset + CallFrameSlot::callee),
74                 GPRInfo::regT0);
75         } else {
76             m_jit.move(
77                 AssemblyHelpers::TrustedImmPtr(inlineCallFrame->calleeRecovery.constant().asCell()),
78                 GPRInfo::regT0);
79         }
80         
81         if (!inlineCallFrame || inlineCallFrame->isVarargs()) {
82             m_jit.load32(
83                 AssemblyHelpers::payloadFor(stackOffset + CallFrameSlot::argumentCount),
84                 GPRInfo::regT1);
85         } else {
86             m_jit.move(
87                 AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()),
88                 GPRInfo::regT1);
89         }
90         
91         m_jit.setupArgumentsWithExecState(
92             AssemblyHelpers::TrustedImmPtr(inlineCallFrame), GPRInfo::regT0, GPRInfo::regT1);
93         switch (recovery.technique()) {
94         case DirectArgumentsThatWereNotCreated:
95             m_jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(operationCreateDirectArgumentsDuringExit)), GPRInfo::nonArgGPR0);
96             break;
97         case ClonedArgumentsThatWereNotCreated:
98             m_jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(operationCreateClonedArgumentsDuringExit)), GPRInfo::nonArgGPR0);
99             break;
100         default:
101             RELEASE_ASSERT_NOT_REACHED();
102             break;
103         }
104         m_jit.call(GPRInfo::nonArgGPR0);
105         m_jit.storeCell(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(operand));
106         
107         alreadyAllocatedArguments.add(id, operand);
108     }
109 }
110
111 extern "C" {
112
113 void compileOSRExit(ExecState* exec)
114 {
115     VM* vm = &exec->vm();
116     auto scope = DECLARE_THROW_SCOPE(*vm);
117
118     if (vm->callFrameForCatch)
119         RELEASE_ASSERT(vm->callFrameForCatch == exec);
120     
121     CodeBlock* codeBlock = exec->codeBlock();
122     ASSERT(codeBlock);
123     ASSERT(codeBlock->jitType() == JITCode::DFGJIT);
124     
125     // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't
126     // really be profitable.
127     DeferGCForAWhile deferGC(vm->heap);
128
129     uint32_t exitIndex = vm->osrExitIndex;
130     OSRExit& exit = codeBlock->jitCode()->dfg()->osrExit[exitIndex];
131     
132     if (vm->callFrameForCatch)
133         ASSERT(exit.m_kind == GenericUnwind);
134     if (exit.isExceptionHandler())
135         ASSERT_UNUSED(scope, !!scope.exception());
136         
137     
138     prepareCodeOriginForOSRExit(exec, exit.m_codeOrigin);
139     
140     // Compute the value recoveries.
141     Operands<ValueRecovery> operands;
142     codeBlock->jitCode()->dfg()->variableEventStream.reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->jitCode()->dfg()->minifiedDFG, exit.m_streamIndex, operands);
143     
144     SpeculationRecovery* recovery = 0;
145     if (exit.m_recoveryIndex != UINT_MAX)
146         recovery = &codeBlock->jitCode()->dfg()->speculationRecovery[exit.m_recoveryIndex];
147
148     {
149         CCallHelpers jit(codeBlock);
150         OSRExitCompiler exitCompiler(jit);
151
152         if (exit.m_kind == GenericUnwind) {
153             // We are acting as a defacto op_catch because we arrive here from genericUnwind().
154             // So, we must restore our call frame and stack pointer.
155             jit.restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer(*vm);
156             jit.loadPtr(vm->addressOfCallFrameForCatch(), GPRInfo::callFrameRegister);
157         }
158         jit.addPtr(
159             CCallHelpers::TrustedImm32(codeBlock->stackPointerOffset() * sizeof(Register)),
160             GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
161
162         jit.jitAssertHasValidCallFrame();
163         
164         if (vm->m_perBytecodeProfiler && codeBlock->jitCode()->dfgCommon()->compilation) {
165             Profiler::Database& database = *vm->m_perBytecodeProfiler;
166             Profiler::Compilation* compilation = codeBlock->jitCode()->dfgCommon()->compilation.get();
167             
168             Profiler::OSRExit* profilerExit = compilation->addOSRExit(
169                 exitIndex, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin),
170                 exit.m_kind, exit.m_kind == UncountableInvalidation);
171             jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress()));
172         }
173
174         exitCompiler.compileExit(*vm, exit, operands, recovery);
175         
176         LinkBuffer patchBuffer(jit, codeBlock);
177         exit.m_code = FINALIZE_CODE_IF(
178             shouldDumpDisassembly() || Options::verboseOSR() || Options::verboseDFGOSRExit(),
179             patchBuffer,
180             ("DFG OSR exit #%u (%s, %s) from %s, with operands = %s",
181                 exitIndex, toCString(exit.m_codeOrigin).data(),
182                 exitKindToString(exit.m_kind), toCString(*codeBlock).data(),
183                 toCString(ignoringContext<DumpContext>(operands)).data()));
184     }
185     
186     MacroAssembler::repatchJump(exit.codeLocationForRepatch(codeBlock), CodeLocationLabel(exit.m_code.code()));
187     
188     vm->osrExitJumpDestination = exit.m_code.code().executableAddress();
189 }
190
191 } // extern "C"
192
193 } } // namespace JSC::DFG
194
195 #endif // ENABLE(DFG_JIT)