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" 32#include "DFGJITCode.h" 33#include "DFGValueSource.h" 34#include "JSCInlines.h" 35#include <wtf/DataLog.h> 36#include <wtf/HashMap.h> 37 38namespace JSC { namespace DFG { 39 40void VariableEventStream::logEvent(const VariableEvent& event) 41{ 42 dataLogF("seq#%u:", static_cast<unsigned>(size())); 43 event.dump(WTF::dataFile()); 44 dataLogF(" "); 45} 46 47namespace { 48 49struct 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 84bool 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 109void VariableEventStream::reconstruct( 110 CodeBlock* codeBlock, CodeOrigin codeOrigin, MinifiedGraph& graph, 111 unsigned index, Operands<ValueRecovery>& valueRecoveries) const 112{ 113 ASSERT(codeBlock->jitType() == JITCode::DFGJIT); 114 CodeBlock* baselineCodeBlock = codeBlock->baselineVersion(); 115 116 unsigned numVariables; 117 if (codeOrigin.inlineCallFrame) 118 numVariables = baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame)->m_numCalleeRegisters + VirtualRegister(codeOrigin.inlineCallFrame->stackOffset).toLocal() + 1; 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); 127 for (size_t i = 0; i < valueRecoveries.size(); ++i) { 128 valueRecoveries[i] = ValueRecovery::displacedInJSStack( 129 VirtualRegister(valueRecoveries.operandForIndex(i)), DataFormatJS); 130 } 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 139 // Step 2: Create a mock-up of the DFG's state and execute the events. 140 Operands<ValueSource> operandSources(codeBlock->numParameters(), numVariables); 141 for (unsigned i = operandSources.size(); i--;) 142 operandSources[i] = ValueSource(SourceIsDead); 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: 166 if (operandSources.hasOperand(event.bytecodeRegister())) 167 operandSources.setOperand(event.bytecodeRegister(), ValueSource(event.id())); 168 break; 169 case SetLocalEvent: 170 if (operandSources.hasOperand(event.bytecodeRegister())) 171 operandSources.setOperand(event.bytecodeRegister(), ValueSource::forDataFormat(event.machineRegister(), event.dataFormat())); 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) { 195 valueRecoveries[i] = ValueRecovery::constant(jsUndefined()); 196 continue; 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 } 219} 220 221} } // namespace JSC::DFG 222 223#endif // ENABLE(DFG_JIT) 224 225