]>
Commit | Line | Data |
---|---|---|
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) | |
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 "RepatchBuffer.h" | |
39 | #include <wtf/StringPrintStream.h> | |
40 | ||
41 | namespace JSC { namespace DFG { | |
42 | ||
43 | void OSRExitCompiler::emitRestoreArguments(const Operands<ValueRecovery>& operands) | |
44 | { | |
45 | HashMap<MinifiedID, int> alreadyAllocatedArguments; // Maps phantom arguments node ID to operand. | |
46 | for (size_t index = 0; index < operands.size(); ++index) { | |
47 | const ValueRecovery& recovery = operands[index]; | |
48 | int operand = operands.operandForIndex(index); | |
49 | ||
50 | if (recovery.technique() != DirectArgumentsThatWereNotCreated | |
51 | && recovery.technique() != ClonedArgumentsThatWereNotCreated) | |
52 | continue; | |
53 | ||
54 | MinifiedID id = recovery.nodeID(); | |
55 | auto iter = alreadyAllocatedArguments.find(id); | |
56 | if (iter != alreadyAllocatedArguments.end()) { | |
57 | JSValueRegs regs = JSValueRegs::withTwoAvailableRegs(GPRInfo::regT0, GPRInfo::regT1); | |
58 | m_jit.loadValue(CCallHelpers::addressFor(iter->value), regs); | |
59 | m_jit.storeValue(regs, CCallHelpers::addressFor(operand)); | |
60 | continue; | |
61 | } | |
62 | ||
63 | InlineCallFrame* inlineCallFrame = | |
64 | m_jit.codeBlock()->jitCode()->dfg()->minifiedDFG.at(id)->inlineCallFrame(); | |
65 | ||
66 | int stackOffset; | |
67 | if (inlineCallFrame) | |
68 | stackOffset = inlineCallFrame->stackOffset; | |
69 | else | |
70 | stackOffset = 0; | |
71 | ||
72 | if (!inlineCallFrame || inlineCallFrame->isClosureCall) { | |
73 | m_jit.loadPtr( | |
74 | AssemblyHelpers::addressFor(stackOffset + JSStack::Callee), | |
75 | GPRInfo::regT0); | |
76 | } else { | |
77 | m_jit.move( | |
78 | AssemblyHelpers::TrustedImmPtr(inlineCallFrame->calleeRecovery.constant().asCell()), | |
79 | GPRInfo::regT0); | |
80 | } | |
81 | ||
82 | if (!inlineCallFrame || inlineCallFrame->isVarargs()) { | |
83 | m_jit.load32( | |
84 | AssemblyHelpers::payloadFor(stackOffset + JSStack::ArgumentCount), | |
85 | GPRInfo::regT1); | |
86 | } else { | |
87 | m_jit.move( | |
88 | AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), | |
89 | GPRInfo::regT1); | |
90 | } | |
91 | ||
92 | m_jit.setupArgumentsWithExecState( | |
93 | AssemblyHelpers::TrustedImmPtr(inlineCallFrame), GPRInfo::regT0, GPRInfo::regT1); | |
94 | switch (recovery.technique()) { | |
95 | case DirectArgumentsThatWereNotCreated: | |
96 | m_jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(operationCreateDirectArgumentsDuringExit)), GPRInfo::nonArgGPR0); | |
97 | break; | |
98 | case ClonedArgumentsThatWereNotCreated: | |
99 | m_jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(operationCreateClonedArgumentsDuringExit)), GPRInfo::nonArgGPR0); | |
100 | break; | |
101 | default: | |
102 | RELEASE_ASSERT_NOT_REACHED(); | |
103 | break; | |
104 | } | |
105 | m_jit.call(GPRInfo::nonArgGPR0); | |
106 | m_jit.storeCell(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(operand)); | |
107 | ||
108 | alreadyAllocatedArguments.add(id, operand); | |
109 | } | |
110 | } | |
111 | ||
112 | extern "C" { | |
113 | ||
114 | void compileOSRExit(ExecState* exec) | |
115 | { | |
116 | SamplingRegion samplingRegion("DFG OSR Exit Compilation"); | |
117 | ||
118 | CodeBlock* codeBlock = exec->codeBlock(); | |
119 | ||
120 | ASSERT(codeBlock); | |
121 | ASSERT(codeBlock->jitType() == JITCode::DFGJIT); | |
122 | ||
123 | VM* vm = &exec->vm(); | |
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 | prepareCodeOriginForOSRExit(exec, exit.m_codeOrigin); | |
133 | ||
134 | // Compute the value recoveries. | |
135 | Operands<ValueRecovery> operands; | |
136 | codeBlock->jitCode()->dfg()->variableEventStream.reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->jitCode()->dfg()->minifiedDFG, exit.m_streamIndex, operands); | |
137 | ||
138 | SpeculationRecovery* recovery = 0; | |
139 | if (exit.m_recoveryIndex != UINT_MAX) | |
140 | recovery = &codeBlock->jitCode()->dfg()->speculationRecovery[exit.m_recoveryIndex]; | |
141 | ||
142 | { | |
143 | CCallHelpers jit(vm, codeBlock); | |
144 | OSRExitCompiler exitCompiler(jit); | |
145 | ||
146 | jit.jitAssertHasValidCallFrame(); | |
147 | ||
148 | if (vm->m_perBytecodeProfiler && codeBlock->jitCode()->dfgCommon()->compilation) { | |
149 | Profiler::Database& database = *vm->m_perBytecodeProfiler; | |
150 | Profiler::Compilation* compilation = codeBlock->jitCode()->dfgCommon()->compilation.get(); | |
151 | ||
152 | Profiler::OSRExit* profilerExit = compilation->addOSRExit( | |
153 | exitIndex, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin), | |
154 | exit.m_kind, exit.m_kind == UncountableInvalidation); | |
155 | jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress())); | |
156 | } | |
157 | ||
158 | exitCompiler.compileExit(exit, operands, recovery); | |
159 | ||
160 | LinkBuffer patchBuffer(*vm, jit, codeBlock); | |
161 | exit.m_code = FINALIZE_CODE_IF( | |
162 | shouldShowDisassembly() || Options::verboseOSR(), | |
163 | patchBuffer, | |
164 | ("DFG OSR exit #%u (%s, %s) from %s, with operands = %s", | |
165 | exitIndex, toCString(exit.m_codeOrigin).data(), | |
166 | exitKindToString(exit.m_kind), toCString(*codeBlock).data(), | |
167 | toCString(ignoringContext<DumpContext>(operands)).data())); | |
168 | } | |
169 | ||
170 | { | |
171 | RepatchBuffer repatchBuffer(codeBlock); | |
172 | repatchBuffer.relink(exit.codeLocationForRepatch(codeBlock), CodeLocationLabel(exit.m_code.code())); | |
173 | } | |
174 | ||
175 | vm->osrExitJumpDestination = exit.m_code.code().executableAddress(); | |
176 | } | |
177 | ||
178 | } // extern "C" | |
179 | ||
180 | } } // namespace JSC::DFG | |
181 | ||
182 | #endif // ENABLE(DFG_JIT) |