Changeset 94629 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Sep 6, 2011, 7:47:51 PM (14 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 1 added
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r94627 r94629 1 2011-09-06 Filip Pizlo <[email protected]> 2 3 DFG JIT does not optimize booleans 4 https://bugs.webkit.org/show_bug.cgi?id=67670 5 6 Reviewed by Gavin Barraclough. 7 8 This adds boolean value profiling, boolean prediction in the DFG, 9 boolean forward flow propagation in the DFGPropagator, boolean 10 data format in DFG generation info, and comprehensive optimizations 11 based on both boolean prediction and boolean generation info. 12 This is brings the speed-up on v8-richards to 12%, and gives slight 13 speed-ups elsewhere as well. 14 15 Making this work right required navigating some subtleties in 16 value profiling. Some functions get compiled with insufficient 17 information because some important path of the function never 18 executed. In these cases, we wish to fall back on static 19 speculation. But to do so, we need to ensure that predictions that 20 are inherent in the code (like that GetById almost certainly takes 21 a cell operand) are reflected in predictions that we make in 22 DFGPropagator. Thus, DFGPropagator now does both backward and 23 forward flow, using a both forward and backward fixpoint. 24 25 The backward flow in DFGPropagator is a separate static analysis, 26 and needs to keep a set of backward flow abstract values for 27 variables, arguments, and globals. To make this easy, this patch 28 factors out DFGGraph's prediction tracking capability into 29 DFGPredictionTracker, which now gets used by both DFGGraph (for 30 forward flow predictions) and DFGPropagator (for backward flow 31 predictions). Backward flow predictions eventually get merged 32 into forward flow ones, but the two are not equivalent: a forward 33 flow prediction is a superset of the backward flow prediction. 34 35 Debugging these prediction issues required a better understanding 36 of where we fail speculation, and what our value predictions look 37 like. This patch also adds optional verbose speculation failure 38 (so an informative printf fires whenever speculation failure occurs) 39 and slight improvements to the verbosity in other places. 40 41 * bytecode/ValueProfile.h: 42 (JSC::ValueProfile::numberOfBooleans): 43 (JSC::ValueProfile::probabilityOfBoolean): 44 (JSC::ValueProfile::dump): 45 (JSC::ValueProfile::computeStatistics): 46 * dfg/DFGByteCodeParser.cpp: 47 (JSC::DFG::ByteCodeParser::stronglyPredict): 48 (JSC::DFG::ByteCodeParser::parseBlock): 49 * dfg/DFGGenerationInfo.h: 50 (JSC::DFG::dataFormatToString): 51 (JSC::DFG::needDataFormatConversion): 52 * dfg/DFGGraph.cpp: 53 (JSC::DFG::Graph::dump): 54 (JSC::DFG::Graph::predictArgumentTypes): 55 * dfg/DFGGraph.h: 56 (JSC::DFG::Graph::Graph): 57 (JSC::DFG::Graph::predictions): 58 (JSC::DFG::Graph::predict): 59 (JSC::DFG::Graph::predictGlobalVar): 60 (JSC::DFG::Graph::getPrediction): 61 (JSC::DFG::Graph::getGlobalVarPrediction): 62 (JSC::DFG::Graph::isBooleanConstant): 63 (JSC::DFG::Graph::valueOfBooleanConstant): 64 * dfg/DFGJITCodeGenerator.cpp: 65 (JSC::DFG::JITCodeGenerator::fillInteger): 66 (JSC::DFG::JITCodeGenerator::fillDouble): 67 (JSC::DFG::JITCodeGenerator::fillJSValue): 68 (JSC::DFG::JITCodeGenerator::isKnownNotInteger): 69 (JSC::DFG::JITCodeGenerator::isKnownBoolean): 70 (JSC::DFG::JITCodeGenerator::nonSpeculativeNonPeepholeCompareNull): 71 (JSC::DFG::JITCodeGenerator::nonSpeculativeNonPeepholeCompare): 72 (JSC::DFG::JITCodeGenerator::nonSpeculativeNonPeepholeStrictEq): 73 (JSC::DFG::JITCodeGenerator::emitBranch): 74 (JSC::DFG::JITCodeGenerator::speculationCheck): 75 (JSC::DFG::GPRTemporary::GPRTemporary): 76 * dfg/DFGJITCodeGenerator.h: 77 (JSC::DFG::JITCodeGenerator::isBooleanConstant): 78 (JSC::DFG::JITCodeGenerator::valueOfBooleanConstant): 79 * dfg/DFGJITCompiler.cpp: 80 (JSC::DFG::JITCompiler::jumpFromSpeculativeToNonSpeculative): 81 (JSC::DFG::JITCompiler::link): 82 * dfg/DFGJITCompiler.h: 83 (JSC::DFG::JITCompiler::debugCall): 84 (JSC::DFG::JITCompiler::isBooleanConstant): 85 (JSC::DFG::JITCompiler::valueOfBooleanConstant): 86 * dfg/DFGNode.h: 87 (JSC::DFG::isBooleanPrediction): 88 (JSC::DFG::predictionToString): 89 (JSC::DFG::mergePredictions): 90 (JSC::DFG::makePrediction): 91 (JSC::DFG::Node::isBooleanConstant): 92 (JSC::DFG::Node::valueOfBooleanConstant): 93 (JSC::DFG::Node::hasBooleanResult): 94 (JSC::DFG::Node::hasNumericResult): 95 (JSC::DFG::Node::predict): 96 * dfg/DFGOperations.cpp: 97 * dfg/DFGOperations.h: 98 * dfg/DFGPredictionTracker.h: Added. 99 (JSC::DFG::operandIsArgument): 100 (JSC::DFG::PredictionSlot::PredictionSlot): 101 (JSC::DFG::PredictionTracker::PredictionTracker): 102 (JSC::DFG::PredictionTracker::initializeSimilarTo): 103 (JSC::DFG::PredictionTracker::numberOfArguments): 104 (JSC::DFG::PredictionTracker::numberOfVariables): 105 (JSC::DFG::PredictionTracker::argumentIndexForOperand): 106 (JSC::DFG::PredictionTracker::predictArgument): 107 (JSC::DFG::PredictionTracker::predict): 108 (JSC::DFG::PredictionTracker::predictGlobalVar): 109 (JSC::DFG::PredictionTracker::getArgumentPrediction): 110 (JSC::DFG::PredictionTracker::getPrediction): 111 (JSC::DFG::PredictionTracker::getGlobalVarPrediction): 112 * dfg/DFGPropagator.cpp: 113 (JSC::DFG::Propagator::Propagator): 114 (JSC::DFG::Propagator::fixpoint): 115 (JSC::DFG::Propagator::setPrediction): 116 (JSC::DFG::Propagator::mergeUse): 117 (JSC::DFG::Propagator::mergePrediction): 118 (JSC::DFG::Propagator::propagateNode): 119 * dfg/DFGSpeculativeJIT.cpp: 120 (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): 121 (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): 122 (JSC::DFG::SpeculativeJIT::fillSpeculateCell): 123 (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): 124 (JSC::DFG::SpeculativeJIT::compare): 125 (JSC::DFG::SpeculativeJIT::compile): 126 * dfg/DFGSpeculativeJIT.h: 127 (JSC::DFG::SpeculateBooleanOperand::SpeculateBooleanOperand): 128 (JSC::DFG::SpeculateBooleanOperand::~SpeculateBooleanOperand): 129 (JSC::DFG::SpeculateBooleanOperand::index): 130 (JSC::DFG::SpeculateBooleanOperand::gpr): 131 (JSC::DFG::SpeculateBooleanOperand::use): 132 * runtime/JSGlobalData.h: 133 * runtime/JSValue.cpp: 134 (JSC::JSValue::description): 135 1 136 2011-09-06 Mark Hahnenberg <[email protected]> 2 137 -
trunk/Source/JavaScriptCore/bytecode/ValueProfile.h
r94559 r94629 118 118 return result; 119 119 } 120 121 unsigned numberOfBooleans() const 122 { 123 unsigned result = 0; 124 for (unsigned i = 0; i < numberOfBuckets; ++i) { 125 if (!!buckets[i] && JSValue::decode(buckets[i]).isBoolean()) 126 result++; 127 } 128 return result; 129 } 120 130 121 131 // These methods are not particularly optimized, in that they will each … … 143 153 return computeProbability(numberOfArrays(), numberOfSamples()); 144 154 } 155 156 unsigned probabilityOfBoolean() const 157 { 158 return computeProbability(numberOfBooleans(), numberOfSamples()); 159 } 145 160 146 161 #ifndef NDEBUG … … 148 163 { 149 164 fprintf(out, 150 "samples = %u, int32 = %u , double = %u, cell = %u, array = %u",165 "samples = %u, int32 = %u (%u), double = %u (%u), cell = %u (%u), array = %u (%u), boolean = %u (%u)", 151 166 numberOfSamples(), 152 numberOfInt32s(), 153 numberOfDoubles(), 154 numberOfCells(), 155 numberOfArrays()); 167 probabilityOfInt32(), numberOfInt32s(), 168 probabilityOfDouble(), numberOfDoubles(), 169 probabilityOfCell(), numberOfCells(), 170 probabilityOfArray(), numberOfArrays(), 171 probabilityOfBoolean(), numberOfBooleans()); 156 172 bool first = true; 157 173 for (unsigned i = 0; i < numberOfBuckets; ++i) { … … 179 195 unsigned cells; 180 196 unsigned arrays; 197 unsigned booleans; 181 198 }; 182 199 … … 184 201 void computeStatistics(JSGlobalData& globalData, Statistics& statistics) const 185 202 { 186 unsigned samples = 0; 187 unsigned int32s = 0; 188 unsigned doubles = 0; 189 unsigned cells = 0; 190 unsigned arrays = 0; 203 unsigned samples = 0; 204 unsigned int32s = 0; 205 unsigned doubles = 0; 206 unsigned cells = 0; 207 unsigned arrays = 0; 208 unsigned booleans = 0; 191 209 192 210 for (unsigned i = 0; i < numberOfBuckets; ++i) { … … 214 232 if (isJSArray(&globalData, value.asCell())) 215 233 arrays++; 216 } 217 } 218 219 statistics.samples = samples; 220 statistics.int32s = int32s; 221 statistics.doubles = doubles; 222 statistics.cells = cells; 223 statistics.arrays = arrays; 234 } else if (value.isBoolean()) 235 booleans++; 236 } 237 238 statistics.samples = samples; 239 statistics.int32s = int32s; 240 statistics.doubles = doubles; 241 statistics.cells = cells; 242 statistics.arrays = arrays; 243 statistics.booleans = booleans; 224 244 } 225 245 -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r94559 r94629 476 476 ASSERT(profile); 477 477 #if DFG_DEBUG_VERBOSE 478 printf("Dynamic pr ediction[%u, %u]: ", nodeIndex, bytecodeIndex);478 printf("Dynamic profile [%u, %u]: ", nodeIndex, bytecodeIndex); 479 479 profile->dump(stdout); 480 480 printf("\n"); 481 481 #endif 482 482 m_graph[nodeIndex].predict(makePrediction(*m_globalData, *profile), StrongPrediction); 483 #if DFG_DEBUG_VERBOSE 484 printf(" Prediction: %s\n", predictionToString(m_graph[nodeIndex].getPrediction())); 485 #endif 483 486 #else 484 487 UNUSED_PARAM(nodeIndex); -
trunk/Source/JavaScriptCore/dfg/DFGGenerationInfo.h
r92986 r94629 43 43 DataFormatInteger = 1, 44 44 DataFormatDouble = 2, 45 DataFormatCell = 3, 45 DataFormatBoolean = 3, 46 DataFormatCell = 4, 46 47 DataFormatJS = 8, 47 48 DataFormatJSInteger = DataFormatJS | DataFormatInteger, 48 49 DataFormatJSDouble = DataFormatJS | DataFormatDouble, 49 50 DataFormatJSCell = DataFormatJS | DataFormatCell, 51 DataFormatJSBoolean = DataFormatJS | DataFormatBoolean 50 52 }; 51 53 … … 62 64 case DataFormatCell: 63 65 return "Cell"; 66 case DataFormatBoolean: 67 return "Boolean"; 64 68 case DataFormatJS: 65 69 return "JS"; … … 70 74 case DataFormatJSCell: 71 75 return "JSCell"; 76 case DataFormatJSBoolean: 77 return "JSBoolean"; 72 78 default: 73 79 return "Unknown"; … … 89 95 case DataFormatJSDouble: 90 96 case DataFormatJSCell: 97 case DataFormatJSBoolean: 91 98 switch (to) { 92 99 case DataFormatInteger: … … 98 105 case DataFormatJSDouble: 99 106 case DataFormatJSCell: 107 case DataFormatJSBoolean: 100 108 return false; 101 109 default: 110 // This captures DataFormatBoolean, which is currently unused. 102 111 ASSERT_NOT_REACHED(); 103 112 } 104 113 default: 114 // This captures DataFormatBoolean, which is currently unused. 105 115 ASSERT_NOT_REACHED(); 106 116 } -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r94559 r94629 53 53 54 54 unsigned refCount = node.refCount(); 55 if (!refCount) 55 if (!refCount) { 56 printf("% 4d:\tskipped %s\n", (int)nodeIndex, opName(op)); 56 57 return; 58 } 57 59 bool mustGenerate = node.mustGenerate(); 58 60 if (mustGenerate) … … 194 196 { 195 197 if (exec) { 196 size_t numberOfArguments = std::min(exec->argumentCountIncludingThis(), m_ argumentPredictions.size());198 size_t numberOfArguments = std::min(exec->argumentCountIncludingThis(), m_predictions.numberOfArguments()); 197 199 198 200 for (size_t arg = 1; arg < numberOfArguments; ++arg) { 199 201 JSValue argumentValue = exec->argument(arg - 1); 200 202 if (argumentValue.isInt32()) 201 m_ argumentPredictions[arg].m_value |= PredictInt32;203 m_predictions.predictArgument(arg, PredictInt32, WeakPrediction); 202 204 else if (argumentValue.isDouble()) 203 m_ argumentPredictions[arg].m_value |= PredictDouble;205 m_predictions.predictArgument(arg, PredictDouble, WeakPrediction); 204 206 } 205 207 } … … 223 225 #endif 224 226 225 m ergePrediction(m_argumentPredictions[arg].m_value, makePrediction(globalData, *profile));227 m_predictions.predictArgument(arg, makePrediction(globalData, *profile) & ~PredictionTagMask, StrongPrediction); 226 228 227 229 #if DFG_DEBUG_VERBOSE 228 printf(" Prediction: %s\n", predictionToString(m_ argumentPredictions[arg].m_value));230 printf(" Prediction: %s\n", predictionToString(m_predictions.getArgumentPrediction(arg))); 229 231 #endif 230 232 } -
trunk/Source/JavaScriptCore/dfg/DFGGraph.h
r94559 r94629 31 31 #include "CodeBlock.h" 32 32 #include "DFGNode.h" 33 #include "DFGPredictionTracker.h" 33 34 #include "RegisterFile.h" 34 35 #include <wtf/HashMap.h> … … 42 43 43 44 namespace DFG { 44 45 // helper function to distinguish vars & temporaries from arguments.46 inline bool operandIsArgument(int operand) { return operand < 0; }47 48 struct PredictionSlot {49 public:50 PredictionSlot()51 : m_value(PredictNone)52 {53 }54 PredictedType m_value;55 };56 45 57 46 typedef uint32_t BlockIndex; … … 104 93 public: 105 94 Graph(unsigned numArguments, unsigned numVariables) 106 : m_argumentPredictions(numArguments) 107 , m_variablePredictions(numVariables) 95 : m_predictions(numArguments, numVariables) 108 96 { 109 97 } … … 136 124 return *m_blocks[blockIndexForBytecodeOffset(bytecodeBegin)]; 137 125 } 138 126 127 PredictionTracker& predictions() 128 { 129 return m_predictions; 130 } 131 139 132 bool predict(int operand, PredictedType prediction, PredictionSource source) 140 133 { 141 if (operandIsArgument(operand)) { 142 unsigned argument = operand + m_argumentPredictions.size() + RegisterFile::CallFrameHeaderSize; 143 return mergePrediction(m_argumentPredictions[argument].m_value, makePrediction(prediction, source)); 144 } 145 146 if ((unsigned)operand >= m_variablePredictions.size()) { 147 ASSERT(operand >= 0); 148 m_variablePredictions.resize(operand + 1); 149 } 150 151 return mergePrediction(m_variablePredictions[operand].m_value, makePrediction(prediction, source)); 134 return m_predictions.predict(operand, prediction, source); 152 135 } 153 136 154 137 bool predictGlobalVar(unsigned varNumber, PredictedType prediction, PredictionSource source) 155 138 { 156 HashMap<unsigned, PredictionSlot>::iterator iter = m_globalVarPredictions.find(varNumber + 1); 157 if (iter == m_globalVarPredictions.end()) { 158 PredictionSlot predictionSlot; 159 bool result = mergePrediction(predictionSlot.m_value, makePrediction(prediction, source)); 160 m_globalVarPredictions.add(varNumber + 1, predictionSlot); 161 return result; 162 } else 163 return mergePrediction(iter->second.m_value, makePrediction(prediction, source)); 139 return m_predictions.predictGlobalVar(varNumber, prediction, source); 164 140 } 165 141 166 142 bool predict(Node& node, PredictedType prediction, PredictionSource source) 167 143 { 168 switch (node.op) { 169 case GetLocal: 170 return predict(node.local(), prediction, source); 171 break; 172 case GetGlobalVar: 173 return predictGlobalVar(node.varNumber(), prediction, source); 174 case GetById: 175 case GetMethod: 176 case GetByVal: 177 case Call: 178 case Construct: 179 return node.predict(prediction, source); 180 default: 181 return false; 182 } 144 return m_predictions.predict(node, prediction, source); 183 145 } 184 146 185 147 PredictedType getPrediction(int operand) 186 148 { 187 if (operandIsArgument(operand)) { 188 unsigned argument = operand + m_argumentPredictions.size() + RegisterFile::CallFrameHeaderSize; 189 return m_argumentPredictions[argument].m_value; 190 } 191 if ((unsigned)operand < m_variablePredictions.size()) 192 return m_variablePredictions[operand].m_value; 193 return PredictNone; 149 return m_predictions.getPrediction(operand); 194 150 } 195 151 196 152 PredictedType getGlobalVarPrediction(unsigned varNumber) 197 153 { 198 HashMap<unsigned, PredictionSlot>::iterator iter = m_globalVarPredictions.find(varNumber + 1); 199 if (iter == m_globalVarPredictions.end()) 200 return PredictNone; 201 return iter->second.m_value; 154 return m_predictions.getGlobalVarPrediction(varNumber); 202 155 } 203 156 … … 212 165 nodePtr = &(*this)[nodePtr->child1()]; 213 166 214 switch (nodePtr->op) { 215 case GetLocal: 216 return getPrediction(nodePtr->local()); 217 case GetGlobalVar: 218 return getGlobalVarPrediction(nodePtr->varNumber()); 219 case GetById: 220 case GetMethod: 221 case GetByVal: 222 case Call: 223 case Construct: 224 return nodePtr->getPrediction(); 225 default: 226 return PredictNone; 227 } 167 return m_predictions.getPrediction(*nodePtr); 228 168 } 229 169 … … 245 185 return at(nodeIndex).isDoubleConstant(codeBlock); 246 186 } 187 bool isBooleanConstant(CodeBlock* codeBlock, NodeIndex nodeIndex) 188 { 189 return at(nodeIndex).isBooleanConstant(codeBlock); 190 } 247 191 // Helper methods get constant values from nodes. 248 192 JSValue valueOfJSConstant(CodeBlock* codeBlock, NodeIndex nodeIndex) … … 257 201 { 258 202 return at(nodeIndex).valueOfDoubleConstant(codeBlock); 203 } 204 bool valueOfBooleanConstant(CodeBlock* codeBlock, NodeIndex nodeIndex) 205 { 206 return at(nodeIndex).valueOfBooleanConstant(codeBlock); 259 207 } 260 208 … … 272 220 void refChildren(NodeIndex); 273 221 274 Vector<PredictionSlot, 16> m_argumentPredictions; 275 Vector<PredictionSlot, 16> m_variablePredictions; 276 HashMap<unsigned, PredictionSlot> m_globalVarPredictions; 222 PredictionTracker m_predictions; 277 223 }; 278 224 -
trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp
r93934 r94629 81 81 case DataFormatCell: 82 82 case DataFormatJSCell: 83 case DataFormatBoolean: 84 case DataFormatJSBoolean: 83 85 // Should only be calling this function if we know this operand to be integer. 84 86 ASSERT_NOT_REACHED(); … … 154 156 case DataFormatCell: 155 157 case DataFormatJSCell: 158 case DataFormatBoolean: 159 case DataFormatJSBoolean: 156 160 // Should only be calling this function if we know this operand to be numeric. 157 161 ASSERT_NOT_REACHED(); … … 296 300 case DataFormatJSInteger: 297 301 case DataFormatJSDouble: 298 case DataFormatJSCell: { 302 case DataFormatJSCell: 303 case DataFormatJSBoolean: { 299 304 GPRReg gpr = info.gpr(); 300 305 m_gprs.lock(gpr); 301 306 return gpr; 302 307 } 308 309 case DataFormatBoolean: 310 // this type currently never occurs 311 ASSERT_NOT_REACHED(); 303 312 } 304 313 … … 407 416 return (info.registerFormat() | DataFormatJS) == DataFormatJSDouble 408 417 || (info.registerFormat() | DataFormatJS) == DataFormatJSCell 418 || (info.registerFormat() | DataFormatJS) == DataFormatJSBoolean 409 419 || (node.isConstant() && !valueOfJSConstant(nodeIndex).isInt32()); 420 } 421 422 bool JITCodeGenerator::isKnownBoolean(NodeIndex nodeIndex) 423 { 424 Node& node = m_jit.graph()[nodeIndex]; 425 if (node.hasBooleanResult()) 426 return true; 427 428 if (isBooleanConstant(nodeIndex)) 429 return true; 430 431 VirtualRegister virtualRegister = node.virtualRegister(); 432 GenerationInfo& info = m_generationInfo[virtualRegister]; 433 434 return (info.registerFormat() | DataFormatJS) == DataFormatJSBoolean 435 || (info.spillFormat() | DataFormatJS) == DataFormatJSBoolean; 410 436 } 411 437 … … 589 615 590 616 m_jit.or32(TrustedImm32(ValueFalse), resultGPR); 591 jsValueResult(resultGPR, m_compileIndex );617 jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean); 592 618 } 593 619 … … 744 770 745 771 m_jit.or32(TrustedImm32(ValueFalse), resultGPR); 746 jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);772 jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean, UseChildrenCalledExplicitly); 747 773 } else { 748 774 GPRTemporary result(this, arg2); … … 778 804 m_jit.or32(TrustedImm32(ValueFalse), resultGPR); 779 805 780 jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);806 jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean, UseChildrenCalledExplicitly); 781 807 } 782 808 } … … 940 966 } 941 967 942 jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);968 jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean, UseChildrenCalledExplicitly); 943 969 } 944 970 … … 969 995 GPRReg valueGPR = value.gpr(); 970 996 971 GPRTemporary result(this);972 GPRReg resultGPR = result.gpr();973 974 value.use();975 976 997 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset()); 977 998 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(node.notTakenBytecodeOffset()); 978 979 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsNumber(0)))), notTaken); 980 addBranch(m_jit.branchPtr(MacroAssembler::AboveOrEqual, valueGPR, GPRInfo::tagTypeNumberRegister), taken); 981 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false)))), notTaken); 982 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true)))), taken); 983 984 silentSpillAllRegisters(resultGPR); 985 m_jit.move(valueGPR, GPRInfo::argumentGPR1); 986 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 987 appendCallWithExceptionCheck(dfgConvertJSValueToBoolean); 988 m_jit.move(GPRInfo::returnValueGPR, resultGPR); 989 silentFillAllRegisters(resultGPR); 990 991 addBranch(m_jit.branchTest8(MacroAssembler::NonZero, resultGPR), taken); 992 if (notTaken != (m_block + 1)) 993 addBranch(m_jit.jump(), notTaken); 994 995 noResult(m_compileIndex, UseChildrenCalledExplicitly); 999 1000 if (isKnownBoolean(node.child1())) { 1001 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero; 1002 1003 if (taken == (m_block + 1)) { 1004 condition = MacroAssembler::Zero; 1005 BlockIndex tmp = taken; 1006 taken = notTaken; 1007 notTaken = tmp; 1008 } 1009 1010 addBranch(m_jit.branchTest32(condition, valueGPR, TrustedImm32(true)), taken); 1011 if (notTaken != (m_block + 1)) 1012 addBranch(m_jit.jump(), notTaken); 1013 1014 noResult(m_compileIndex); 1015 } else { 1016 GPRTemporary result(this); 1017 GPRReg resultGPR = result.gpr(); 1018 1019 bool predictBoolean = isBooleanPrediction(m_jit.graph().getPrediction(m_jit.graph()[node.child1()])); 1020 1021 if (predictBoolean) { 1022 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false)))), notTaken); 1023 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true)))), taken); 1024 } 1025 1026 if (m_isSpeculative && predictBoolean) { 1027 speculationCheck(m_jit.jump()); 1028 value.use(); 1029 } else { 1030 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsNumber(0)))), notTaken); 1031 addBranch(m_jit.branchPtr(MacroAssembler::AboveOrEqual, valueGPR, GPRInfo::tagTypeNumberRegister), taken); 1032 1033 if (!predictBoolean) { 1034 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false)))), notTaken); 1035 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true)))), taken); 1036 } 1037 1038 value.use(); 1039 1040 silentSpillAllRegisters(resultGPR); 1041 m_jit.move(valueGPR, GPRInfo::argumentGPR1); 1042 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 1043 appendCallWithExceptionCheck(dfgConvertJSValueToBoolean); 1044 m_jit.move(GPRInfo::returnValueGPR, resultGPR); 1045 silentFillAllRegisters(resultGPR); 1046 1047 addBranch(m_jit.branchTest8(MacroAssembler::NonZero, resultGPR), taken); 1048 if (notTaken != (m_block + 1)) 1049 addBranch(m_jit.jump(), notTaken); 1050 } 1051 1052 noResult(m_compileIndex, UseChildrenCalledExplicitly); 1053 } 996 1054 } 997 1055 … … 1080 1138 1081 1139 m_jit.addJSCall(fastCall, slowCall, targetToCheck, isCall, m_jit.graph()[m_compileIndex].exceptionInfo); 1140 } 1141 1142 void JITCodeGenerator::speculationCheck(MacroAssembler::Jump jumpToFail) 1143 { 1144 ASSERT(m_isSpeculative); 1145 static_cast<SpeculativeJIT*>(this)->speculationCheck(jumpToFail); 1082 1146 } 1083 1147 … … 1288 1352 } 1289 1353 1354 GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateBooleanOperand& op1) 1355 : m_jit(jit) 1356 , m_gpr(InvalidGPRReg) 1357 { 1358 if (m_jit->canReuse(op1.index())) 1359 m_gpr = m_jit->reuse(op1.gpr()); 1360 else 1361 m_gpr = m_jit->allocate(); 1362 } 1363 1290 1364 GPRTemporary::GPRTemporary(JITCodeGenerator* jit, JSValueOperand& op1) 1291 1365 : m_jit(jit) -
trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h
r93934 r94629 42 42 class SpeculateDoubleOperand; 43 43 class SpeculateCellOperand; 44 class SpeculateBooleanOperand; 44 45 45 46 … … 411 412 bool isKnownNotInteger(NodeIndex); 412 413 414 bool isKnownBoolean(NodeIndex); 415 413 416 // Checks/accessors for constant values. 414 417 bool isConstant(NodeIndex nodeIndex) { return m_jit.isConstant(nodeIndex); } … … 416 419 bool isInt32Constant(NodeIndex nodeIndex) { return m_jit.isInt32Constant(nodeIndex); } 417 420 bool isDoubleConstant(NodeIndex nodeIndex) { return m_jit.isDoubleConstant(nodeIndex); } 421 bool isBooleanConstant(NodeIndex nodeIndex) { return m_jit.isBooleanConstant(nodeIndex); } 418 422 int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); } 419 423 double valueOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.valueOfDoubleConstant(nodeIndex); } 420 424 JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(nodeIndex); } 425 bool valueOfBooleanConstant(NodeIndex nodeIndex) { return m_jit.valueOfBooleanConstant(nodeIndex); } 421 426 bool isNullConstant(NodeIndex nodeIndex) 422 427 { … … 576 581 577 582 void emitCall(Node&); 583 584 void speculationCheck(MacroAssembler::Jump jumpToFail); 578 585 579 586 // Called once a node has completed code generation but prior to setting … … 1122 1129 GPRTemporary(JITCodeGenerator*, IntegerOperand&, IntegerOperand&); 1123 1130 GPRTemporary(JITCodeGenerator*, SpeculateCellOperand&); 1131 GPRTemporary(JITCodeGenerator*, SpeculateBooleanOperand&); 1124 1132 GPRTemporary(JITCodeGenerator*, JSValueOperand&); 1125 1133 -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r94559 r94629 489 489 breakpoint(); 490 490 #endif 491 492 #if DFG_VERBOSE_SPECULATION_FAILURE 493 SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo; 494 debugInfo->codeBlock = m_codeBlock; 495 debugInfo->debugOffset = debugOffset(); 496 497 debugCall(debugOperationPrintSpeculationFailure, debugInfo); 498 #endif 491 499 492 500 // Does this speculation check require any additional recovery to be performed, … … 494 502 // non-speculative path. 495 503 if (recovery) { 496 // The only additional recovery we currently support is for integer add operation 497 ASSERT(recovery->type() == SpeculativeAdd); 498 ASSERT(check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].nodeIndex != NoNode); 499 // Revert the add. 500 sub32(recovery->src(), recovery->dest()); 501 502 // If recovery->dest() should have been boxed prior to the addition, then rebox 503 // it. 504 DataFormat format = check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].format; 505 ASSERT(format == DataFormatInteger || format == DataFormatJSInteger || format == DataFormatJS); 506 if (format != DataFormatInteger) 507 orPtr(GPRInfo::tagTypeNumberRegister, recovery->dest()); 504 switch (recovery->type()) { 505 case SpeculativeAdd: { 506 ASSERT(check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].nodeIndex != NoNode); 507 // Revert the add. 508 sub32(recovery->src(), recovery->dest()); 509 510 // If recovery->dest() should have been boxed prior to the addition, then rebox 511 // it. 512 DataFormat format = check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].format; 513 ASSERT(format == DataFormatInteger || format == DataFormatJSInteger || format == DataFormatJS); 514 if (format != DataFormatInteger) 515 orPtr(GPRInfo::tagTypeNumberRegister, recovery->dest()); 516 break; 517 } 518 519 case BooleanSpeculationCheck: { 520 ASSERT(check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].nodeIndex != NoNode); 521 // Rebox the (non-)boolean 522 xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), recovery->dest()); 523 break; 524 } 525 526 default: 527 ASSERT_NOT_REACHED(); 528 break; 529 } 508 530 } 509 531 … … 876 898 // Link the code, populate data in CodeBlock data structures. 877 899 #if DFG_DEBUG_VERBOSE 878 fprintf(stderr, "JIT code start at [%p, %p)\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize());900 fprintf(stderr, "JIT code for %p start at [%p, %p)\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()); 879 901 #endif 880 902 -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h
r94559 r94629 55 55 struct SpeculationCheck; 56 56 57 #ifndef NDEBUG 58 typedef void (*V_DFGDebugOperation_EP)(ExecState*, void*); 59 #endif 60 61 #if DFG_VERBOSE_SPECULATION_FAILURE 62 struct SpeculationFailureDebugInfo { 63 CodeBlock* codeBlock; 64 unsigned debugOffset; 65 }; 66 #endif 67 57 68 // === CallRecord === 58 69 // … … 206 217 return functionCall; 207 218 } 219 220 #ifndef NDEBUG 221 // Add a debug call. This call has no effect on JIT code execution state. 222 void debugCall(V_DFGDebugOperation_EP function, void* argument) 223 { 224 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) 225 storePtr(GPRInfo::toRegister(i), m_globalData->debugDataBuffer + i); 226 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) { 227 move(TrustedImmPtr(m_globalData->debugDataBuffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0); 228 storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0); 229 } 230 move(TrustedImmPtr(argument), GPRInfo::argumentGPR1); 231 move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 232 move(TrustedImmPtr(reinterpret_cast<void*>(function)), GPRInfo::regT0); 233 call(GPRInfo::regT0); 234 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) { 235 move(TrustedImmPtr(m_globalData->debugDataBuffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0); 236 loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i)); 237 } 238 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) 239 loadPtr(m_globalData->debugDataBuffer + i, GPRInfo::toRegister(i)); 240 } 241 #endif 208 242 209 243 // Helper methods to check nodes for constants. … … 212 246 bool isInt32Constant(NodeIndex nodeIndex) { return graph().isInt32Constant(codeBlock(), nodeIndex); } 213 247 bool isDoubleConstant(NodeIndex nodeIndex) { return graph().isDoubleConstant(codeBlock(), nodeIndex); } 248 bool isBooleanConstant(NodeIndex nodeIndex) { return graph().isBooleanConstant(codeBlock(), nodeIndex); } 214 249 // Helper methods get constant values from nodes. 215 250 JSValue valueOfJSConstant(NodeIndex nodeIndex) { return graph().valueOfJSConstant(codeBlock(), nodeIndex); } 216 251 int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return graph().valueOfInt32Constant(codeBlock(), nodeIndex); } 217 252 double valueOfDoubleConstant(NodeIndex nodeIndex) { return graph().valueOfDoubleConstant(codeBlock(), nodeIndex); } 253 bool valueOfBooleanConstant(NodeIndex nodeIndex) { return graph().valueOfBooleanConstant(codeBlock(), nodeIndex); } 218 254 219 255 // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs. -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r94559 r94629 45 45 // Emit a breakpoint into the speculation failure code. 46 46 #define DFG_JIT_BREAK_ON_SPECULATION_FAILURE 0 47 // Log every speculation failure. 48 #define DFG_VERBOSE_SPECULATION_FAILURE 0 47 49 // Disable the DFG JIT without having to touch Platform.h! 48 50 #define DFG_DEBUG_LOCAL_DISBALE 0 … … 90 92 #define NodeResultDouble 0x2000 91 93 #define NodeResultInt32 0x3000 94 #define NodeResultBoolean 0x4000 92 95 93 96 // This macro defines a set of information about all known node types, used to populate NodeId, NodeType below. … … 141 144 \ 142 145 /* Nodes for comparison operations. */\ 143 macro(CompareLess, NodeResult JS| NodeMustGenerate) \144 macro(CompareLessEq, NodeResult JS| NodeMustGenerate) \145 macro(CompareGreater, NodeResult JS| NodeMustGenerate) \146 macro(CompareGreaterEq, NodeResult JS| NodeMustGenerate) \147 macro(CompareEq, NodeResult JS| NodeMustGenerate) \148 macro(CompareStrictEq, NodeResult JS) \146 macro(CompareLess, NodeResultBoolean | NodeMustGenerate) \ 147 macro(CompareLessEq, NodeResultBoolean | NodeMustGenerate) \ 148 macro(CompareGreater, NodeResultBoolean | NodeMustGenerate) \ 149 macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate) \ 150 macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \ 151 macro(CompareStrictEq, NodeResultBoolean) \ 149 152 \ 150 153 /* Calls. */\ … … 160 163 macro(Breakpoint, NodeMustGenerate) \ 161 164 macro(CheckHasInstance, NodeMustGenerate) \ 162 macro(InstanceOf, NodeResult JS) \163 macro(LogicalNot, NodeResult JS) \165 macro(InstanceOf, NodeResultBoolean) \ 166 macro(LogicalNot, NodeResultBoolean) \ 164 167 \ 165 168 /* Block terminals. */\ … … 199 202 static const PredictedType PredictDouble = 0x08; 200 203 static const PredictedType PredictNumber = 0x0c; 201 static const PredictedType PredictTop = 0x0f; 204 static const PredictedType PredictBoolean = 0x10; 205 static const PredictedType PredictTop = 0x1f; 202 206 static const PredictedType StrongPredictionTag = 0x80; 203 207 static const PredictedType PredictionTagMask = 0x80; … … 228 232 { 229 233 return !!(value & PredictNumber) && !(value & ~(PredictNumber | PredictionTagMask)); 234 } 235 236 inline bool isBooleanPrediction(PredictedType value) 237 { 238 return (value & ~PredictionTagMask) == PredictBoolean; 230 239 } 231 240 … … 249 258 case PredictInt32: 250 259 return "p-strong-int32"; 260 case PredictDouble: 261 return "p-strong-double"; 251 262 case PredictNumber: 252 263 return "p-strong-number"; 264 case PredictBoolean: 265 return "p-strong-boolean"; 253 266 default: 254 267 return "p-strong-top"; … … 264 277 case PredictInt32: 265 278 return "p-weak-int32"; 279 case PredictDouble: 280 return "p-weak-double"; 266 281 case PredictNumber: 267 282 return "p-weak-number"; 283 case PredictBoolean: 284 return "p-weak-boolean"; 268 285 default: 269 286 return "p-weak-top"; … … 326 343 if (statistics.cells == statistics.samples) 327 344 return StrongPredictionTag | PredictCell; 345 346 if (statistics.booleans == statistics.samples) 347 return StrongPredictionTag | PredictBoolean; 328 348 329 349 return StrongPredictionTag | PredictTop; … … 424 444 } 425 445 446 bool isBooleanConstant(CodeBlock* codeBlock) 447 { 448 return isConstant() && valueOfJSConstant(codeBlock).isBoolean(); 449 } 450 426 451 int32_t valueOfInt32Constant(CodeBlock* codeBlock) 427 452 { … … 434 459 ASSERT(isDoubleConstant(codeBlock)); 435 460 return valueOfJSConstant(codeBlock).uncheckedGetNumber(); 461 } 462 463 bool valueOfBooleanConstant(CodeBlock* codeBlock) 464 { 465 ASSERT(isBooleanConstant(codeBlock)); 466 return valueOfJSConstant(codeBlock).getBoolean(); 436 467 } 437 468 … … 493 524 return (op & NodeResultMask) == NodeResultJS; 494 525 } 526 527 bool hasBooleanResult() 528 { 529 return (op & NodeResultMask) == NodeResultBoolean; 530 } 495 531 496 532 // Check for integers or doubles. 497 533 bool hasNumericResult() 498 534 { 499 // This check will need updating if more result types are added. 500 ASSERT((hasInt32Result() || hasDoubleResult()) == !hasJSResult()); 501 return !hasJSResult(); 535 return hasInt32Result() || hasDoubleResult(); 502 536 } 503 537 … … 564 598 ASSERT(source == StrongPrediction); 565 599 566 PredictedType newPrediction = StrongPredictionTag | prediction ;600 PredictedType newPrediction = StrongPredictionTag | prediction | m_opInfo2; 567 601 bool result = m_opInfo2 != newPrediction; 568 m_opInfo2 |= newPrediction;602 m_opInfo2 = newPrediction; 569 603 return result; 570 604 } -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r93375 r94629 679 679 } 680 680 681 #if DFG_VERBOSE_SPECULATION_FAILURE 682 void debugOperationPrintSpeculationFailure(ExecState*, void* debugInfoRaw) 683 { 684 SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw); 685 printf("Speculation failure in %p at 0x%x!\n", debugInfo->codeBlock, debugInfo->debugOffset); 686 } 687 #endif 688 681 689 } // extern "C" 682 690 } } // namespace JSC::DFG -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r93070 r94629 116 116 RegisterSizedBoolean dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue); 117 117 118 #if DFG_VERBOSE_SPECULATION_FAILURE 119 void debugOperationPrintSpeculationFailure(ExecState*, void*); 120 #endif 121 118 122 } // extern "C" 119 123 } } // namespace JSC::DFG -
trunk/Source/JavaScriptCore/dfg/DFGPropagator.cpp
r94559 r94629 41 41 , m_profiledBlock(profiledBlock) 42 42 { 43 // Predictions is a forward flow property that propagates the values seen at 44 // a particular value source to their various uses, ensuring that uses perform 45 // speculation that does not contravene the expected values. 43 46 m_predictions.resize(m_graph.size()); 44 for (NodeIndex i = 0; i < m_graph.size(); ++i) 47 48 // Uses is a backward flow property that propagates the hard expectations at 49 // certain uses to their value sources, ensuring that predictions about 50 // values do not contravene the code itself. This comes up only in the 51 // cases of obvious cell uses, like GetById and friends as well as Call. 52 // We're essentially statically speculating that if the value profile indicates 53 // that only booleans (for example) flow into a GetById, then the value 54 // profile is simply wrong due to insufficient coverage and needs to be 55 // adjusted accordingly. The alternatives would be to assume either 56 // that the GetById never executes, or always executes on a boolean leading 57 // to whatever bizarre behavior that's supposed to cause. 58 m_uses.resize(m_graph.size()); 59 m_variableUses.initializeSimilarTo(m_graph.predictions()); 60 61 for (unsigned i = 0; i < m_graph.size(); ++i) { 45 62 m_predictions[i] = PredictNone; 63 m_uses[i] = PredictNone; 64 } 46 65 } 47 66 … … 52 71 #endif 53 72 do { 73 m_changed = false; 74 54 75 // Forward propagation is near-optimal for both topologically-sorted and 55 76 // DFS-sorted code. 56 m_changed = false;57 77 propagateForward(); 58 78 if (!m_changed) … … 65 85 m_changed = false; 66 86 propagateBackward(); 67 if (!m_changed)68 break;69 70 // Do another forward pass because forward passes are on average more71 // profitable.72 m_changed = false;73 propagateForward();74 87 } while (m_changed); 75 88 } 76 89 77 90 private: 78 void setPrediction(PredictedType prediction) 79 { 91 bool setPrediction(PredictedType prediction) 92 { 93 ASSERT(m_graph[m_compileIndex].hasResult()); 94 80 95 if (m_predictions[m_compileIndex] == prediction) 81 return ;96 return false; 82 97 83 98 m_predictions[m_compileIndex] = prediction; 84 m_changed = true; 85 } 86 87 void mergePrediction(PredictedType prediction) 88 { 89 if (DFG::mergePrediction(m_predictions[m_compileIndex], prediction)) 90 m_changed = true; 99 return true; 100 } 101 102 bool mergeUse(NodeIndex nodeIndex, PredictedType prediction) 103 { 104 ASSERT(m_graph[nodeIndex].hasResult()); 105 106 return DFG::mergePrediction(m_uses[nodeIndex], prediction); 107 } 108 109 bool mergePrediction(PredictedType prediction) 110 { 111 ASSERT(m_graph[m_compileIndex].hasResult()); 112 113 return DFG::mergePrediction(m_predictions[m_compileIndex], prediction); 91 114 } 92 115 … … 97 120 98 121 NodeType op = node.op; 122 123 #if DFG_DEBUG_VERBOSE 124 printf(" %s[%u]: ", Graph::opName(op), m_compileIndex); 125 #endif 126 127 bool changed = false; 128 99 129 switch (op) { 100 130 case JSConstant: { 101 131 JSValue value = node.valueOfJSConstant(m_codeBlock); 102 132 if (value.isInt32()) 103 setPrediction(makePrediction(PredictInt32, StrongPrediction));133 changed |= setPrediction(makePrediction(PredictInt32, StrongPrediction)); 104 134 else if (value.isDouble()) 105 setPrediction(makePrediction(PredictDouble, StrongPrediction));135 changed |= setPrediction(makePrediction(PredictDouble, StrongPrediction)); 106 136 else if (value.isCell()) { 107 137 JSCell* cell = value.asCell(); 108 138 if (isJSArray(&m_globalData, cell)) 109 setPrediction(makePrediction(PredictArray, StrongPrediction));139 changed |= setPrediction(makePrediction(PredictArray, StrongPrediction)); 110 140 else 111 setPrediction(makePrediction(PredictCell, StrongPrediction)); 112 } else 113 setPrediction(makePrediction(PredictTop, StrongPrediction)); 141 changed |= setPrediction(makePrediction(PredictCell, StrongPrediction)); 142 } else if (value.isBoolean()) 143 changed |= setPrediction(makePrediction(PredictBoolean, StrongPrediction)); 144 else 145 changed |= setPrediction(makePrediction(PredictTop, StrongPrediction)); 114 146 break; 115 147 } 116 148 117 149 case GetLocal: { 150 changed |= m_graph.predict(node.local(), m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction); 151 changed |= m_variableUses.predict(node.local(), m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction); 152 118 153 PredictedType prediction = m_graph.getPrediction(node.local()); 119 154 if (isStrongPrediction(prediction)) 120 mergePrediction(prediction);155 changed |= mergePrediction(prediction); 121 156 break; 122 157 } 123 158 124 159 case SetLocal: { 125 m_changed |= m_graph.predict(node.local(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction); 160 changed |= m_graph.predict(node.local(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction); 161 changed |= mergeUse(node.child1(), m_variableUses.getPrediction(node.local())); 126 162 break; 127 163 } … … 136 172 case ValueToInt32: 137 173 case ArithMod: { 138 setPrediction(makePrediction(PredictInt32, StrongPrediction));174 changed |= setPrediction(makePrediction(PredictInt32, StrongPrediction)); 139 175 break; 140 176 } … … 145 181 if (isStrongPrediction(prediction)) { 146 182 if (isNumberPrediction(prediction)) 147 mergePrediction(prediction);183 changed |= mergePrediction(prediction); 148 184 else 149 mergePrediction(makePrediction(PredictNumber, StrongPrediction));185 changed |= mergePrediction(makePrediction(PredictNumber, StrongPrediction)); 150 186 } 187 151 188 break; 152 189 } … … 159 196 if (isNumberPrediction(left) && isNumberPrediction(right)) { 160 197 if (isInt32Prediction(mergePredictions(left, right))) 161 mergePrediction(makePrediction(PredictInt32, StrongPrediction));198 changed |= mergePrediction(makePrediction(PredictInt32, StrongPrediction)); 162 199 else 163 mergePrediction(makePrediction(PredictDouble, StrongPrediction));200 changed |= mergePrediction(makePrediction(PredictDouble, StrongPrediction)); 164 201 } else 165 mergePrediction(makePrediction(PredictTop, StrongPrediction));202 changed |= mergePrediction(makePrediction(PredictTop, StrongPrediction)); 166 203 } 167 204 break; … … 176 213 if (isStrongPrediction(left) && isStrongPrediction(right)) { 177 214 if (isInt32Prediction(mergePredictions(left, right))) 178 mergePrediction(makePrediction(PredictInt32, StrongPrediction));215 changed |= mergePrediction(makePrediction(PredictInt32, StrongPrediction)); 179 216 else 180 mergePrediction(makePrediction(PredictDouble, StrongPrediction));217 changed |= mergePrediction(makePrediction(PredictDouble, StrongPrediction)); 181 218 } 182 219 break; … … 184 221 185 222 case ArithDiv: { 186 setPrediction(makePrediction(PredictDouble, StrongPrediction));223 changed |= setPrediction(makePrediction(PredictDouble, StrongPrediction)); 187 224 break; 188 225 } … … 196 233 case CompareStrictEq: 197 234 case InstanceOf: { 198 // This is sad, as we don't have a boolean prediction, even though we easily 199 // could. 200 setPrediction(makePrediction(PredictTop, StrongPrediction)); 235 changed |= setPrediction(makePrediction(PredictBoolean, StrongPrediction)); 201 236 break; 202 237 } … … 204 239 case GetById: 205 240 case GetMethod: 206 case GetByVal: 241 case GetByVal: { 242 changed |= mergeUse(node.child1(), PredictCell | StrongPredictionTag); 243 changed |= node.predict(m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction); 244 if (isStrongPrediction(node.getPrediction())) 245 changed |= setPrediction(node.getPrediction()); 246 break; 247 } 248 207 249 case Call: 208 250 case Construct: { 251 changed |= mergeUse(m_graph.m_varArgChildren[node.firstChild()], PredictCell | StrongPredictionTag); 252 changed |= node.predict(m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction); 209 253 if (isStrongPrediction(node.getPrediction())) 210 setPrediction(node.getPrediction());254 changed |= setPrediction(node.getPrediction()); 211 255 break; 212 256 } 213 257 214 258 case ConvertThis: { 215 setPrediction(makePrediction(PredictCell, StrongPrediction));259 changed |= setPrediction(makePrediction(PredictCell, StrongPrediction)); 216 260 break; 217 261 } 218 262 219 263 case GetGlobalVar: { 264 changed |= m_variableUses.predictGlobalVar(node.varNumber(), m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction); 220 265 PredictedType prediction = m_graph.getGlobalVarPrediction(node.varNumber()); 221 266 if (isStrongPrediction(prediction)) 222 mergePrediction(prediction);267 changed |= mergePrediction(prediction); 223 268 break; 224 269 } 225 270 226 271 case PutGlobalVar: { 227 m_changed |= m_graph.predictGlobalVar(node.varNumber(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction); 228 break; 229 } 230 272 changed |= m_graph.predictGlobalVar(node.varNumber(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction); 273 changed |= mergeUse(node.child1(), m_variableUses.getGlobalVarPrediction(node.varNumber())); 274 break; 275 } 276 277 case PutByVal: 278 case PutByValAlias: 279 case PutById: 280 case PutByIdDirect: 281 changed |= mergeUse(node.child1(), PredictCell | StrongPredictionTag); 282 break; 283 231 284 #ifndef NDEBUG 232 285 // These get ignored because they don't return anything. 233 case PutByVal:234 case PutByValAlias:235 286 case DFG::Jump: 236 287 case Branch: 237 288 case Return: 238 case PutById:239 case PutByIdDirect:240 289 case CheckHasInstance: 241 290 case Phi: … … 256 305 #endif 257 306 } 307 308 #if DFG_DEBUG_VERBOSE 309 printf("expect(%s) use(%s) %s\n", predictionToString(m_predictions[m_compileIndex]), predictionToString(m_uses[m_compileIndex]), changed ? "CHANGED" : ""); 310 #endif 311 312 m_changed |= changed; 258 313 } 259 314 … … 284 339 285 340 Vector<PredictedType, 16> m_predictions; 341 Vector<PredictedType, 16> m_uses; 342 343 PredictionTracker m_variableUses; 286 344 287 345 #if DFG_DEBUG_VERBOSE -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r93934 r94629 129 129 case DataFormatDouble: 130 130 case DataFormatCell: 131 case DataFormatBoolean: 131 132 case DataFormatJSDouble: 132 case DataFormatJSCell: { 133 case DataFormatJSCell: 134 case DataFormatJSBoolean: { 133 135 terminateSpeculativeExecution(); 134 136 returnFormat = DataFormatInteger; … … 224 226 225 227 switch (info.registerFormat()) { 226 case DataFormatNone: 227 // Should have filled, above.228 case DataFormatNone: // Should have filled, above. 229 case DataFormatBoolean: // This type never occurs. 228 230 ASSERT_NOT_REACHED(); 229 231 230 232 case DataFormatCell: 231 233 case DataFormatJSCell: 232 case DataFormatJS: { 234 case DataFormatJS: 235 case DataFormatJSBoolean: { 233 236 GPRReg jsValueGpr = info.gpr(); 234 237 m_gprs.lock(jsValueGpr); … … 350 353 case DataFormatInteger: 351 354 case DataFormatJSDouble: 352 case DataFormatDouble: { 355 case DataFormatDouble: 356 case DataFormatJSBoolean: 357 case DataFormatBoolean: { 358 terminateSpeculativeExecution(); 359 return allocate(); 360 } 361 } 362 363 ASSERT_NOT_REACHED(); 364 return InvalidGPRReg; 365 } 366 367 GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) 368 { 369 Node& node = m_jit.graph()[nodeIndex]; 370 VirtualRegister virtualRegister = node.virtualRegister(); 371 GenerationInfo& info = m_generationInfo[virtualRegister]; 372 373 switch (info.registerFormat()) { 374 case DataFormatNone: { 375 GPRReg gpr = allocate(); 376 377 if (node.isConstant()) { 378 JSValue jsValue = valueOfJSConstant(nodeIndex); 379 if (jsValue.isBoolean()) { 380 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); 381 m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr); 382 info.fillJSValue(gpr, DataFormatJSBoolean); 383 return gpr; 384 } 385 terminateSpeculativeExecution(); 386 return gpr; 387 } 388 ASSERT(info.spillFormat() & DataFormatJS); 389 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); 390 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); 391 392 info.fillJSValue(gpr, DataFormatJS); 393 if (info.spillFormat() != DataFormatJSBoolean) { 394 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); 395 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); 396 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); 397 } 398 info.fillJSValue(gpr, DataFormatJSBoolean); 399 return gpr; 400 } 401 402 case DataFormatBoolean: 403 case DataFormatJSBoolean: { 404 GPRReg gpr = info.gpr(); 405 m_gprs.lock(gpr); 406 return gpr; 407 } 408 409 case DataFormatJS: { 410 GPRReg gpr = info.gpr(); 411 m_gprs.lock(gpr); 412 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); 413 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); 414 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); 415 info.fillJSValue(gpr, DataFormatJSBoolean); 416 return gpr; 417 } 418 419 case DataFormatJSInteger: 420 case DataFormatInteger: 421 case DataFormatJSDouble: 422 case DataFormatDouble: 423 case DataFormatJSCell: 424 case DataFormatCell: { 353 425 terminateSpeculativeExecution(); 354 426 return allocate(); … … 529 601 // If we add a DataFormatBool, we should use it here. 530 602 m_jit.or32(TrustedImm32(ValueFalse), result.gpr()); 531 jsValueResult(result.gpr(), m_compileIndex );603 jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean); 532 604 } 533 605 … … 562 634 VirtualRegister virtualRegister = node.virtualRegister(); 563 635 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS); 564 m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), isArrayPrediction(prediction) ? DataFormatJSCell : DataFormatJS); 636 637 DataFormat format; 638 if (isArrayPrediction(prediction)) 639 format = DataFormatJSCell; 640 else if (isBooleanPrediction(prediction)) 641 format = DataFormatJSBoolean; 642 else 643 format = DataFormatJS; 644 645 m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), format); 565 646 } 566 647 break; … … 579 660 m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local())); 580 661 noResult(m_compileIndex); 662 } else if (isBooleanPrediction(predictedType)) { 663 SpeculateBooleanOperand boolean(this, node.child1()); 664 m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local())); 665 noResult(m_compileIndex); 581 666 } else { 582 667 JSValueOperand value(this, node.child1()); … … 842 927 843 928 case LogicalNot: { 929 if (isKnownBoolean(node.child1())) { 930 SpeculateBooleanOperand value(this, node.child1()); 931 GPRTemporary result(this, value); 932 933 m_jit.move(value.gpr(), result.gpr()); 934 m_jit.xorPtr(TrustedImm32(true), result.gpr()); 935 936 jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean); 937 break; 938 } 939 844 940 JSValueOperand value(this, node.child1()); 845 941 GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add). … … 851 947 852 948 // If we add a DataFormatBool, we should use it here. 853 jsValueResult(result.gpr(), m_compileIndex );949 jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean); 854 950 break; 855 951 } … … 1228 1324 1229 1325 putResult.link(&m_jit); 1230 jsValueResult(scratchReg, m_compileIndex );1326 jsValueResult(scratchReg, m_compileIndex, DataFormatJSBoolean); 1231 1327 break; 1232 1328 } -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r92593 r94629 38 38 // may need be performed should a speculation check fail. 39 39 enum SpeculationRecoveryType { 40 SpeculativeAdd 40 SpeculativeAdd, 41 BooleanSpeculationCheck 41 42 }; 42 43 … … 133 134 FPRReg fillSpeculateDouble(NodeIndex); 134 135 GPRReg fillSpeculateCell(NodeIndex); 135 136 private: 136 GPRReg fillSpeculateBoolean(NodeIndex); 137 138 private: 139 friend class JITCodeGenerator; 140 137 141 void compile(Node&); 138 142 void compile(BasicBlock&); … … 409 413 }; 410 414 415 class SpeculateBooleanOperand { 416 public: 417 explicit SpeculateBooleanOperand(SpeculativeJIT* jit, NodeIndex index) 418 : m_jit(jit) 419 , m_index(index) 420 , m_gprOrInvalid(InvalidGPRReg) 421 { 422 ASSERT(m_jit); 423 if (jit->isFilled(index)) 424 gpr(); 425 } 426 427 ~SpeculateBooleanOperand() 428 { 429 ASSERT(m_gprOrInvalid != InvalidGPRReg); 430 m_jit->unlock(m_gprOrInvalid); 431 } 432 433 NodeIndex index() const 434 { 435 return m_index; 436 } 437 438 GPRReg gpr() 439 { 440 if (m_gprOrInvalid == InvalidGPRReg) 441 m_gprOrInvalid = m_jit->fillSpeculateBoolean(index()); 442 return m_gprOrInvalid; 443 } 444 445 void use() 446 { 447 m_jit->use(m_index); 448 } 449 450 private: 451 SpeculativeJIT* m_jit; 452 NodeIndex m_index; 453 GPRReg m_gprOrInvalid; 454 }; 455 411 456 412 457 // === SpeculationCheckIndexIterator === -
trunk/Source/JavaScriptCore/runtime/JSGlobalData.h
r93755 r94629 233 233 ReturnAddressPtr exceptionLocation; 234 234 JSValue hostCallReturnValue; 235 #ifndef NDEBUG 236 int64_t debugDataBuffer[64]; 237 #endif 235 238 #endif 236 239 -
trunk/Source/JavaScriptCore/runtime/JSValue.cpp
r91555 r94629 127 127 else if (isInt32()) 128 128 snprintf(description, size, "Int32: %d", asInt32()); 129 else if (isDouble()) 130 snprintf(description, size, "Double: %lf", asDouble()); 131 else if (isCell()) 129 else if (isDouble()) { 130 #if USE(JSVALUE64) 131 snprintf(description, size, "Double: %lf, %lx", asDouble(), reinterpretDoubleToIntptr(asDouble())); 132 #else 133 union { 134 double asDouble; 135 uint32_t asTwoInt32s[2]; 136 } u; 137 u.asDouble = asDouble(); 138 snprintf(description, size, "Double: %lf, %08x:%08x", asDouble(), u.asTwoInt32s[1], u.asTwoInt32s[0]); 139 #endif 140 } else if (isCell()) 132 141 snprintf(description, size, "Cell: %p", asCell()); 133 142 else if (isTrue())
Note:
See TracChangeset
for help on using the changeset viewer.