Changeset 95523 in webkit
- Timestamp:
- Sep 20, 2011 2:41:16 AM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r95516 r95523 1 2011-09-18 Filip Pizlo <fpizlo@apple.com> 2 3 DFG JIT does not speculate aggressively enough on GetById 4 https://bugs.webkit.org/show_bug.cgi?id=68320 5 6 Reviewed by Oliver Hunt. 7 8 This adds the ability to access properties directly, by offset. 9 This optimization kicks in when at the time of DFG compilation, 10 it appears that the given get_by_id is self-cached by the old JIT. 11 Two new opcodes get introduced: CheckStructure and GetByOffset. 12 CheckStructure performs a speculation check on the object's 13 structure, and returns the storage pointer. GetByOffset performs 14 a direct read of the field from the storage pointer. Both 15 CheckStructure and GetByOffset can be CSE'd, so that we can 16 eliminate redundant structure checks, and redundant reads of the 17 same field. 18 19 This is a 4% speed-up on V8, a 2% slow-down on Kraken, and 20 neutral on SunSpider. 21 22 * bytecode/PredictedType.cpp: 23 (JSC::predictionFromClassInfo): 24 (JSC::predictionFromStructure): 25 (JSC::predictionFromCell): 26 * bytecode/PredictedType.h: 27 * dfg/DFGByteCodeParser.cpp: 28 (JSC::DFG::ByteCodeParser::parseBlock): 29 * dfg/DFGGenerationInfo.h: 30 (JSC::DFG::dataFormatToString): 31 (JSC::DFG::needDataFormatConversion): 32 (JSC::DFG::GenerationInfo::initStorage): 33 (JSC::DFG::GenerationInfo::spill): 34 (JSC::DFG::GenerationInfo::fillStorage): 35 * dfg/DFGGraph.h: 36 (JSC::DFG::Graph::predict): 37 (JSC::DFG::Graph::getPrediction): 38 * dfg/DFGJITCodeGenerator.cpp: 39 (JSC::DFG::JITCodeGenerator::fillInteger): 40 (JSC::DFG::JITCodeGenerator::fillDouble): 41 (JSC::DFG::JITCodeGenerator::fillJSValue): 42 (JSC::DFG::JITCodeGenerator::fillStorage): 43 (JSC::DFG::GPRTemporary::GPRTemporary): 44 * dfg/DFGJITCodeGenerator.h: 45 (JSC::DFG::JITCodeGenerator::silentSpillGPR): 46 (JSC::DFG::JITCodeGenerator::silentFillGPR): 47 (JSC::DFG::JITCodeGenerator::spill): 48 (JSC::DFG::JITCodeGenerator::storageResult): 49 (JSC::DFG::StorageOperand::StorageOperand): 50 (JSC::DFG::StorageOperand::~StorageOperand): 51 (JSC::DFG::StorageOperand::index): 52 (JSC::DFG::StorageOperand::gpr): 53 (JSC::DFG::StorageOperand::use): 54 * dfg/DFGNode.h: 55 (JSC::DFG::OpInfo::OpInfo): 56 (JSC::DFG::Node::Node): 57 (JSC::DFG::Node::hasPrediction): 58 (JSC::DFG::Node::hasStructure): 59 (JSC::DFG::Node::structure): 60 (JSC::DFG::Node::hasStorageAccessData): 61 (JSC::DFG::Node::storageAccessDataIndex): 62 * dfg/DFGPropagator.cpp: 63 (JSC::DFG::Propagator::propagateNode): 64 (JSC::DFG::Propagator::globalVarLoadElimination): 65 (JSC::DFG::Propagator::getMethodLoadElimination): 66 (JSC::DFG::Propagator::checkStructureLoadElimination): 67 (JSC::DFG::Propagator::getByOffsetLoadElimination): 68 (JSC::DFG::Propagator::performNodeCSE): 69 * dfg/DFGSpeculativeJIT.cpp: 70 (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): 71 (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): 72 (JSC::DFG::SpeculativeJIT::fillSpeculateCell): 73 (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): 74 (JSC::DFG::SpeculativeJIT::compile): 75 * wtf/StdLibExtras.h: 76 (WTF::safeCast): 77 1 78 2011-09-19 Mark Hahnenberg <mhahnenberg@apple.com> 2 79 -
trunk/Source/JavaScriptCore/bytecode/PredictedType.cpp
r95273 r95523 83 83 #endif 84 84 85 PredictedType predictionFromC ell(JSCell* cell)85 PredictedType predictionFromClassInfo(const ClassInfo* classInfo) 86 86 { 87 const ClassInfo* classInfo = cell->structure()->classInfo();88 89 87 if (classInfo == &JSFinalObject::s_info) 90 88 return PredictFinalObject; … … 100 98 101 99 return PredictCellOther; 100 } 101 102 PredictedType predictionFromStructure(Structure* structure) 103 { 104 return predictionFromClassInfo(structure->classInfo()); 105 } 106 107 PredictedType predictionFromCell(JSCell* cell) 108 { 109 return predictionFromStructure(cell->structure()); 102 110 } 103 111 -
trunk/Source/JavaScriptCore/bytecode/PredictedType.h
r95273 r95523 33 33 34 34 namespace JSC { 35 36 class Structure; 35 37 36 38 typedef uint16_t PredictedType; … … 151 153 } 152 154 155 PredictedType predictionFromClassInfo(const ClassInfo*); 156 PredictedType predictionFromStructure(Structure*); 153 157 PredictedType predictionFromCell(JSCell*); 154 158 PredictedType predictionFromValue(JSValue); -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r95484 r95523 1137 1137 case op_get_by_id: { 1138 1138 NodeIndex base = get(currentInstruction[2].u.operand); 1139 unsigned identifier = currentInstruction[3].u.operand; 1140 1141 NodeIndex getById = addToGraph(GetById, OpInfo(identifier), OpInfo(PredictNone), base); 1139 unsigned identifierNumber = currentInstruction[3].u.operand; 1140 1141 StructureStubInfo& stubInfo = m_profiledBlock->getStubInfo(m_currentIndex); 1142 1143 NodeIndex getById = NoNode; 1144 if (stubInfo.seen && stubInfo.accessType == access_get_by_id_self) { 1145 Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); 1146 Identifier identifier = m_codeBlock->identifier(identifierNumber); 1147 size_t offset = structure->get(*m_globalData, identifier); 1148 1149 if (offset != notFound) { 1150 getById = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(PredictNone), addToGraph(CheckStructure, OpInfo(structure), base)); 1151 1152 StorageAccessData storageAccessData; 1153 storageAccessData.offset = offset; 1154 storageAccessData.identifierNumber = identifierNumber; 1155 m_graph.m_storageAccessData.append(storageAccessData); 1156 } 1157 } 1158 1159 if (getById == NoNode) 1160 getById = addToGraph(GetById, OpInfo(identifierNumber), OpInfo(PredictNone), base); 1161 1142 1162 set(currentInstruction[1].u.operand, getById); 1143 1163 stronglyPredict(getById); -
trunk/Source/JavaScriptCore/dfg/DFGGenerationInfo.h
r95240 r95523 45 45 DataFormatBoolean = 3, 46 46 DataFormatCell = 4, 47 DataFormatStorage = 5, 47 48 DataFormatJS = 8, 48 49 DataFormatJSInteger = DataFormatJS | DataFormatInteger, … … 66 67 case DataFormatBoolean: 67 68 return "Boolean"; 69 case DataFormatStorage: 70 return "Storage"; 68 71 case DataFormatJS: 69 72 return "JS"; … … 111 114 ASSERT_NOT_REACHED(); 112 115 } 116 case DataFormatStorage: 117 ASSERT(to == DataFormatStorage); 118 return false; 113 119 default: 114 120 // This captures DataFormatBoolean, which is currently unused. … … 210 216 u.fpr = fpr; 211 217 } 218 void initStorage(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr) 219 { 220 m_nodeIndex = nodeIndex; 221 m_useCount = useCount; 222 m_registerFormat = DataFormatStorage; 223 m_spillFormat = DataFormatNone; 224 m_canFill = false; 225 u.gpr = gpr; 226 } 212 227 213 228 // Get the index of the node that produced this value. … … 289 304 // We should only be spilling values that are currently in machine registers. 290 305 ASSERT(m_registerFormat != DataFormatNone); 291 // We only spill values that have been boxed as a JSValue; otherwise the GC 292 // would need a way to distinguish cell pointers from numeric primitives. 293 ASSERT(spillFormat & DataFormatJS); 306 // We only spill values that have been boxed as a JSValue because historically 307 // we assumed that the GC would want to be able to precisely identify heap 308 // pointers. This is not true anymore, but we still assume, in the fill code, 309 // that any spill slot for a JS value is boxed. For storage pointers, there is 310 // nothing we can do to box them, so we allow that to be an exception. 311 ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatStorage); 294 312 295 313 m_registerFormat = DataFormatNone; … … 330 348 m_registerFormat = DataFormatDouble; 331 349 u.fpr = fpr; 350 } 351 void fillStorage(GPRReg gpr) 352 { 353 m_registerFormat = DataFormatStorage; 354 u.gpr = gpr; 332 355 } 333 356 -
trunk/Source/JavaScriptCore/dfg/DFGGraph.h
r95389 r95523 85 85 }; 86 86 87 struct StorageAccessData { 88 size_t offset; 89 unsigned identifierNumber; 90 91 // NOTE: the offset and identifierNumber do not by themselves 92 // uniquely identify a property. The identifierNumber and a 93 // Structure* do. If those two match, then the offset should 94 // be the same, as well. For any Node that has a StorageAccessData, 95 // it is possible to retrieve the Structure* by looking at the 96 // first child. It should be a CheckStructure, which has the 97 // Structure*. 98 }; 99 87 100 typedef Vector <BlockIndex, 2> PredecessorList; 88 101 … … 183 196 case Call: 184 197 case Construct: 198 case GetByOffset: 185 199 return node.predict(prediction, source); 186 200 default: … … 224 238 case Call: 225 239 case Construct: 240 case GetByOffset: 226 241 return nodePtr->getPrediction(); 227 242 case CheckMethod: … … 300 315 Vector<NodeIndex, 16> m_varArgChildren; 301 316 Vector<MethodCheckData> m_methodCheckData; 317 Vector<StorageAccessData> m_storageAccessData; 302 318 unsigned m_preservedVars; 303 319 unsigned m_parameterSlots; -
trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp
r95484 r95523 92 92 case DataFormatBoolean: 93 93 case DataFormatJSBoolean: 94 case DataFormatStorage: 94 95 // Should only be calling this function if we know this operand to be integer. 95 96 ASSERT_NOT_REACHED(); … … 167 168 case DataFormatBoolean: 168 169 case DataFormatJSBoolean: 170 case DataFormatStorage: 169 171 // Should only be calling this function if we know this operand to be numeric. 170 172 ASSERT_NOT_REACHED(); … … 317 319 318 320 case DataFormatBoolean: 321 case DataFormatStorage: 319 322 // this type currently never occurs 320 323 ASSERT_NOT_REACHED(); … … 322 325 323 326 ASSERT_NOT_REACHED(); 327 return InvalidGPRReg; 328 } 329 330 GPRReg JITCodeGenerator::fillStorage(NodeIndex nodeIndex) 331 { 332 Node& node = m_jit.graph()[nodeIndex]; 333 VirtualRegister virtualRegister = node.virtualRegister(); 334 GenerationInfo& info = m_generationInfo[virtualRegister]; 335 336 switch (info.registerFormat()) { 337 case DataFormatNone: { 338 GPRReg gpr = allocate(); 339 ASSERT(info.spillFormat() == DataFormatStorage); 340 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); 341 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); 342 info.fillStorage(gpr); 343 return gpr; 344 } 345 346 case DataFormatStorage: { 347 GPRReg gpr = info.gpr(); 348 m_gprs.lock(gpr); 349 return gpr; 350 } 351 352 default: 353 ASSERT_NOT_REACHED(); 354 } 355 324 356 return InvalidGPRReg; 325 357 } … … 1083 1115 wasNotDefaultHasInstance.link(&m_jit); 1084 1116 jsValueResult(scratchReg, m_compileIndex, UseChildrenCalledExplicitly); 1085 }1086 1087 template<typename To, typename From>1088 inline To safeCast(From value)1089 {1090 To result = static_cast<To>(value);1091 ASSERT(result == value);1092 return result;1093 1117 } 1094 1118 … … 2058 2082 } 2059 2083 2084 GPRTemporary::GPRTemporary(JITCodeGenerator* jit, StorageOperand& op1) 2085 : m_jit(jit) 2086 , m_gpr(InvalidGPRReg) 2087 { 2088 if (m_jit->canReuse(op1.index())) 2089 m_gpr = m_jit->reuse(op1.gpr()); 2090 else 2091 m_gpr = m_jit->allocate(); 2092 } 2093 2060 2094 FPRTemporary::FPRTemporary(JITCodeGenerator* jit) 2061 2095 : m_jit(jit) -
trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h
r95484 r95523 61 61 enum SpillOrder { 62 62 SpillOrderConstant = 1, // no spill, and cheap fill 63 SpillOrderSpilled = 2, // no spill 64 SpillOrderJS = 4, // needs spill 65 SpillOrderCell = 4, // needs spill 66 SpillOrderInteger = 5, // needs spill and box 67 SpillOrderDouble = 6, // needs spill and convert 63 SpillOrderSpilled = 2, // no spill 64 SpillOrderJS = 4, // needs spill 65 SpillOrderCell = 4, // needs spill 66 SpillOrderStorage = 4, // needs spill 67 SpillOrderInteger = 5, // needs spill and box 68 SpillOrderDouble = 6, // needs spill and convert 68 69 }; 69 70 … … 76 77 FPRReg fillDouble(NodeIndex); 77 78 GPRReg fillJSValue(NodeIndex); 79 GPRReg fillStorage(NodeIndex); 78 80 79 81 // lock and unlock GPR & FPR registers. … … 224 226 DataFormat registerFormat = info.registerFormat(); 225 227 226 if (registerFormat == DataFormatInteger) {228 if (registerFormat == DataFormatInteger) 227 229 m_jit.store32(info.gpr(), JITCompiler::addressFor(spillMe)); 228 }else {229 ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell );230 else { 231 ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell || registerFormat == DataFormatStorage); 230 232 m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe)); 231 233 } … … 275 277 m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex), info.gpr()); 276 278 else { 277 ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell );279 ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell || registerFormat == DataFormatStorage); 278 280 m_jit.loadPtr(JITCompiler::addressFor(spillMe), info.gpr()); 279 281 } … … 387 389 388 390 DataFormat spillFormat = info.registerFormat(); 389 if (spillFormat == DataFormatDouble) { 391 switch (spillFormat) { 392 case DataFormatDouble: { 390 393 // All values are spilled as JSValues, so box the double via a temporary gpr. 391 394 GPRReg gpr = boxDouble(info.fpr()); … … 395 398 return; 396 399 } 397 398 // The following code handles JSValues, int32s, and cells. 399 ASSERT(spillFormat == DataFormatInteger || spillFormat == DataFormatCell || spillFormat & DataFormatJS); 400 401 GPRReg reg = info.gpr(); 402 // We need to box int32 and cell values ... 403 // but on JSVALUE64 boxing a cell is a no-op! 404 if (spillFormat == DataFormatInteger) 405 m_jit.orPtr(GPRInfo::tagTypeNumberRegister, reg); 406 407 // Spill the value, and record it as spilled in its boxed form. 408 m_jit.storePtr(reg, JITCompiler::addressFor(spillMe)); 409 info.spill((DataFormat)(spillFormat | DataFormatJS)); 400 401 case DataFormatStorage: { 402 // This is special, since it's not a JS value - as in it's not visible to JS 403 // code. 404 m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe)); 405 info.spill(DataFormatStorage); 406 return; 407 } 408 409 default: 410 // The following code handles JSValues, int32s, and cells. 411 ASSERT(spillFormat == DataFormatInteger || spillFormat == DataFormatCell || spillFormat & DataFormatJS); 412 413 GPRReg reg = info.gpr(); 414 // We need to box int32 and cell values ... 415 // but on JSVALUE64 boxing a cell is a no-op! 416 if (spillFormat == DataFormatInteger) 417 m_jit.orPtr(GPRInfo::tagTypeNumberRegister, reg); 418 419 // Spill the value, and record it as spilled in its boxed form. 420 m_jit.storePtr(reg, JITCompiler::addressFor(spillMe)); 421 info.spill((DataFormat)(spillFormat | DataFormatJS)); 422 return; 423 } 410 424 } 411 425 … … 700 714 { 701 715 jsValueResult(reg, nodeIndex, DataFormatJS, mode); 716 } 717 void storageResult(GPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren) 718 { 719 Node& node = m_jit.graph()[nodeIndex]; 720 if (mode == CallUseChildren) 721 useChildren(node); 722 723 VirtualRegister virtualRegister = node.virtualRegister(); 724 m_gprs.retain(reg, virtualRegister, SpillOrderStorage); 725 GenerationInfo& info = m_generationInfo[virtualRegister]; 726 info.initStorage(nodeIndex, node.refCount(), reg); 702 727 } 703 728 void doubleResult(FPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren) … … 1161 1186 }; 1162 1187 1188 class StorageOperand { 1189 public: 1190 explicit StorageOperand(JITCodeGenerator* jit, NodeIndex index) 1191 : m_jit(jit) 1192 , m_index(index) 1193 , m_gprOrInvalid(InvalidGPRReg) 1194 { 1195 ASSERT(m_jit); 1196 if (jit->isFilled(index)) 1197 gpr(); 1198 } 1199 1200 ~StorageOperand() 1201 { 1202 ASSERT(m_gprOrInvalid != InvalidGPRReg); 1203 m_jit->unlock(m_gprOrInvalid); 1204 } 1205 1206 NodeIndex index() const 1207 { 1208 return m_index; 1209 } 1210 1211 GPRReg gpr() 1212 { 1213 if (m_gprOrInvalid == InvalidGPRReg) 1214 m_gprOrInvalid = m_jit->fillStorage(index()); 1215 return m_gprOrInvalid; 1216 } 1217 1218 void use() 1219 { 1220 m_jit->use(m_index); 1221 } 1222 1223 private: 1224 JITCodeGenerator* m_jit; 1225 NodeIndex m_index; 1226 GPRReg m_gprOrInvalid; 1227 }; 1228 1163 1229 1164 1230 // === Temporaries === … … 1181 1247 GPRTemporary(JITCodeGenerator*, SpeculateBooleanOperand&); 1182 1248 GPRTemporary(JITCodeGenerator*, JSValueOperand&); 1249 GPRTemporary(JITCodeGenerator*, StorageOperand&); 1183 1250 1184 1251 ~GPRTemporary() -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r95484 r95523 120 120 121 121 // These values record the result type of the node (as checked by NodeResultMask, above), 0 for no result. 122 #define NodeResultJS 0x1000 123 #define NodeResultNumber 0x2000 124 #define NodeResultInt32 0x3000 125 #define NodeResultBoolean 0x4000 122 #define NodeResultJS 0x1000 123 #define NodeResultNumber 0x2000 124 #define NodeResultInt32 0x3000 125 #define NodeResultBoolean 0x4000 126 #define NodeResultStorage 0x5000 126 127 127 128 // This macro defines a set of information about all known node types, used to populate NodeId, NodeType below. … … 185 186 macro(PutById, NodeMustGenerate | NodeClobbersWorld) \ 186 187 macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \ 188 macro(CheckStructure, NodeResultStorage | NodeMustGenerate) \ 189 macro(GetByOffset, NodeResultJS) \ 187 190 macro(GetMethod, NodeResultJS | NodeMustGenerate) \ 188 191 macro(CheckMethod, NodeResultJS | NodeMustGenerate) \ … … 239 242 // a constant index, argument, or identifier) from a NodeIndex. 240 243 struct OpInfo { 241 explicit OpInfo(unsigned value) : m_value(value) {} 242 unsigned m_value; 244 explicit OpInfo(int value) : m_value(value) { } 245 explicit OpInfo(unsigned value) : m_value(value) { } 246 explicit OpInfo(uintptr_t value) : m_value(value) { } 247 explicit OpInfo(void* value) : m_value(reinterpret_cast<uintptr_t>(value)) { } 248 uintptr_t m_value; 243 249 }; 244 250 … … 283 289 , m_refCount(0) 284 290 , m_opInfo(imm1.m_value) 285 , m_opInfo2( imm2.m_value)291 , m_opInfo2(safeCast<unsigned>(imm2.m_value)) 286 292 { 287 293 ASSERT(!(op & NodeHasVarArgs)); … … 298 304 , m_refCount(0) 299 305 , m_opInfo(imm1.m_value) 300 , m_opInfo2( imm2.m_value)306 , m_opInfo2(safeCast<unsigned>(imm2.m_value)) 301 307 { 302 308 ASSERT(op & NodeHasVarArgs); … … 458 464 case Call: 459 465 case Construct: 466 case GetByOffset: 460 467 return true; 461 468 default: … … 499 506 } 500 507 508 bool hasStructure() 509 { 510 return op == CheckStructure; 511 } 512 513 Structure* structure() 514 { 515 return reinterpret_cast<Structure*>(m_opInfo); 516 } 517 518 bool hasStorageAccessData() 519 { 520 return op == GetByOffset; 521 } 522 523 unsigned storageAccessDataIndex() 524 { 525 return m_opInfo; 526 } 527 501 528 bool hasVirtualRegister() 502 529 { … … 610 637 // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects). 611 638 unsigned m_refCount; 612 // Immediate values, accesses type-checked via accessors above. 613 unsigned m_opInfo, m_opInfo2; 639 // Immediate values, accesses type-checked via accessors above. The first one is 640 // big enough to store a pointer. 641 uintptr_t m_opInfo; 642 unsigned m_opInfo2; 614 643 }; 615 644 -
trunk/Source/JavaScriptCore/dfg/DFGPropagator.cpp
r95484 r95523 302 302 } 303 303 304 case CheckStructure: { 305 // We backward propagate what this CheckStructure tells us. Maybe that's the right way 306 // to go; maybe it isn't. I'm not sure. What we'd really want is flow-sensitive 307 // forward propagation of what we learn from having executed CheckStructure. But for 308 // now we preserve the flow-insensitive nature of this analysis, because it's cheap to 309 // run and seems to work well enough. 310 changed |= mergeUse(node.child1(), predictionFromStructure(node.structure()) | StrongPredictionTag); 311 changed |= setPrediction(PredictOther | StrongPredictionTag); 312 break; 313 } 314 315 case GetByOffset: { 316 changed |= node.predict(m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction); 317 if (isStrongPrediction(node.getPrediction())) 318 changed |= setPrediction(node.getPrediction()); 319 break; 320 } 321 304 322 case CheckMethod: { 305 323 changed |= mergeUse(node.child1(), PredictObjectUnknown | StrongPredictionTag); … … 661 679 NodeIndex globalVarLoadElimination(unsigned varNumber) 662 680 { 663 NodeIndex start = startIndex ();681 NodeIndex start = startIndexForChildren(); 664 682 for (NodeIndex index = m_compileIndex; index-- > start;) { 665 683 Node& node = m_graph[index]; … … 707 725 NodeIndex getMethodLoadElimination(const MethodCheckData& methodCheckData, unsigned identifierNumber, NodeIndex child1) 708 726 { 709 NodeIndex start = startIndex ();727 NodeIndex start = startIndexForChildren(child1); 710 728 for (NodeIndex index = m_compileIndex; index-- > start;) { 711 729 Node& node = m_graph[index]; … … 714 732 && node.identifierNumber() == identifierNumber 715 733 && m_graph.m_methodCheckData[node.methodCheckDataIndex()] == methodCheckData) 734 return index; 735 if (clobbersWorld(index)) 736 break; 737 } 738 return NoNode; 739 } 740 741 NodeIndex checkStructureLoadElimination(Structure* structure, NodeIndex child1) 742 { 743 NodeIndex start = startIndexForChildren(child1); 744 for (NodeIndex index = m_compileIndex; index-- > start;) { 745 Node& node = m_graph[index]; 746 if (node.op == CheckStructure 747 && node.child1() == child1 748 && node.structure() == structure) 749 return index; 750 if (clobbersWorld(index)) 751 break; 752 } 753 return NoNode; 754 } 755 756 NodeIndex getByOffsetLoadElimination(unsigned identifierNumber, NodeIndex child1) 757 { 758 NodeIndex start = startIndexForChildren(child1); 759 for (NodeIndex index = m_compileIndex; index-- > start;) { 760 Node& node = m_graph[index]; 761 if (node.op == GetByOffset 762 && node.child1() == child1 763 && m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber == identifierNumber) 716 764 return index; 717 765 if (clobbersWorld(index)) … … 851 899 break; 852 900 901 case CheckStructure: 902 setReplacement(checkStructureLoadElimination(node.structure(), node.child1())); 903 break; 904 905 case GetByOffset: 906 setReplacement(getByOffsetLoadElimination(m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber, node.child1())); 907 break; 908 853 909 default: 854 910 // do nothing. -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r95484 r95523 142 142 return allocate(); 143 143 } 144 145 case DataFormatStorage: 146 ASSERT_NOT_REACHED(); 144 147 } 145 148 … … 273 276 case DataFormatNone: // Should have filled, above. 274 277 case DataFormatBoolean: // This type never occurs. 278 case DataFormatStorage: 275 279 ASSERT_NOT_REACHED(); 276 280 … … 407 411 return allocate(); 408 412 } 413 414 case DataFormatStorage: 415 ASSERT_NOT_REACHED(); 409 416 } 410 417 … … 477 484 return allocate(); 478 485 } 486 487 case DataFormatStorage: 488 ASSERT_NOT_REACHED(); 479 489 } 480 490 … … 1495 1505 1496 1506 jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly); 1507 break; 1508 } 1509 1510 case CheckStructure: { 1511 SpeculateCellOperand base(this, node.child1()); 1512 GPRTemporary result(this, base); 1513 1514 GPRReg baseGPR = base.gpr(); 1515 GPRReg resultGPR = result.gpr(); 1516 1517 speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structure()))); 1518 1519 m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR); 1520 1521 storageResult(resultGPR, m_compileIndex); 1522 break; 1523 } 1524 1525 case GetByOffset: { 1526 StorageOperand storage(this, node.child1()); 1527 GPRTemporary result(this, storage); 1528 1529 GPRReg storageGPR = storage.gpr(); 1530 GPRReg resultGPR = result.gpr(); 1531 1532 StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node.storageAccessDataIndex()]; 1533 1534 m_jit.loadPtr(JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue)), resultGPR); 1535 1536 jsValueResult(resultGPR, m_compileIndex); 1497 1537 break; 1498 1538 } -
trunk/Source/JavaScriptCore/wtf/StdLibExtras.h
r93466 r95523 27 27 #define WTF_StdLibExtras_h 28 28 29 #include <wtf/Assertions.h> 29 #include "CheckedArithmetic.h" 30 #include "Assertions.h" 30 31 31 32 // Use these to declare and define a static local variable (static T;) so that … … 101 102 u.from = from; 102 103 return u.to; 104 } 105 106 template<typename To, typename From> 107 inline To safeCast(From value) 108 { 109 ASSERT(isInBounds<To>(value)); 110 return static_cast<To>(value); 103 111 } 104 112 … … 210 218 using WTF::binarySearch; 211 219 using WTF::bitwise_cast; 220 using WTF::safeCast; 212 221 213 222 #endif // WTF_StdLibExtras_h
Note: See TracChangeset
for help on using the changeset viewer.