Changeset 128699 in webkit
- Timestamp:
- Sep 15, 2012 7:36:22 PM (12 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r128680 r128699 1 2012-09-15 Filip Pizlo <fpizlo@apple.com> 2 3 Structure check hoisting fails to consider the possibility of conflicting checks on the source of the first assignment to the hoisted variable 4 https://bugs.webkit.org/show_bug.cgi?id=96872 5 6 Reviewed by Oliver Hunt. 7 8 This does a few related things: 9 10 - It turns off the use of ForceOSRExit for sure-to-fail CheckStructures, because 11 I noticed that this would sometimes happen for a ForwardCheckStructure. The 12 problem is that ForceOSRExit exits backwards, not forwards. Since the code that 13 led to those ForceOSRExit's being inserted was written out of paranoia rather 14 than need, I removed it. Specifically, I removed the m_isValid = false code 15 for CheckStructure/StructureTransitionWatchpoint in AbstractState. 16 17 - If a structure check causes a structure set to go empty, we don't want a 18 PutStructure to revive the set. It should instead be smart enough to realize 19 that an empty set implies that the code can't execute. This was the only "bug" 20 that the use of m_isValid = false was preventing. 21 22 - Finally, the main change: structure check hoisting looks at the source of the 23 SetLocals on structure-check-hoistable variables and ensures that the source 24 is not checked with a conflicting structure. This is O(n^2) but it does not 25 show up at all in performance tests. 26 27 The first two parts of this change were auxiliary bugs that were revealed by 28 the structure check hoister doing bad things. 29 30 * dfg/DFGAbstractState.cpp: 31 (JSC::DFG::AbstractState::initialize): 32 (JSC::DFG::AbstractState::execute): 33 * dfg/DFGStructureCheckHoistingPhase.cpp: 34 (JSC::DFG::StructureCheckHoistingPhase::run): 35 1 36 2012-09-14 Filip Pizlo <fpizlo@apple.com> 2 37 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
r128544 r128699 148 148 AbstractValue value; 149 149 value.setMostSpecific(graph.m_mustHandleValues[i]); 150 block->valuesAtHead.operand(graph.m_mustHandleValues.operandForIndex(i)).merge(value); 150 int operand = graph.m_mustHandleValues.operandForIndex(i); 151 block->valuesAtHead.operand(operand).merge(value); 152 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) 153 dataLog(" Initializing Block #%u, operand r%d, to ", blockIndex, operand); 154 block->valuesAtHead.operand(operand).dump(WTF::dataFile()); 155 dataLog("\n"); 156 #endif 151 157 } 152 158 block->cfaShouldRevisit = true; … … 1294 1300 || !isCellSpeculation(value.m_type)); 1295 1301 value.filter(set); 1296 // This is likely to be unnecessary, but it's conservative, and that's a good thing.1297 // This is trying to avoid situations where the CFA proves that this structure check1298 // must fail due to a future structure proof. We have two options at that point. We1299 // can either compile all subsequent code as we would otherwise, or we can ensure1300 // that the subsequent code is never reachable. The former is correct because the1301 // Proof Is Infallible (TM) -- hence even if we don't force the subsequent code to1302 // be unreachable, it must be unreachable nonetheless. But imagine what would happen1303 // if the proof was borked. In the former case, we'd get really bizarre bugs where1304 // we assumed that the structure of this object was known even though it wasn't. In1305 // the latter case, we'd have a slight performance pathology because this would be1306 // turned into an OSR exit unnecessarily. Which would you rather have?1307 if (value.m_currentKnownStructure.isClear()1308 || value.m_futurePossibleStructure.isClear())1309 m_isValid = false;1310 1302 m_haveStructures = true; 1311 1303 break; … … 1326 1318 ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad. 1327 1319 value.filter(node.structure()); 1328 // See comment in CheckStructure for why this is here.1329 if (value.m_currentKnownStructure.isClear()1330 || value.m_futurePossibleStructure.isClear())1331 m_isValid = false;1332 1320 m_haveStructures = true; 1333 1321 node.setCanExit(true); … … 1338 1326 case PhantomPutStructure: 1339 1327 node.setCanExit(false); 1340 clobberStructures(indexInBlock); 1341 forNode(node.child1()).set(node.structureTransitionData().newStructure); 1342 m_haveStructures = true; 1328 if (!forNode(node.child1()).m_currentKnownStructure.isClear()) { 1329 clobberStructures(indexInBlock); 1330 forNode(node.child1()).set(node.structureTransitionData().newStructure); 1331 m_haveStructures = true; 1332 } 1343 1333 break; 1344 1334 case GetButterfly: -
trunk/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
r128400 r128699 68 68 continue; 69 69 switch (node.op()) { 70 case CheckStructure: { 70 case CheckStructure: 71 case StructureTransitionWatchpoint: { 71 72 Node& child = m_graph[node.child1()]; 72 73 if (child.op() != GetLocal) … … 92 93 case PutByOffset: 93 94 case PutStructure: 94 case StructureTransitionWatchpoint:95 95 case AllocatePropertyStorage: 96 96 case ReallocatePropertyStorage: … … 105 105 // Don't count these uses. 106 106 break; 107 108 case SetLocal: { 109 // Find all uses of the source of the SetLocal. If any of them are a 110 // kind of CheckStructure, then we should notice them to ensure that 111 // we're not hoisting a check that would contravene checks that are 112 // already being performed. 113 VariableAccessData* variable = node.variableAccessData(); 114 if (variable->isCaptured() || variable->structureCheckHoistingFailed()) 115 break; 116 if (!isCellSpeculation(variable->prediction())) 117 break; 118 NodeIndex source = node.child1().index(); 119 for (unsigned subIndexInBlock = 0; subIndexInBlock < block->size(); ++subIndexInBlock) { 120 NodeIndex subNodeIndex = block->at(subIndexInBlock); 121 Node& subNode = m_graph[subNodeIndex]; 122 if (!subNode.shouldGenerate()) 123 continue; 124 switch (subNode.op()) { 125 case CheckStructure: 126 case StructureTransitionWatchpoint: { 127 if (subNode.child1().index() != source) 128 break; 129 130 noticeStructureCheck(variable, subNode.structureSet()); 131 break; 132 } 133 default: 134 break; 135 } 136 } 137 138 m_graph.vote(node, VoteOther); 139 break; 140 } 107 141 108 142 default:
Note: See TracChangeset
for help on using the changeset viewer.