]>
Commit | Line | Data |
---|---|---|
93a37866 A |
1 | /* |
2 | * Copyright (C) 2012, 2013 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 "DFGVariableEventStream.h" | |
28 | ||
29 | #if ENABLE(DFG_JIT) | |
30 | ||
31 | #include "CodeBlock.h" | |
81345200 | 32 | #include "DFGJITCode.h" |
93a37866 | 33 | #include "DFGValueSource.h" |
81345200 | 34 | #include "JSCInlines.h" |
93a37866 A |
35 | #include <wtf/DataLog.h> |
36 | #include <wtf/HashMap.h> | |
37 | ||
38 | namespace JSC { namespace DFG { | |
39 | ||
40 | void VariableEventStream::logEvent(const VariableEvent& event) | |
41 | { | |
42 | dataLogF("seq#%u:", static_cast<unsigned>(size())); | |
43 | event.dump(WTF::dataFile()); | |
44 | dataLogF(" "); | |
45 | } | |
46 | ||
47 | namespace { | |
48 | ||
49 | struct MinifiedGenerationInfo { | |
50 | bool filled; // true -> in gpr/fpr/pair, false -> spilled | |
51 | VariableRepresentation u; | |
52 | DataFormat format; | |
53 | ||
54 | MinifiedGenerationInfo() | |
55 | : format(DataFormatNone) | |
56 | { | |
57 | } | |
58 | ||
59 | void update(const VariableEvent& event) | |
60 | { | |
61 | switch (event.kind()) { | |
62 | case BirthToFill: | |
63 | case Fill: | |
64 | filled = true; | |
65 | break; | |
66 | case BirthToSpill: | |
67 | case Spill: | |
68 | filled = false; | |
69 | break; | |
70 | case Death: | |
71 | format = DataFormatNone; | |
72 | return; | |
73 | default: | |
74 | return; | |
75 | } | |
76 | ||
77 | u = event.variableRepresentation(); | |
78 | format = event.dataFormat(); | |
79 | } | |
80 | }; | |
81 | ||
82 | } // namespace | |
83 | ||
84 | bool VariableEventStream::tryToSetConstantRecovery(ValueRecovery& recovery, CodeBlock* codeBlock, MinifiedNode* node) const | |
85 | { | |
86 | if (!node) | |
87 | return false; | |
88 | ||
89 | if (node->hasConstantNumber()) { | |
90 | recovery = ValueRecovery::constant( | |
91 | codeBlock->constantRegister( | |
92 | FirstConstantRegisterIndex + node->constantNumber()).get()); | |
93 | return true; | |
94 | } | |
95 | ||
96 | if (node->hasWeakConstant()) { | |
97 | recovery = ValueRecovery::constant(node->weakConstant()); | |
98 | return true; | |
99 | } | |
100 | ||
101 | if (node->op() == PhantomArguments) { | |
102 | recovery = ValueRecovery::argumentsThatWereNotCreated(); | |
103 | return true; | |
104 | } | |
105 | ||
106 | return false; | |
107 | } | |
108 | ||
109 | void VariableEventStream::reconstruct( | |
110 | CodeBlock* codeBlock, CodeOrigin codeOrigin, MinifiedGraph& graph, | |
111 | unsigned index, Operands<ValueRecovery>& valueRecoveries) const | |
112 | { | |
81345200 | 113 | ASSERT(codeBlock->jitType() == JITCode::DFGJIT); |
93a37866 A |
114 | CodeBlock* baselineCodeBlock = codeBlock->baselineVersion(); |
115 | ||
116 | unsigned numVariables; | |
117 | if (codeOrigin.inlineCallFrame) | |
81345200 | 118 | numVariables = baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame)->m_numCalleeRegisters + VirtualRegister(codeOrigin.inlineCallFrame->stackOffset).toLocal() + 1; |
93a37866 A |
119 | else |
120 | numVariables = baselineCodeBlock->m_numCalleeRegisters; | |
121 | ||
122 | // Crazy special case: if we're at index == 0 then this must be an argument check | |
123 | // failure, in which case all variables are already set up. The recoveries should | |
124 | // reflect this. | |
125 | if (!index) { | |
126 | valueRecoveries = Operands<ValueRecovery>(codeBlock->numParameters(), numVariables); | |
81345200 A |
127 | for (size_t i = 0; i < valueRecoveries.size(); ++i) { |
128 | valueRecoveries[i] = ValueRecovery::displacedInJSStack( | |
129 | VirtualRegister(valueRecoveries.operandForIndex(i)), DataFormatJS); | |
130 | } | |
93a37866 A |
131 | return; |
132 | } | |
133 | ||
134 | // Step 1: Find the last checkpoint, and figure out the number of virtual registers as we go. | |
135 | unsigned startIndex = index - 1; | |
136 | while (at(startIndex).kind() != Reset) | |
137 | startIndex--; | |
138 | ||
93a37866 A |
139 | // Step 2: Create a mock-up of the DFG's state and execute the events. |
140 | Operands<ValueSource> operandSources(codeBlock->numParameters(), numVariables); | |
81345200 A |
141 | for (unsigned i = operandSources.size(); i--;) |
142 | operandSources[i] = ValueSource(SourceIsDead); | |
93a37866 A |
143 | HashMap<MinifiedID, MinifiedGenerationInfo> generationInfos; |
144 | for (unsigned i = startIndex; i < index; ++i) { | |
145 | const VariableEvent& event = at(i); | |
146 | switch (event.kind()) { | |
147 | case Reset: | |
148 | // nothing to do. | |
149 | break; | |
150 | case BirthToFill: | |
151 | case BirthToSpill: { | |
152 | MinifiedGenerationInfo info; | |
153 | info.update(event); | |
154 | generationInfos.add(event.id(), info); | |
155 | break; | |
156 | } | |
157 | case Fill: | |
158 | case Spill: | |
159 | case Death: { | |
160 | HashMap<MinifiedID, MinifiedGenerationInfo>::iterator iter = generationInfos.find(event.id()); | |
161 | ASSERT(iter != generationInfos.end()); | |
162 | iter->value.update(event); | |
163 | break; | |
164 | } | |
165 | case MovHintEvent: | |
81345200 A |
166 | if (operandSources.hasOperand(event.bytecodeRegister())) |
167 | operandSources.setOperand(event.bytecodeRegister(), ValueSource(event.id())); | |
93a37866 A |
168 | break; |
169 | case SetLocalEvent: | |
81345200 A |
170 | if (operandSources.hasOperand(event.bytecodeRegister())) |
171 | operandSources.setOperand(event.bytecodeRegister(), ValueSource::forDataFormat(event.machineRegister(), event.dataFormat())); | |
93a37866 A |
172 | break; |
173 | default: | |
174 | RELEASE_ASSERT_NOT_REACHED(); | |
175 | break; | |
176 | } | |
177 | } | |
178 | ||
179 | // Step 3: Compute value recoveries! | |
180 | valueRecoveries = Operands<ValueRecovery>(codeBlock->numParameters(), numVariables); | |
181 | for (unsigned i = 0; i < operandSources.size(); ++i) { | |
182 | ValueSource& source = operandSources[i]; | |
183 | if (source.isTriviallyRecoverable()) { | |
184 | valueRecoveries[i] = source.valueRecovery(); | |
185 | continue; | |
186 | } | |
187 | ||
188 | ASSERT(source.kind() == HaveNode); | |
189 | MinifiedNode* node = graph.at(source.id()); | |
190 | if (tryToSetConstantRecovery(valueRecoveries[i], codeBlock, node)) | |
191 | continue; | |
192 | ||
193 | MinifiedGenerationInfo info = generationInfos.get(source.id()); | |
194 | if (info.format == DataFormatNone) { | |
81345200 A |
195 | valueRecoveries[i] = ValueRecovery::constant(jsUndefined()); |
196 | continue; | |
93a37866 A |
197 | } |
198 | ||
199 | ASSERT(info.format != DataFormatNone); | |
200 | ||
201 | if (info.filled) { | |
202 | if (info.format == DataFormatDouble) { | |
203 | valueRecoveries[i] = ValueRecovery::inFPR(info.u.fpr); | |
204 | continue; | |
205 | } | |
206 | #if USE(JSVALUE32_64) | |
207 | if (info.format & DataFormatJS) { | |
208 | valueRecoveries[i] = ValueRecovery::inPair(info.u.pair.tagGPR, info.u.pair.payloadGPR); | |
209 | continue; | |
210 | } | |
211 | #endif | |
212 | valueRecoveries[i] = ValueRecovery::inGPR(info.u.gpr, info.format); | |
213 | continue; | |
214 | } | |
215 | ||
216 | valueRecoveries[i] = | |
217 | ValueRecovery::displacedInJSStack(static_cast<VirtualRegister>(info.u.virtualReg), info.format); | |
218 | } | |
93a37866 A |
219 | } |
220 | ||
221 | } } // namespace JSC::DFG | |
222 | ||
223 | #endif // ENABLE(DFG_JIT) | |
224 |