2 * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGVariableEventStream.h"
31 #include "CodeBlock.h"
32 #include "DFGValueSource.h"
33 #include "Operations.h"
34 #include <wtf/DataLog.h>
35 #include <wtf/HashMap.h>
37 namespace JSC
{ namespace DFG
{
39 void VariableEventStream::logEvent(const VariableEvent
& event
)
41 dataLogF("seq#%u:", static_cast<unsigned>(size()));
42 event
.dump(WTF::dataFile());
48 struct MinifiedGenerationInfo
{
49 bool filled
; // true -> in gpr/fpr/pair, false -> spilled
50 VariableRepresentation u
;
53 MinifiedGenerationInfo()
54 : format(DataFormatNone
)
58 void update(const VariableEvent
& event
)
60 switch (event
.kind()) {
70 format
= DataFormatNone
;
76 u
= event
.variableRepresentation();
77 format
= event
.dataFormat();
83 bool VariableEventStream::tryToSetConstantRecovery(ValueRecovery
& recovery
, CodeBlock
* codeBlock
, MinifiedNode
* node
) const
88 if (node
->hasConstantNumber()) {
89 recovery
= ValueRecovery::constant(
90 codeBlock
->constantRegister(
91 FirstConstantRegisterIndex
+ node
->constantNumber()).get());
95 if (node
->hasWeakConstant()) {
96 recovery
= ValueRecovery::constant(node
->weakConstant());
100 if (node
->op() == PhantomArguments
) {
101 recovery
= ValueRecovery::argumentsThatWereNotCreated();
108 void VariableEventStream::reconstruct(
109 CodeBlock
* codeBlock
, CodeOrigin codeOrigin
, MinifiedGraph
& graph
,
110 unsigned index
, Operands
<ValueRecovery
>& valueRecoveries
) const
112 ASSERT(codeBlock
->getJITType() == JITCode::DFGJIT
);
113 CodeBlock
* baselineCodeBlock
= codeBlock
->baselineVersion();
115 unsigned numVariables
;
116 if (codeOrigin
.inlineCallFrame
)
117 numVariables
= baselineCodeBlockForInlineCallFrame(codeOrigin
.inlineCallFrame
)->m_numCalleeRegisters
+ codeOrigin
.inlineCallFrame
->stackOffset
;
119 numVariables
= baselineCodeBlock
->m_numCalleeRegisters
;
121 // Crazy special case: if we're at index == 0 then this must be an argument check
122 // failure, in which case all variables are already set up. The recoveries should
125 valueRecoveries
= Operands
<ValueRecovery
>(codeBlock
->numParameters(), numVariables
);
126 for (size_t i
= 0; i
< valueRecoveries
.size(); ++i
)
127 valueRecoveries
[i
] = ValueRecovery::alreadyInJSStack();
131 // Step 1: Find the last checkpoint, and figure out the number of virtual registers as we go.
132 unsigned startIndex
= index
- 1;
133 while (at(startIndex
).kind() != Reset
)
136 #if DFG_ENABLE(DEBUG_VERBOSE)
137 dataLogF("Computing OSR exit recoveries starting at seq#%u.\n", startIndex
);
140 // Step 2: Create a mock-up of the DFG's state and execute the events.
141 Operands
<ValueSource
> operandSources(codeBlock
->numParameters(), numVariables
);
142 HashMap
<MinifiedID
, MinifiedGenerationInfo
> generationInfos
;
143 for (unsigned i
= startIndex
; i
< index
; ++i
) {
144 const VariableEvent
& event
= at(i
);
145 switch (event
.kind()) {
151 MinifiedGenerationInfo info
;
153 generationInfos
.add(event
.id(), info
);
159 HashMap
<MinifiedID
, MinifiedGenerationInfo
>::iterator iter
= generationInfos
.find(event
.id());
160 ASSERT(iter
!= generationInfos
.end());
161 iter
->value
.update(event
);
165 if (operandSources
.hasOperand(event
.operand()))
166 operandSources
.setOperand(event
.operand(), ValueSource(event
.id()));
169 if (operandSources
.hasOperand(event
.operand()))
170 operandSources
.setOperand(event
.operand(), ValueSource::forDataFormat(event
.dataFormat()));
173 RELEASE_ASSERT_NOT_REACHED();
178 // Step 3: Compute value recoveries!
179 valueRecoveries
= Operands
<ValueRecovery
>(codeBlock
->numParameters(), numVariables
);
180 for (unsigned i
= 0; i
< operandSources
.size(); ++i
) {
181 ValueSource
& source
= operandSources
[i
];
182 if (source
.isTriviallyRecoverable()) {
183 valueRecoveries
[i
] = source
.valueRecovery();
187 ASSERT(source
.kind() == HaveNode
);
188 MinifiedNode
* node
= graph
.at(source
.id());
189 if (tryToSetConstantRecovery(valueRecoveries
[i
], codeBlock
, node
))
192 MinifiedGenerationInfo info
= generationInfos
.get(source
.id());
193 if (info
.format
== DataFormatNone
) {
194 // Try to see if there is an alternate node that would contain the value we want.
195 // There are four possibilities:
197 // Int32ToDouble: We can use this in place of the original node, but
198 // we'd rather not; so we use it only if it is the only remaining
201 // ValueToInt32: If the only remaining live version of the value is
202 // ValueToInt32, then we can use it.
204 // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber
205 // then the only remaining uses are ones that want a properly formed number
206 // rather than a UInt32 intermediate.
208 // DoubleAsInt32: Same as UInt32ToNumber.
210 // The reverse of the above: This node could be a UInt32ToNumber, but its
211 // alternative is still alive. This means that the only remaining uses of
212 // the number would be fine with a UInt32 intermediate.
216 if (node
&& node
->op() == UInt32ToNumber
) {
217 MinifiedID id
= node
->child1();
218 if (tryToSetConstantRecovery(valueRecoveries
[i
], codeBlock
, graph
.at(id
)))
220 info
= generationInfos
.get(id
);
221 if (info
.format
!= DataFormatNone
)
226 MinifiedID int32ToDoubleID
;
227 MinifiedID valueToInt32ID
;
228 MinifiedID uint32ToNumberID
;
229 MinifiedID doubleAsInt32ID
;
231 HashMap
<MinifiedID
, MinifiedGenerationInfo
>::iterator iter
= generationInfos
.begin();
232 HashMap
<MinifiedID
, MinifiedGenerationInfo
>::iterator end
= generationInfos
.end();
233 for (; iter
!= end
; ++iter
) {
234 MinifiedID id
= iter
->key
;
238 if (!node
->hasChild1())
240 if (node
->child1() != source
.id())
242 if (iter
->value
.format
== DataFormatNone
)
244 switch (node
->op()) {
246 case ForwardInt32ToDouble
:
247 int32ToDoubleID
= id
;
253 uint32ToNumberID
= id
;
256 doubleAsInt32ID
= id
;
264 if (!!doubleAsInt32ID
)
265 idToUse
= doubleAsInt32ID
;
266 else if (!!int32ToDoubleID
)
267 idToUse
= int32ToDoubleID
;
268 else if (!!valueToInt32ID
)
269 idToUse
= valueToInt32ID
;
270 else if (!!uint32ToNumberID
)
271 idToUse
= uint32ToNumberID
;
274 info
= generationInfos
.get(idToUse
);
275 ASSERT(info
.format
!= DataFormatNone
);
281 valueRecoveries
[i
] = ValueRecovery::constant(jsUndefined());
286 ASSERT(info
.format
!= DataFormatNone
);
289 if (info
.format
== DataFormatDouble
) {
290 valueRecoveries
[i
] = ValueRecovery::inFPR(info
.u
.fpr
);
293 #if USE(JSVALUE32_64)
294 if (info
.format
& DataFormatJS
) {
295 valueRecoveries
[i
] = ValueRecovery::inPair(info
.u
.pair
.tagGPR
, info
.u
.pair
.payloadGPR
);
299 valueRecoveries
[i
] = ValueRecovery::inGPR(info
.u
.gpr
, info
.format
);
304 ValueRecovery::displacedInJSStack(static_cast<VirtualRegister
>(info
.u
.virtualReg
), info
.format
);
307 // Step 4: Make sure that for locals that coincide with true call frame headers, the exit compiler knows
308 // that those values don't have to be recovered. Signal this by using ValueRecovery::alreadyInJSStack()
309 for (InlineCallFrame
* inlineCallFrame
= codeOrigin
.inlineCallFrame
; inlineCallFrame
; inlineCallFrame
= inlineCallFrame
->caller
.inlineCallFrame
) {
310 for (unsigned i
= JSStack::CallFrameHeaderSize
; i
--;)
311 valueRecoveries
.setLocal(inlineCallFrame
->stackOffset
- i
- 1, ValueRecovery::alreadyInJSStack());
315 } } // namespace JSC::DFG
317 #endif // ENABLE(DFG_JIT)