Changeset 117542 in webkit
- Timestamp:
- May 17, 2012, 10:30:16 PM (13 years ago)
- Location:
- branches/dfgopt
- Files:
-
- 18 added
- 28 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/dfgopt/LayoutTests/ChangeLog
r114449 r117542 1 2012-05-17 Filip Pizlo <fpizlo@apple.com> 2 3 DFG should optimize aliased uses of the Arguments object of the current call frame 4 https://bugs.webkit.org/show_bug.cgi?id=86552 5 6 Rubber stamped by Geoff Garen. 7 8 Added a bunch of tests that check that our optimizations for aliased uses of the 9 'arguments' object are robust against various forms of JavaScript crazy. 10 11 * fast/js/dfg-arguments-alias-escape-expected.txt: Added. 12 * fast/js/dfg-arguments-alias-escape.html: Added. 13 * fast/js/dfg-arguments-alias-expected.txt: Added. 14 * fast/js/dfg-arguments-alias.html: Added. 15 * fast/js/dfg-arguments-cross-code-origin-expected.txt: Added. 16 * fast/js/dfg-arguments-cross-code-origin.html: Added. 17 * fast/js/dfg-arguments-mixed-alias-expected.txt: Added. 18 * fast/js/dfg-arguments-mixed-alias.html: Added. 19 * fast/js/dfg-arguments-osr-exit-expected.txt: Added. 20 * fast/js/dfg-arguments-osr-exit.html: Added. 21 * fast/js/dfg-arguments-unexpected-escape-expected.txt: Added. 22 * fast/js/dfg-arguments-unexpected-escape.html: Added. 23 * fast/js/jsc-test-list: 24 * fast/js/script-tests/dfg-arguments-alias-escape.js: Added. 25 (foo): 26 (bar): 27 * fast/js/script-tests/dfg-arguments-alias.js: Added. 28 (foo): 29 (bar): 30 * fast/js/script-tests/dfg-arguments-cross-code-origin.js: Added. 31 (foo): 32 (bar): 33 (baz): 34 * fast/js/script-tests/dfg-arguments-mixed-alias.js: Added. 35 (foo): 36 (bar): 37 * fast/js/script-tests/dfg-arguments-osr-exit.js: Added. 38 (baz): 39 (foo): 40 (bar): 41 * fast/js/script-tests/dfg-arguments-unexpected-escape.js: Added. 42 (baz): 43 (foo): 44 (bar): 45 1 46 2012-04-17 Vincent Scheib <scheib@chromium.org> 2 47 -
branches/dfgopt/LayoutTests/fast/js/jsc-test-list
r107997 r117542 65 65 fast/js/delete-getters-setters 66 66 fast/js/delete-then-put 67 fast/js/dfg-arguments-osr-exit 68 fast/js/dfg-arguments-mixed-alias 69 fast/js/dfg-arguments-cross-code-origin 70 fast/js/dfg-arguments-unexpected-escape 71 fast/js/dfg-arguments-alias 72 fast/js/dfg-arguments-alias-escape 67 73 fast/js/dfg-array-length-dead 68 74 fast/js/dfg-convert-this-dom-window -
branches/dfgopt/Source/JavaScriptCore/ChangeLog
r117370 r117542 1 2012-05-17 Filip Pizlo <fpizlo@apple.com> 2 3 DFG should optimize aliased uses of the Arguments object of the current call frame 4 https://bugs.webkit.org/show_bug.cgi?id=86552 5 6 Reviewed by Geoff Garen. 7 8 Performs must-alias and escape analysis on uses of CreateArguments, and if 9 a variable is must-aliased to CreateArguments and does not escape, then we 10 turn all uses of that variable into direct arguments accesses. 11 12 36% speed-up on V8/earley leading to a 2.3% speed-up overall in V8. 13 14 * bytecode/CodeBlock.h: 15 (JSC::CodeBlock::uncheckedArgumentsRegister): 16 * bytecode/ValueRecovery.h: 17 (JSC::ValueRecovery::argumentsThatWereNotCreated): 18 (ValueRecovery): 19 (JSC::ValueRecovery::dump): 20 * dfg/DFGAbstractState.cpp: 21 (JSC::DFG::AbstractState::execute): 22 * dfg/DFGAdjacencyList.h: 23 (AdjacencyList): 24 (JSC::DFG::AdjacencyList::removeEdgeFromBag): 25 * dfg/DFGArgumentsSimplificationPhase.cpp: 26 (JSC::DFG::ArgumentsSimplificationPhase::run): 27 (ArgumentsSimplificationPhase): 28 (JSC::DFG::ArgumentsSimplificationPhase::observeBadArgumentsUse): 29 (JSC::DFG::ArgumentsSimplificationPhase::observeBadArgumentsUses): 30 (JSC::DFG::ArgumentsSimplificationPhase::observeProperArgumentsUse): 31 (JSC::DFG::ArgumentsSimplificationPhase::isOKToOptimize): 32 (JSC::DFG::ArgumentsSimplificationPhase::removeArgumentsReferencingPhantomChild): 33 * dfg/DFGAssemblyHelpers.h: 34 (JSC::DFG::AssemblyHelpers::argumentsRegisterFor): 35 (AssemblyHelpers): 36 * dfg/DFGByteCodeParser.cpp: 37 (JSC::DFG::ByteCodeParser::parseBlock): 38 * dfg/DFGCFGSimplificationPhase.cpp: 39 (JSC::DFG::CFGSimplificationPhase::removePotentiallyDeadPhiReference): 40 * dfg/DFGGPRInfo.h: 41 (GPRInfo): 42 * dfg/DFGGraph.cpp: 43 (JSC::DFG::Graph::collectGarbage): 44 (DFG): 45 * dfg/DFGGraph.h: 46 (Graph): 47 (JSC::DFG::Graph::executableFor): 48 (JSC::DFG::Graph::argumentsRegisterFor): 49 (JSC::DFG::Graph::uncheckedArgumentsRegisterFor): 50 (JSC::DFG::Graph::clobbersWorld): 51 * dfg/DFGNode.h: 52 (JSC::DFG::Node::hasHeapPrediction): 53 * dfg/DFGNodeType.h: 54 (DFG): 55 * dfg/DFGOSRExitCompiler.cpp: 56 * dfg/DFGOSRExitCompiler.h: 57 (JSC::DFG::OSRExitCompiler::OSRExitCompiler): 58 (OSRExitCompiler): 59 * dfg/DFGOSRExitCompiler32_64.cpp: 60 (JSC::DFG::OSRExitCompiler::compileExit): 61 * dfg/DFGOSRExitCompiler64.cpp: 62 (JSC::DFG::OSRExitCompiler::compileExit): 63 * dfg/DFGOperations.cpp: 64 * dfg/DFGPredictionPropagationPhase.cpp: 65 (JSC::DFG::PredictionPropagationPhase::propagate): 66 * dfg/DFGSpeculativeJIT.cpp: 67 (JSC::DFG::ValueSource::dump): 68 (JSC::DFG::SpeculativeJIT::compile): 69 (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): 70 * dfg/DFGSpeculativeJIT.h: 71 * dfg/DFGSpeculativeJIT32_64.cpp: 72 (JSC::DFG::SpeculativeJIT::compile): 73 * dfg/DFGSpeculativeJIT64.cpp: 74 (JSC::DFG::SpeculativeJIT::compile): 75 * dfg/DFGVariableAccessData.h: 76 (JSC::DFG::VariableAccessData::VariableAccessData): 77 (JSC::DFG::VariableAccessData::mergeIsArgumentsAlias): 78 (VariableAccessData): 79 (JSC::DFG::VariableAccessData::isArgumentsAlias): 80 * jit/JITOpcodes.cpp: 81 (JSC::JIT::emitSlow_op_get_argument_by_val): 82 1 83 2012-05-16 Filip Pizlo <fpizlo@apple.com> 2 84 -
branches/dfgopt/Source/JavaScriptCore/bytecode/CodeBlock.h
r116912 r117542 448 448 return m_argumentsRegister; 449 449 } 450 int uncheckedArgumentsRegister() 451 { 452 if (!usesArguments()) 453 return InvalidVirtualRegister; 454 return argumentsRegister(); 455 } 450 456 void setActivationRegister(int activationRegister) 451 457 { -
branches/dfgopt/Source/JavaScriptCore/bytecode/ValueRecovery.h
r112164 r117542 62 62 CellDisplacedInRegisterFile, 63 63 BooleanDisplacedInRegisterFile, 64 // It's an Arguments object. 65 ArgumentsThatWereNotCreated, 64 66 // It's a constant. 65 67 Constant, … … 188 190 result.m_technique = Constant; 189 191 result.m_source.constant = JSValue::encode(value); 192 return result; 193 } 194 195 static ValueRecovery argumentsThatWereNotCreated() 196 { 197 ValueRecovery result; 198 result.m_technique = ArgumentsThatWereNotCreated; 190 199 return result; 191 200 } … … 316 325 fprintf(out, "*bool(%d)", virtualRegister()); 317 326 break; 327 case ArgumentsThatWereNotCreated: 328 fprintf(out, "arguments"); 329 break; 318 330 case Constant: 319 331 fprintf(out, "[%s]", constant().description()); -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
r117370 r117542 1096 1096 1097 1097 case GetMyArgumentsLength: 1098 if (!m_graph.m_executablesWhoseArgumentsEscaped.contains( 1099 m_graph.executableFor(node.codeOrigin))) { 1100 // We know that this executable does not escape its arguments, so we can optimize 1101 // the arguments a bit. Note that this is not sufficient to force constant folding 1102 // of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation. 1103 // We perform further optimizations on this later on. 1104 if (node.codeOrigin.inlineCallFrame) { 1105 forNode(nodeIndex).set(jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1)); 1106 break; 1107 } 1108 forNode(nodeIndex).set(PredictInt32); 1109 break; 1110 } 1098 // We know that this executable does not escape its arguments, so we can optimize 1099 // the arguments a bit. Note that this is not sufficient to force constant folding 1100 // of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation. 1101 // We perform further optimizations on this later on. 1102 if (node.codeOrigin.inlineCallFrame) { 1103 forNode(nodeIndex).set(jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1)); 1104 break; 1105 } 1106 forNode(nodeIndex).set(PredictInt32); 1107 break; 1108 1109 case GetMyArgumentsLengthSafe: 1111 1110 // This potentially clobbers all structures if the arguments object had a getter 1112 1111 // installed on the length property. … … 1118 1117 1119 1118 case GetMyArgumentByVal: 1120 if (!m_graph.m_executablesWhoseArgumentsEscaped.contains( 1121 m_graph.executableFor(node.codeOrigin))) { 1122 // We know that this executable does not escape its arguments, so we can optimize 1123 // the arguments a bit. Note that this ends up being further optimized by the 1124 // ArgumentsSimplificationPhase. 1125 forNode(node.child1()).filter(PredictInt32); 1126 forNode(nodeIndex).makeTop(); 1127 break; 1128 } 1119 // We know that this executable does not escape its arguments, so we can optimize 1120 // the arguments a bit. Note that this ends up being further optimized by the 1121 // ArgumentsSimplificationPhase. 1122 forNode(node.child1()).filter(PredictInt32); 1123 forNode(nodeIndex).makeTop(); 1124 break; 1125 1126 case GetMyArgumentByValSafe: 1129 1127 // This potentially clobbers all structures if the property we're accessing has 1130 1128 // a getter. We don't speculate against this. -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGAdjacencyList.h
r115512 r117542 129 129 initialize(); 130 130 } 131 132 // Call this if you wish to remove an edge and the node treats the list of children 133 // as a "bag" - an unordered set where the index of the edge does not matter. 134 void removeEdgeFromBag(unsigned edgeIndex) 135 { 136 for (unsigned i = edgeIndex; i < Size - 1; ++i) 137 setChild(i, child(i + 1)); 138 setChild(Size - 1, Edge()); 139 } 131 140 132 141 unsigned firstChild() const -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
r117017 r117542 35 35 #include "DFGPhase.h" 36 36 #include "DFGValidate.h" 37 #include <wtf/HashSet.h> 38 #include <wtf/HashMap.h> 37 39 38 40 namespace JSC { namespace DFG { 41 42 namespace { 43 44 template<typename T> 45 struct NullableHashTraits : public HashTraits<T> { 46 static const bool emptyValueIsZero = false; 47 static T emptyValue() { return reinterpret_cast<T>(1); } 48 }; 49 50 struct ArgumentsAliasingData { 51 InlineCallFrame* callContext; 52 bool callContextSet; 53 bool multipleCallContexts; 54 55 bool assignedFromArguments; 56 bool assignedFromManyThings; 57 58 bool escapes; 59 60 ArgumentsAliasingData() 61 : callContext(0) 62 , callContextSet(false) 63 , multipleCallContexts(false) 64 , assignedFromArguments(false) 65 , assignedFromManyThings(false) 66 , escapes(false) 67 { 68 } 69 70 void mergeCallContext(InlineCallFrame* newCallContext) 71 { 72 if (multipleCallContexts) 73 return; 74 75 if (!callContextSet) { 76 callContext = newCallContext; 77 callContextSet = true; 78 return; 79 } 80 81 if (callContext == newCallContext) 82 return; 83 84 multipleCallContexts = true; 85 } 86 87 bool callContextIsValid() 88 { 89 return callContextSet && !multipleCallContexts; 90 } 91 92 void mergeArgumentsAssignment() 93 { 94 assignedFromArguments = true; 95 } 96 97 void mergeNonArgumentsAssignment() 98 { 99 assignedFromManyThings = true; 100 } 101 102 bool argumentsAssignmentIsValid() 103 { 104 return assignedFromArguments && !assignedFromManyThings; 105 } 106 107 bool isValid() 108 { 109 return callContextIsValid() && argumentsAssignmentIsValid() && !escapes; 110 } 111 }; 112 113 } // end anonymous namespace 39 114 40 115 class ArgumentsSimplificationPhase : public Phase { … … 52 127 bool changed = false; 53 128 54 InsertionSet<NodeIndex> insertionSet; 55 129 // Record which arguments are known to escape no matter what. 130 for (unsigned i = codeBlock()->inlineCallFrames().size(); i--;) { 131 InlineCallFrame* inlineCallFrame = &codeBlock()->inlineCallFrames()[i]; 132 if (m_graph.m_executablesWhoseArgumentsEscaped.contains( 133 m_graph.executableFor(inlineCallFrame))) 134 m_createsArguments.add(inlineCallFrame); 135 } 136 137 // Create data for variable access datas that we will want to analyze. 138 for (unsigned i = m_graph.m_variableAccessData.size(); i--;) { 139 VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i]; 140 if (!variableAccessData->isRoot()) 141 continue; 142 if (variableAccessData->isCaptured()) 143 continue; 144 m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData()); 145 } 146 147 // Figure out which variables alias the arguments and nothing else, and are 148 // used only for GetByVal and GetArgumentsLength accesses. At the same time, 149 // identify uses of CreateArguments that are not consistent with the arguments 150 // being aliased only to variables that satisfy these constraints. 56 151 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { 57 152 BasicBlock* block = m_graph.m_blocks[blockIndex].get(); … … 61 156 NodeIndex nodeIndex = block->at(indexInBlock); 62 157 Node& node = m_graph[nodeIndex]; 158 if (!node.shouldGenerate()) 159 continue; 63 160 switch (node.op()) { 64 case GetMyArgumentsLength: { 65 if (m_graph.m_executablesWhoseArgumentsEscaped.contains( 66 m_graph.executableFor(node.codeOrigin))) 67 break; 161 case CreateArguments: { 162 // Ignore this op. If we see a lone CreateArguments then we want to 163 // completely ignore it because: 164 // 1) The default would be to see that the child is a GetLocal on the 165 // arguments register and conclude that we have an arguments escape. 166 // 2) The fact that a CreateArguments exists does not mean that it 167 // will continue to exist after we're done with this phase. As far 168 // as this phase is concerned, a CreateArguments only "exists" if it 169 // is used in a manner that necessitates its existance. 170 break; 171 } 172 173 case SetLocal: { 174 Node& source = m_graph[node.child1()]; 175 VariableAccessData* variableAccessData = node.variableAccessData(); 176 if (source.op() != CreateArguments) { 177 // Make sure that the source of the SetLocal knows that if it's 178 // a variable that we think is aliased to the arguments, then it 179 // may escape at this point. In future, we could track transitive 180 // aliasing. But not yet. 181 observeBadArgumentsUse(node.child1()); 182 183 if (variableAccessData->isCaptured()) 184 break; 185 186 // Make sure that if it's a variable that we think is aliased to 187 // the arguments, that we know that it might actually not be. 188 ArgumentsAliasingData& data = 189 m_argumentsAliasing.find(variableAccessData)->second; 190 data.mergeNonArgumentsAssignment(); 191 data.mergeCallContext(node.codeOrigin.inlineCallFrame); 192 break; 193 } 194 int argumentsRegister = 195 m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin); 196 if (variableAccessData->local() == argumentsRegister 197 || variableAccessData->local() == 198 unmodifiedArgumentsRegister(argumentsRegister)) { 199 if (node.codeOrigin.inlineCallFrame == source.codeOrigin.inlineCallFrame) 200 break; 201 m_createsArguments.add(source.codeOrigin.inlineCallFrame); 202 break; 203 } 204 if (variableAccessData->isCaptured()) { 205 m_createsArguments.add(source.codeOrigin.inlineCallFrame); 206 break; 207 } 208 ArgumentsAliasingData& data = 209 m_argumentsAliasing.find(variableAccessData)->second; 210 data.mergeArgumentsAssignment(); 211 // This ensures that the variable's uses are in the same context as 212 // the arguments it is aliasing. 213 data.mergeCallContext(node.codeOrigin.inlineCallFrame); 214 data.mergeCallContext(source.codeOrigin.inlineCallFrame); 215 break; 216 } 217 218 case GetLocal: 219 case Phi: { 220 VariableAccessData* variableAccessData = node.variableAccessData(); 221 if (variableAccessData->isCaptured()) 222 break; 223 ArgumentsAliasingData& data = 224 m_argumentsAliasing.find(variableAccessData)->second; 225 data.mergeCallContext(node.codeOrigin.inlineCallFrame); 226 break; 227 } 228 229 case Flush: { 230 VariableAccessData* variableAccessData = node.variableAccessData(); 231 if (variableAccessData->isCaptured()) 232 break; 233 ArgumentsAliasingData& data = 234 m_argumentsAliasing.find(variableAccessData)->second; 235 data.mergeCallContext(node.codeOrigin.inlineCallFrame); 236 237 // If a variable is used in a flush then by definition it escapes. 238 data.escapes = true; 239 break; 240 } 241 242 case SetArgument: { 243 VariableAccessData* variableAccessData = node.variableAccessData(); 244 if (variableAccessData->isCaptured()) 245 break; 246 ArgumentsAliasingData& data = 247 m_argumentsAliasing.find(variableAccessData)->second; 248 data.mergeNonArgumentsAssignment(); 249 data.mergeCallContext(node.codeOrigin.inlineCallFrame); 250 break; 251 } 252 253 case GetByVal: { 254 if (!node.prediction() 255 || !m_graph[node.child1()].prediction() 256 || !m_graph[node.child2()].prediction()) { 257 observeBadArgumentsUses(node); 258 break; 259 } 260 261 if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) 262 || !m_graph[node.child2()].shouldSpeculateInteger()) { 263 observeBadArgumentsUses(node); 264 break; 265 } 266 267 if (m_graph[node.child1()].shouldSpeculateArguments()) { 268 // If arguments is used as an index, then it's an escaping use. 269 // That's so awful and pretty much impossible since it would 270 // imply that the arguments were predicted integer, but it's 271 // good to be defensive and thorough. 272 observeBadArgumentsUse(node.child2()); 273 observeProperArgumentsUse(node, node.child1()); 274 break; 275 } 276 277 observeBadArgumentsUses(node); 278 break; 279 } 280 281 case GetArgumentsLength: { 282 observeProperArgumentsUse(node, node.child1()); 283 break; 284 } 285 286 default: 287 observeBadArgumentsUses(node); 288 break; 289 } 290 } 291 } 292 293 // Now we know which variables are aliased to arguments. But if any of them are 294 // found to have escaped, or were otherwise invalidated, then we need to mark 295 // the arguments as requiring creation. This is a property of SetLocals to 296 // variables that are neither the correct arguments register nor are marked as 297 // being arguments-aliased. 298 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { 299 BasicBlock* block = m_graph.m_blocks[blockIndex].get(); 300 if (!block) 301 continue; 302 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { 303 NodeIndex nodeIndex = block->at(indexInBlock); 304 Node& node = m_graph[nodeIndex]; 305 if (!node.shouldGenerate()) 306 continue; 307 if (node.op() != SetLocal) 308 continue; 309 Node& source = m_graph[node.child1()]; 310 if (source.op() != CreateArguments) 311 continue; 312 VariableAccessData* variableAccessData = node.variableAccessData(); 313 if (variableAccessData->isCaptured()) { 314 // The captured case would have already been taken care of in the 315 // previous pass. 316 continue; 317 } 318 319 ArgumentsAliasingData& data = 320 m_argumentsAliasing.find(variableAccessData)->second; 321 if (data.isValid()) 322 continue; 323 324 m_createsArguments.add(source.codeOrigin.inlineCallFrame); 325 } 326 } 327 328 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) 329 dataLog("Arguments aliasing states:\n"); 330 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { 331 VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i]; 332 if (!variableAccessData->isRoot()) 333 continue; 334 dataLog(" r%d(%s): ", variableAccessData->local(), m_graph.nameOfVariableAccessData(variableAccessData)); 335 if (variableAccessData->isCaptured()) 336 dataLog("Captured"); 337 else { 338 ArgumentsAliasingData& data = 339 m_argumentsAliasing.find(variableAccessData)->second; 340 bool first = true; 341 if (data.callContextIsValid()) { 342 if (!first) 343 dataLog(", "); 344 dataLog("Have Call Context: %p", data.callContext); 345 first = false; 346 if (!m_createsArguments.contains(data.callContext)) 347 dataLog(" (Does Not Create Arguments)"); 348 } 349 if (data.argumentsAssignmentIsValid()) { 350 if (!first) 351 dataLog(", "); 352 dataLog("Arguments Assignment Is Valid"); 353 first = false; 354 } 355 if (!data.escapes) { 356 if (!first) 357 dataLog(", "); 358 dataLog("Does Not Escape"); 359 first = false; 360 } 361 if (!first) 362 dataLog(", "); 363 if (data.isValid()) { 364 if (m_createsArguments.contains(data.callContext)) 365 dataLog("VALID"); 366 else 367 dataLog("INVALID (due to argument creation)"); 368 } else 369 dataLog("INVALID (due to bad variable use)"); 370 } 371 dataLog("\n"); 372 } 373 #endif 374 375 InsertionSet<NodeIndex> insertionSet; 376 377 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { 378 BasicBlock* block = m_graph.m_blocks[blockIndex].get(); 379 if (!block) 380 continue; 381 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { 382 NodeIndex nodeIndex = block->at(indexInBlock); 383 Node& node = m_graph[nodeIndex]; 384 if (!node.shouldGenerate()) 385 continue; 386 387 switch (node.op()) { 388 case SetLocal: { 389 Node& source = m_graph[node.child1()]; 390 if (source.op() != CreateArguments) 391 break; 392 393 VariableAccessData* variableAccessData = node.variableAccessData(); 394 395 // If this is a store into the arguments register for an InlineCallFrame* 396 // that does not create arguments, then kill it. 397 int argumentsRegister = 398 m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin); 399 if ((variableAccessData->local() == argumentsRegister 400 || variableAccessData->local() 401 == unmodifiedArgumentsRegister(argumentsRegister)) 402 && !m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) { 403 // Find the Flush. It should be the next instruction. 404 Node& flush = m_graph[block->at(indexInBlock + 1)]; 405 ASSERT(flush.op() == Flush); 406 ASSERT(flush.variableAccessData() == variableAccessData); 407 ASSERT(flush.child1() == nodeIndex); 408 // Be defensive in release mode. 409 if (flush.op() != Flush 410 || flush.variableAccessData() != variableAccessData 411 || flush.child1() != nodeIndex) 412 break; 413 flush.setOpAndDefaultFlags(Nop); 414 m_graph.clearAndDerefChild1(flush); 415 flush.setRefCount(0); 416 changed = true; 417 break; 418 } 419 420 if (variableAccessData->isCaptured()) 421 break; 422 423 // If this is a store into a VariableAccessData* that is marked as 424 // arguments aliasing for an InlineCallFrame* that does not create 425 // arguments, then flag the VariableAccessData as being an 426 // arguments-aliased. This'll let the OSR exit machinery do the right 427 // things. Note also that the SetLocal should become dead as soon as 428 // we replace all uses of this variable with GetMyArgumentsLength and 429 // GetMyArgumentByVal. 430 if (m_argumentsAliasing.find(variableAccessData)->second.isValid() 431 && !m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) { 432 changed |= variableAccessData->mergeIsArgumentsAlias(true); 433 break; 434 } 435 break; 436 } 437 438 case Phantom: { 439 // It's highly likely that we will have a Phantom referencing either 440 // CreateArguments, or a local op for the arguments register, or a 441 // local op for an arguments-aliased variable. In any of those cases, 442 // we should remote the phantom reference, since: 443 // 1) Phantoms only exist to aid OSR exit. But arguments simplification 444 // has its own OSR exit story, which is to inform OSR exit to reify 445 // the arguments as necessary. 446 // 2) The Phantom may keep the CreateArguments node alive, which is 447 // precisely what we don't want. 448 for (unsigned i = 0; i < AdjacencyList::Size; ++i) 449 removeArgumentsReferencingPhantomChild(node, i); 450 break; 451 } 452 453 case GetByVal: { 454 if (!node.prediction() 455 || !m_graph[node.child1()].prediction() 456 || !m_graph[node.child2()].prediction()) 457 break; 458 459 if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) 460 || !m_graph[node.child2()].shouldSpeculateInteger()) 461 break; 462 463 if (m_graph[node.child1()].shouldSpeculateArguments()) { 464 // This can be simplified to GetMyArgumentByVal if we know that 465 // it satisfies either condition (1) or (2): 466 // 1) Its first child is a valid ArgumentsAliasingData and the 467 // InlineCallFrame* is not marked as creating arguments. 468 // 2) Its first child is CreateArguments and its InlineCallFrame* 469 // is not marked as creating arguments. 470 471 if (!isOKToOptimize(m_graph[node.child1()])) 472 break; 473 474 m_graph.deref(node.child1()); 475 node.children.child1() = node.children.child2(); 476 node.children.child2() = Edge(); 477 node.setOpAndDefaultFlags(GetMyArgumentByVal); 478 changed = true; 479 --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal. 480 break; 481 } 482 break; 483 } 484 485 case GetArgumentsLength: { 486 if (!isOKToOptimize(m_graph[node.child1()])) 487 break; 488 489 m_graph.deref(node.child1()); 490 node.children.child1() = Edge(); 491 node.setOpAndDefaultFlags(GetMyArgumentsLength); 492 changed = true; 493 --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength. 494 break; 495 } 496 497 case GetMyArgumentsLength: 498 case GetMyArgumentsLengthSafe: { 499 if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) { 500 ASSERT(node.op() == GetMyArgumentsLengthSafe); 501 break; 502 } 503 if (node.op() == GetMyArgumentsLengthSafe) { 504 node.setOp(GetMyArgumentsLength); 505 changed = true; 506 } 68 507 if (!node.codeOrigin.inlineCallFrame) 69 508 break; … … 83 522 } 84 523 85 case GetMyArgumentByVal: { 86 if (m_graph.m_executablesWhoseArgumentsEscaped.contains( 87 m_graph.executableFor(node.codeOrigin))) 88 break; 524 case GetMyArgumentByVal: 525 case GetMyArgumentByValSafe: { 526 if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) { 527 ASSERT(node.op() == GetMyArgumentByValSafe); 528 break; 529 } 530 if (node.op() == GetMyArgumentByValSafe) { 531 node.setOp(GetMyArgumentByVal); 532 changed = true; 533 } 89 534 if (!node.codeOrigin.inlineCallFrame) 90 535 break; … … 139 584 } 140 585 586 if (changed) 587 m_graph.collectGarbage(); 588 141 589 return changed; 590 } 591 592 private: 593 HashSet<InlineCallFrame*, 594 DefaultHash<InlineCallFrame*>::Hash, 595 NullableHashTraits<InlineCallFrame*> > m_createsArguments; 596 HashMap<VariableAccessData*, ArgumentsAliasingData, 597 DefaultHash<VariableAccessData*>::Hash, 598 NullableHashTraits<VariableAccessData*> > m_argumentsAliasing; 599 600 void observeBadArgumentsUse(Edge edge) 601 { 602 if (!edge) 603 return; 604 605 Node& child = m_graph[edge]; 606 if (child.op() != GetLocal) 607 return; 608 609 if (child.local() == m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)) { 610 m_createsArguments.add(child.codeOrigin.inlineCallFrame); 611 return; 612 } 613 614 VariableAccessData* variableAccessData = child.variableAccessData(); 615 if (variableAccessData->isCaptured()) 616 return; 617 618 ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second; 619 data.escapes = true; 620 } 621 622 void observeBadArgumentsUses(Node& node) 623 { 624 for (unsigned i = m_graph.numChildren(node); i--;) 625 observeBadArgumentsUse(m_graph.child(node, i)); 626 } 627 628 void observeProperArgumentsUse(Node& node, Edge edge) 629 { 630 Node& child = m_graph[edge]; 631 if (child.op() != GetLocal) { 632 // When can this happen? At least two cases that I can think 633 // of: 634 // 635 // 1) Aliased use of arguments in the same basic block, 636 // like: 637 // 638 // var a = arguments; 639 // var x = arguments[i]; 640 // 641 // 2) If we're accessing arguments we got from the heap! 642 643 if (child.op() == CreateArguments 644 && node.codeOrigin.inlineCallFrame 645 != child.codeOrigin.inlineCallFrame) 646 m_createsArguments.add(child.codeOrigin.inlineCallFrame); 647 648 return; 649 } 650 651 VariableAccessData* variableAccessData = child.variableAccessData(); 652 if (variableAccessData->isCaptured()) 653 return; 654 655 ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second; 656 data.mergeCallContext(node.codeOrigin.inlineCallFrame); 657 } 658 659 bool isOKToOptimize(Node& source) 660 { 661 switch (source.op()) { 662 case GetLocal: { 663 VariableAccessData* variableAccessData = source.variableAccessData(); 664 if (variableAccessData->isCaptured()) 665 break; 666 ArgumentsAliasingData& data = 667 m_argumentsAliasing.find(variableAccessData)->second; 668 if (!data.isValid()) 669 break; 670 if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) 671 break; 672 673 return true; 674 } 675 676 case CreateArguments: { 677 if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) 678 break; 679 680 return true; 681 } 682 683 default: 684 break; 685 } 686 687 return false; 688 } 689 690 void removeArgumentsReferencingPhantomChild(Node& node, unsigned edgeIndex) 691 { 692 Edge edge = node.children.child(edgeIndex); 693 if (!edge) 694 return; 695 696 Node& child = m_graph[edge]; 697 switch (child.op()) { 698 case Phi: // Arises if we had CSE on a GetLocal of the arguments register. 699 case GetLocal: // Arises if we had CSE on an arguments access to a variable aliased to the arguments. 700 case SetLocal: { // Arises if we had CSE on a GetLocal of the arguments register. 701 VariableAccessData* variableAccessData = child.variableAccessData(); 702 bool isDeadArgumentsRegister = 703 variableAccessData->local() == 704 m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin) 705 && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame); 706 bool isAliasedArgumentsRegister = 707 !variableAccessData->isCaptured() 708 && m_argumentsAliasing.find(variableAccessData)->second.isValid() 709 && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame); 710 if (!isDeadArgumentsRegister && !isAliasedArgumentsRegister) 711 break; 712 m_graph.deref(edge); 713 node.children.removeEdgeFromBag(edgeIndex); 714 break; 715 } 716 717 case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first. 718 if (m_createsArguments.contains(child.codeOrigin.inlineCallFrame)) 719 break; 720 m_graph.deref(edge); 721 node.children.removeEdgeFromBag(edgeIndex); 722 break; 723 } 724 725 default: 726 break; 727 } 142 728 } 143 729 }; -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
r117017 r117542 312 312 } 313 313 314 int argumentsRegisterFor( const CodeOrigin& codeOrigin)315 { 316 if (! codeOrigin.inlineCallFrame)314 int argumentsRegisterFor(InlineCallFrame* inlineCallFrame) 315 { 316 if (!inlineCallFrame) 317 317 return codeBlock()->argumentsRegister(); 318 318 319 319 return baselineCodeBlockForInlineCallFrame( 320 codeOrigin.inlineCallFrame)->argumentsRegister() + 321 codeOrigin.inlineCallFrame->stackOffset; 320 inlineCallFrame)->argumentsRegister() + inlineCallFrame->stackOffset; 321 } 322 323 int argumentsRegisterFor(const CodeOrigin& codeOrigin) 324 { 325 return argumentsRegisterFor(codeOrigin.inlineCallFrame); 322 326 } 323 327 -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r117017 r117542 2454 2454 case op_create_arguments: { 2455 2455 m_graph.m_hasArguments = true; 2456 m_graph.m_executablesWhoseArgumentsEscaped.add(m_inlineStackTop->executable());2457 2456 NodeIndex createArguments = addToGraph(CreateArguments, get(currentInstruction[1].u.operand)); 2458 2457 set(currentInstruction[1].u.operand, createArguments); … … 2474 2473 case op_get_arguments_length: { 2475 2474 m_graph.m_hasArguments = true; 2476 set(currentInstruction[1].u.operand, addToGraph(GetMyArgumentsLength ));2475 set(currentInstruction[1].u.operand, addToGraph(GetMyArgumentsLengthSafe)); 2477 2476 NEXT_OPCODE(op_get_arguments_length); 2478 2477 } … … 2482 2481 set(currentInstruction[1].u.operand, 2483 2482 addToGraph( 2484 GetMyArgumentByVal , OpInfo(0), OpInfo(getPrediction()),2483 GetMyArgumentByValSafe, OpInfo(0), OpInfo(getPrediction()), 2485 2484 get(currentInstruction[3].u.operand))); 2486 2485 NEXT_OPCODE(op_get_argument_by_val); -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
r117370 r117542 396 396 if (phiNode.shouldGenerate()) 397 397 m_graph.deref(myNodeIndex); 398 for (unsigned i = edgeIndex; i < AdjacencyList::Size - 1; ++i) 399 phiNode.children.setChild(i, phiNode.children.child(i + 1)); 400 phiNode.children.setChild(AdjacencyList::Size - 1, Edge()); 398 phiNode.children.removeEdgeFromBag(edgeIndex); 401 399 } 402 400 -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGGPRInfo.h
r114434 r117542 272 272 static const GPRReg argumentGPR0 = X86Registers::ecx; // regT2 273 273 static const GPRReg argumentGPR1 = X86Registers::edx; // regT1 274 static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0 275 static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3 274 276 static const GPRReg returnValueGPR = X86Registers::eax; // regT0 275 277 static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 … … 341 343 static const GPRReg argumentGPR4 = X86Registers::r8; // regT6 342 344 static const GPRReg argumentGPR5 = X86Registers::r9; // regT7 345 static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0 346 static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3 343 347 static const GPRReg returnValueGPR = X86Registers::eax; // regT0 344 348 static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 … … 411 415 // any change introducing a problem here is likely to be immediately apparent! 412 416 static const GPRReg argumentGPR3 = ARMRegisters::r3; // FIXME! 417 static const GPRReg nonArgGPR0 = X86Registers::r4; // regT3 418 static const GPRReg nonArgGPR1 = X86Registers::r8; // regT4 413 419 static const GPRReg returnValueGPR = ARMRegisters::r0; // regT0 414 420 static const GPRReg returnValueGPR2 = ARMRegisters::r1; // regT1 -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGGraph.cpp
r116912 r117542 403 403 } 404 404 405 void Graph::collectGarbage() 406 { 407 // First reset the counts to 0 for all nodes. 408 for (unsigned i = size(); i--;) 409 at(i).setRefCount(0); 410 411 // Now find the roots: the nodes that are must-generate. Set their ref counts to 412 // 1 and put them on the worklist. 413 Vector<NodeIndex, 128> worklist; 414 for (BlockIndex blockIndex = 0; blockIndex < m_blocks.size(); ++blockIndex) { 415 BasicBlock* block = m_blocks[blockIndex].get(); 416 if (!block) 417 continue; 418 for (unsigned indexInBlock = block->size(); indexInBlock--;) { 419 NodeIndex nodeIndex = block->at(indexInBlock); 420 Node& node = at(nodeIndex); 421 if (!(node.flags() & NodeMustGenerate)) 422 continue; 423 node.setRefCount(1); 424 worklist.append(nodeIndex); 425 } 426 } 427 428 while (!worklist.isEmpty()) { 429 NodeIndex nodeIndex = worklist.last(); 430 worklist.removeLast(); 431 Node& node = at(nodeIndex); 432 ASSERT(node.shouldGenerate()); // It should not be on the worklist unless it's ref'ed. 433 if (node.flags() & NodeHasVarArgs) { 434 for (unsigned childIdx = node.firstChild(); 435 childIdx < node.firstChild() + node.numChildren(); 436 ++childIdx) { 437 NodeIndex childNodeIndex = m_varArgChildren[childIdx].index(); 438 if (!at(childNodeIndex).ref()) 439 continue; 440 worklist.append(childNodeIndex); 441 } 442 } else if (node.child1()) { 443 if (at(node.child1()).ref()) 444 worklist.append(node.child1().index()); 445 if (node.child2()) { 446 if (at(node.child2()).ref()) 447 worklist.append(node.child2().index()); 448 if (node.child3()) { 449 if (at(node.child3()).ref()) 450 worklist.append(node.child3().index()); 451 } 452 } 453 } 454 } 455 } 456 405 457 void Graph::determineReachability() 406 458 { -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGGraph.h
r117370 r117542 162 162 } 163 163 164 // Call this if you've modified the reference counts of nodes that deal with 165 // local variables. This is necessary because local variable references can form 166 // cycles, and hence reference counting is not enough. This will reset the 167 // reference counts according to reachability. 168 void collectGarbage(); 169 164 170 void convertToConstant(NodeIndex nodeIndex, unsigned constantNumber) 165 171 { … … 305 311 } 306 312 313 ExecutableBase* executableFor(InlineCallFrame* inlineCallFrame) 314 { 315 if (!inlineCallFrame) 316 return m_codeBlock->ownerExecutable(); 317 318 return inlineCallFrame->executable.get(); 319 } 320 307 321 ExecutableBase* executableFor(const CodeOrigin& codeOrigin) 308 322 { 323 return executableFor(codeOrigin.inlineCallFrame); 324 } 325 326 CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin) 327 { 328 return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock); 329 } 330 331 int argumentsRegisterFor(const CodeOrigin& codeOrigin) 332 { 309 333 if (!codeOrigin.inlineCallFrame) 310 return m_codeBlock->ownerExecutable(); 311 312 return codeOrigin.inlineCallFrame->executable.get(); 313 } 314 315 CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin) 316 { 317 return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock); 334 return m_codeBlock->argumentsRegister(); 335 336 return baselineCodeBlockForInlineCallFrame( 337 codeOrigin.inlineCallFrame)->argumentsRegister() + 338 codeOrigin.inlineCallFrame->stackOffset; 339 } 340 341 int uncheckedArgumentsRegisterFor(const CodeOrigin& codeOrigin) 342 { 343 if (!codeOrigin.inlineCallFrame) 344 return m_codeBlock->uncheckedArgumentsRegister(); 345 346 CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame( 347 codeOrigin.inlineCallFrame); 348 if (!codeBlock->usesArguments()) 349 return InvalidVirtualRegister; 350 351 return codeBlock->argumentsRegister() + 352 codeOrigin.inlineCallFrame->stackOffset; 318 353 } 319 354 … … 413 448 case GetByVal: 414 449 return !byValIsPure(node); 415 case GetMyArgumentByVal:416 return m_executablesWhoseArgumentsEscaped.contains(417 executableFor(node.codeOrigin));418 450 default: 419 451 ASSERT_NOT_REACHED(); -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGNode.h
r117017 r117542 529 529 case GetByVal: 530 530 case GetMyArgumentByVal: 531 case GetMyArgumentByValSafe: 531 532 case Call: 532 533 case Construct: -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGNodeType.h
r117017 r117542 64 64 macro(GetLocalUnlinked, NodeResultJS) \ 65 65 \ 66 /* Marker for a rguments being set. */\66 /* Marker for an argument being set at the prologue of a function. */\ 67 67 macro(SetArgument, 0) \ 68 68 \ … … 199 199 macro(CreateArguments, NodeResultJS) \ 200 200 macro(TearOffArguments, NodeMustGenerate) \ 201 macro(GetMyArgumentsLength, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ 202 macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \ 201 macro(GetMyArgumentsLength, NodeResultJS | NodeMustGenerate) \ 202 macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate) \ 203 macro(GetMyArgumentsLengthSafe, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ 204 macro(GetMyArgumentByValSafe, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ 203 205 macro(CheckArgumentsNotCreated, NodeMustGenerate) \ 204 206 \ -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
r115694 r117542 73 73 74 74 { 75 AssemblyHelpers jit(globalData, codeBlock);75 CCallHelpers jit(globalData, codeBlock); 76 76 OSRExitCompiler exitCompiler(jit); 77 77 -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h
r113552 r117542 32 32 33 33 #include "DFGAssemblyHelpers.h" 34 #include "DFGCCallHelpers.h" 34 35 #include "DFGOSRExit.h" 35 36 #include "DFGOperations.h" … … 43 44 class OSRExitCompiler { 44 45 public: 45 OSRExitCompiler( AssemblyHelpers& jit)46 OSRExitCompiler(CCallHelpers& jit) 46 47 : m_jit(jit) 47 48 { … … 73 74 void handleExitCounts(const OSRExit&); 74 75 75 AssemblyHelpers& m_jit;76 CCallHelpers& m_jit; 76 77 Vector<unsigned> m_poisonScratchIndices; 77 78 }; -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
r113552 r117542 131 131 bool haveConstants = false; 132 132 bool haveUndefined = false; 133 bool haveArguments = false; 133 134 134 135 for (int index = 0; index < exit.numberOfRecoveries(); ++index) { … … 192 193 if (recovery.constant().isUndefined()) 193 194 haveUndefined = true; 195 break; 196 197 case ArgumentsThatWereNotCreated: 198 haveArguments = true; 194 199 break; 195 200 … … 527 532 } 528 533 529 // 11) Adjust the old JIT's execute counter. Since we are exiting OSR, we know 534 // 11) Create arguments if necessary and place them into the appropriate aliased 535 // registers. 536 537 if (haveArguments) { 538 for (int index = 0; index < exit.numberOfRecoveries(); ++index) { 539 const ValueRecovery& recovery = exit.valueRecovery(index); 540 if (recovery.technique() != ArgumentsThatWereNotCreated) 541 continue; 542 int operand = exit.operandForIndex(index); 543 // Find the right inline call frame. 544 InlineCallFrame* inlineCallFrame = 0; 545 for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; 546 current; 547 current = current->caller.inlineCallFrame) { 548 if (current->stackOffset <= operand) { 549 inlineCallFrame = current; 550 break; 551 } 552 } 553 int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); 554 555 m_jit.load32(AssemblyHelpers::payloadFor(argumentsRegister), GPRInfo::regT0); 556 AssemblyHelpers::Jump haveArguments = m_jit.branch32( 557 AssemblyHelpers::NotEqual, 558 AssemblyHelpers::tagFor(argumentsRegister), 559 AssemblyHelpers::TrustedImm32(JSValue::EmptyValueTag)); 560 561 if (inlineCallFrame) { 562 m_jit.setupArgumentsWithExecState( 563 AssemblyHelpers::TrustedImmPtr(inlineCallFrame)); 564 m_jit.move( 565 AssemblyHelpers::TrustedImmPtr( 566 bitwise_cast<void*>(operationCreateInlinedArguments)), 567 GPRInfo::nonArgGPR0); 568 } else { 569 m_jit.setupArgumentsExecState(); 570 m_jit.move( 571 AssemblyHelpers::TrustedImmPtr( 572 bitwise_cast<void*>(operationCreateArguments)), 573 GPRInfo::nonArgGPR0); 574 } 575 m_jit.call(GPRInfo::nonArgGPR0); 576 m_jit.store32( 577 AssemblyHelpers::TrustedImm32(JSValue::CellTag), 578 AssemblyHelpers::tagFor(argumentsRegister)); 579 m_jit.store32( 580 GPRInfo::returnValueGPR, 581 AssemblyHelpers::payloadFor(argumentsRegister)); 582 m_jit.store32( 583 AssemblyHelpers::TrustedImm32(JSValue::CellTag), 584 AssemblyHelpers::tagFor(unmodifiedArgumentsRegister(argumentsRegister))); 585 m_jit.store32( 586 GPRInfo::returnValueGPR, 587 AssemblyHelpers::payloadFor(unmodifiedArgumentsRegister(argumentsRegister))); 588 m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. 589 590 haveArguments.link(&m_jit); 591 m_jit.store32( 592 AssemblyHelpers::TrustedImm32(JSValue::CellTag), 593 AssemblyHelpers::tagFor(operand)); 594 m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor(operand)); 595 } 596 } 597 598 // 12) Adjust the old JIT's execute counter. Since we are exiting OSR, we know 530 599 // that all new calls into this code will go to the new JIT, so the execute 531 600 // counter only affects call frames that performed OSR exit and call frames … … 565 634 handleExitCounts(exit); 566 635 567 // 1 2) Load the result of the last bytecode operation into regT0.636 // 13) Load the result of the last bytecode operation into regT0. 568 637 569 638 if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) { … … 572 641 } 573 642 574 // 1 3) Fix call frame (s).643 // 14) Fix call frame (s). 575 644 576 645 ASSERT(m_jit.baselineCodeBlock()->getJITType() == JITCode::BaselineJIT); … … 611 680 m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister); 612 681 613 // 1 4) Jump into the corresponding baseline JIT code.682 // 15) Jump into the corresponding baseline JIT code. 614 683 615 684 CodeBlock* baselineCodeBlock = m_jit.baselineCodeBlockFor(exit.m_codeOrigin); -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
r113552 r117542 128 128 bool haveUndefined = false; 129 129 bool haveUInt32s = false; 130 bool haveArguments = false; 130 131 131 132 for (int index = 0; index < exit.numberOfRecoveries(); ++index) { … … 183 184 if (recovery.constant().isUndefined()) 184 185 haveUndefined = true; 186 break; 187 188 case ArgumentsThatWereNotCreated: 189 haveArguments = true; 185 190 break; 186 191 … … 506 511 } 507 512 508 // 13) Adjust the old JIT's execute counter. Since we are exiting OSR, we know 513 // 13) Create arguments if necessary and place them into the appropriate aliased 514 // registers. 515 516 if (haveArguments) { 517 for (int index = 0; index < exit.numberOfRecoveries(); ++index) { 518 const ValueRecovery& recovery = exit.valueRecovery(index); 519 if (recovery.technique() != ArgumentsThatWereNotCreated) 520 continue; 521 int operand = exit.operandForIndex(index); 522 // Find the right inline call frame. 523 InlineCallFrame* inlineCallFrame = 0; 524 for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; 525 current; 526 current = current->caller.inlineCallFrame) { 527 if (current->stackOffset <= operand) { 528 inlineCallFrame = current; 529 break; 530 } 531 } 532 int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); 533 534 m_jit.loadPtr(AssemblyHelpers::addressFor(argumentsRegister), GPRInfo::regT0); 535 AssemblyHelpers::Jump haveArguments = m_jit.branchTestPtr( 536 AssemblyHelpers::NonZero, GPRInfo::regT0); 537 538 if (inlineCallFrame) { 539 m_jit.setupArgumentsWithExecState( 540 AssemblyHelpers::TrustedImmPtr(inlineCallFrame)); 541 m_jit.move( 542 AssemblyHelpers::TrustedImmPtr( 543 bitwise_cast<void*>(operationCreateInlinedArguments)), 544 GPRInfo::nonArgGPR0); 545 } else { 546 m_jit.setupArgumentsExecState(); 547 m_jit.move( 548 AssemblyHelpers::TrustedImmPtr( 549 bitwise_cast<void*>(operationCreateArguments)), 550 GPRInfo::nonArgGPR0); 551 } 552 m_jit.call(GPRInfo::nonArgGPR0); 553 m_jit.storePtr(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(argumentsRegister)); 554 m_jit.storePtr( 555 GPRInfo::returnValueGPR, 556 AssemblyHelpers::addressFor(unmodifiedArgumentsRegister(argumentsRegister))); 557 m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. 558 559 haveArguments.link(&m_jit); 560 m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor(operand)); 561 } 562 } 563 564 // 14) Adjust the old JIT's execute counter. Since we are exiting OSR, we know 509 565 // that all new calls into this code will go to the new JIT, so the execute 510 566 // counter only affects call frames that performed OSR exit and call frames … … 544 600 handleExitCounts(exit); 545 601 546 // 1 4) Load the result of the last bytecode operation into regT0.602 // 15) Load the result of the last bytecode operation into regT0. 547 603 548 604 if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) 549 605 m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); 550 606 551 // 1 5) Fix call frame(s).607 // 16) Fix call frame(s). 552 608 553 609 ASSERT(m_jit.baselineCodeBlock()->getJITType() == JITCode::BaselineJIT); … … 585 641 m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister); 586 642 587 // 1 6) Jump into the corresponding baseline JIT code.643 // 17) Jump into the corresponding baseline JIT code. 588 644 589 645 CodeBlock* baselineCodeBlock = m_jit.baselineCodeBlockFor(exit.m_codeOrigin); -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGOperations.cpp
r116838 r117542 1025 1025 JSCell* DFG_OPERATION operationCreateArguments(ExecState* exec) 1026 1026 { 1027 return Arguments::create(exec->globalData(), exec); 1027 // NB: This needs to be exceedingly careful with top call frame tracking, since it 1028 // may be called from OSR exit, while the state of the call stack is bizarre. 1029 Arguments* result = Arguments::create(exec->globalData(), exec); 1030 ASSERT(!exec->globalData().exception); 1031 return result; 1028 1032 } 1029 1033 … … 1031 1035 ExecState* exec, InlineCallFrame* inlineCallFrame) 1032 1036 { 1033 return Arguments::create(exec->globalData(), exec, inlineCallFrame); 1037 // NB: This needs to be exceedingly careful with top call frame tracking, since it 1038 // may be called from OSR exit, while the state of the call stack is bizarre. 1039 Arguments* result = Arguments::create(exec->globalData(), exec, inlineCallFrame); 1040 ASSERT(!exec->globalData().exception); 1041 return result; 1034 1042 } 1035 1043 -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r117017 r117542 438 438 } 439 439 440 case GetMyArgumentByVal : {440 case GetMyArgumentByValSafe: { 441 441 changed |= mergePrediction(node.getHeapPrediction()); 442 442 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); … … 444 444 } 445 445 446 case GetMyArgumentsLength : {446 case GetMyArgumentsLengthSafe: { 447 447 changed |= setPrediction(PredictInt32); 448 448 break; … … 617 617 case GetStringLength: 618 618 case Int32ToDouble: 619 case GetLocalUnlinked: { 619 case GetLocalUnlinked: 620 case GetMyArgumentsLength: 621 case GetMyArgumentByVal: { 620 622 // This node should never be visible at this stage of compilation. It is 621 623 // inserted by fixup(), which follows this phase. -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r116555 r117542 801 801 case DoubleInRegisterFile: 802 802 fprintf(out, "Double"); 803 break; 804 case ArgumentsSource: 805 fprintf(out, "Arguments"); 803 806 break; 804 807 case HaveNode: … … 987 990 else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat()) 988 991 m_variables[i] = ValueSource(DoubleInRegisterFile); 992 else if (at(nodeIndex).variableAccessData()->isArgumentsAlias()) 993 m_variables[i] = ValueSource(ArgumentsSource); 989 994 else 990 995 m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction()); … … 1346 1351 case DoubleInRegisterFile: 1347 1352 return ValueRecovery::alreadyInRegisterFileAsUnboxedDouble(); 1353 1354 case ArgumentsSource: 1355 return ValueRecovery::argumentsThatWereNotCreated(); 1348 1356 1349 1357 case HaveNode: { 1350 1358 if (isConstant(valueSource.nodeIndex())) 1351 1359 return ValueRecovery::constant(valueOfJSConstant(valueSource.nodeIndex())); 1352 1360 1353 1361 Node* nodePtr = &at(valueSource.nodeIndex()); 1354 1362 if (!nodePtr->shouldGenerate()) { 1363 if (nodePtr->op() == CreateArguments) 1364 return ValueRecovery::argumentsThatWereNotCreated(); 1355 1365 // It's legitimately dead. As in, nobody will ever use this node, or operand, 1356 1366 // ever. Set it to Undefined to make the GC happy after the OSR. -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r116838 r117542 57 57 BooleanInRegisterFile, 58 58 DoubleInRegisterFile, 59 ArgumentsSource, 59 60 HaveNode 60 61 }; -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r117017 r117542 3910 3910 3911 3911 case GetMyArgumentsLength: { 3912 if (!m_jit.graph().m_executablesWhoseArgumentsEscaped.contains( 3913 m_jit.graph().executableFor(node.codeOrigin))) { 3914 GPRTemporary result(this); 3915 GPRReg resultGPR = result.gpr(); 3916 3917 speculationCheck( 3918 ArgumentsEscaped, JSValueRegs(), NoNode, 3919 m_jit.branch32( 3920 JITCompiler::NotEqual, 3921 JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)), 3922 TrustedImm32(JSValue::EmptyValueTag))); 3923 3924 ASSERT(!node.codeOrigin.inlineCallFrame); 3925 m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR); 3926 m_jit.sub32(TrustedImm32(1), resultGPR); 3927 integerResult(resultGPR, m_compileIndex); 3928 break; 3929 } 3930 3912 GPRTemporary result(this); 3913 GPRReg resultGPR = result.gpr(); 3914 3915 speculationCheck( 3916 ArgumentsEscaped, JSValueRegs(), NoNode, 3917 m_jit.branch32( 3918 JITCompiler::NotEqual, 3919 JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)), 3920 TrustedImm32(JSValue::EmptyValueTag))); 3921 3922 ASSERT(!node.codeOrigin.inlineCallFrame); 3923 m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR); 3924 m_jit.sub32(TrustedImm32(1), resultGPR); 3925 integerResult(resultGPR, m_compileIndex); 3926 break; 3927 } 3928 3929 case GetMyArgumentsLengthSafe: { 3931 3930 GPRTemporary resultPayload(this); 3932 3931 GPRTemporary resultTag(this); … … 3971 3970 GPRReg resultTagGPR = resultTag.gpr(); 3972 3971 3973 if (!m_jit.graph().m_executablesWhoseArgumentsEscaped.contains( 3974 m_jit.graph().executableFor(node.codeOrigin))) { 3975 speculationCheck( 3976 ArgumentsEscaped, JSValueRegs(), NoNode, 3977 m_jit.branch32( 3978 JITCompiler::NotEqual, 3979 JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)), 3980 TrustedImm32(JSValue::EmptyValueTag))); 3981 3982 m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR); 3983 3984 if (node.codeOrigin.inlineCallFrame) { 3985 speculationCheck( 3986 Uncountable, JSValueRegs(), NoNode, 3987 m_jit.branch32( 3988 JITCompiler::AboveOrEqual, 3989 resultPayloadGPR, 3990 Imm32(node.codeOrigin.inlineCallFrame->arguments.size()))); 3991 } else { 3992 speculationCheck( 3993 Uncountable, JSValueRegs(), NoNode, 3994 m_jit.branch32( 3995 JITCompiler::AboveOrEqual, 3996 resultPayloadGPR, 3997 JITCompiler::payloadFor(RegisterFile::ArgumentCount))); 3998 } 3999 4000 m_jit.neg32(resultPayloadGPR); 4001 4002 size_t baseOffset = 4003 ((node.codeOrigin.inlineCallFrame 4004 ? node.codeOrigin.inlineCallFrame->stackOffset 4005 : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register); 4006 m_jit.load32( 4007 JITCompiler::BaseIndex( 4008 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, 4009 baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), 4010 resultTagGPR); 4011 m_jit.load32( 4012 JITCompiler::BaseIndex( 4013 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, 4014 baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), 4015 resultPayloadGPR); 4016 4017 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex); 4018 break; 4019 } 4020 4021 JITCompiler::JumpList slowPath; 4022 slowPath.append( 3972 speculationCheck( 3973 ArgumentsEscaped, JSValueRegs(), NoNode, 4023 3974 m_jit.branch32( 4024 3975 JITCompiler::NotEqual, 4025 3976 JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)), 4026 3977 TrustedImm32(JSValue::EmptyValueTag))); 4027 3978 4028 3979 m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR); 3980 4029 3981 if (node.codeOrigin.inlineCallFrame) { 4030 slowPath.append( 3982 speculationCheck( 3983 Uncountable, JSValueRegs(), NoNode, 4031 3984 m_jit.branch32( 4032 3985 JITCompiler::AboveOrEqual, … … 4034 3987 Imm32(node.codeOrigin.inlineCallFrame->arguments.size()))); 4035 3988 } else { 4036 slowPath.append( 3989 speculationCheck( 3990 Uncountable, JSValueRegs(), NoNode, 4037 3991 m_jit.branch32( 4038 3992 JITCompiler::AboveOrEqual, … … 4057 4011 baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), 4058 4012 resultPayloadGPR); 4013 4014 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex); 4015 break; 4016 } 4017 case GetMyArgumentByValSafe: { 4018 SpeculateStrictInt32Operand index(this, node.child1()); 4019 GPRTemporary resultPayload(this); 4020 GPRTemporary resultTag(this); 4021 GPRReg indexGPR = index.gpr(); 4022 GPRReg resultPayloadGPR = resultPayload.gpr(); 4023 GPRReg resultTagGPR = resultTag.gpr(); 4024 4025 JITCompiler::JumpList slowPath; 4026 slowPath.append( 4027 m_jit.branch32( 4028 JITCompiler::NotEqual, 4029 JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)), 4030 TrustedImm32(JSValue::EmptyValueTag))); 4031 4032 m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR); 4033 if (node.codeOrigin.inlineCallFrame) { 4034 slowPath.append( 4035 m_jit.branch32( 4036 JITCompiler::AboveOrEqual, 4037 resultPayloadGPR, 4038 Imm32(node.codeOrigin.inlineCallFrame->arguments.size()))); 4039 } else { 4040 slowPath.append( 4041 m_jit.branch32( 4042 JITCompiler::AboveOrEqual, 4043 resultPayloadGPR, 4044 JITCompiler::payloadFor(RegisterFile::ArgumentCount))); 4045 } 4046 4047 m_jit.neg32(resultPayloadGPR); 4048 4049 size_t baseOffset = 4050 ((node.codeOrigin.inlineCallFrame 4051 ? node.codeOrigin.inlineCallFrame->stackOffset 4052 : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register); 4053 m_jit.load32( 4054 JITCompiler::BaseIndex( 4055 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, 4056 baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), 4057 resultTagGPR); 4058 m_jit.load32( 4059 JITCompiler::BaseIndex( 4060 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, 4061 baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), 4062 resultPayloadGPR); 4059 4063 4060 4064 addSlowPathGenerator( -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r117017 r117542 3891 3891 GPRReg resultGPR = result.gpr(); 3892 3892 3893 if (!m_jit.graph().m_executablesWhoseArgumentsEscaped.contains( 3894 m_jit.graph().executableFor(node.codeOrigin))) { 3895 speculationCheck( 3896 ArgumentsEscaped, JSValueRegs(), NoNode, 3897 m_jit.branchTestPtr( 3898 JITCompiler::NonZero, 3899 JITCompiler::addressFor( 3900 m_jit.argumentsRegisterFor(node.codeOrigin)))); 3901 3902 ASSERT(!node.codeOrigin.inlineCallFrame); 3903 m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR); 3904 m_jit.sub32(TrustedImm32(1), resultGPR); 3905 integerResult(resultGPR, m_compileIndex); 3906 break; 3907 } 3893 speculationCheck( 3894 ArgumentsEscaped, JSValueRegs(), NoNode, 3895 m_jit.branchTestPtr( 3896 JITCompiler::NonZero, 3897 JITCompiler::addressFor( 3898 m_jit.argumentsRegisterFor(node.codeOrigin)))); 3899 3900 ASSERT(!node.codeOrigin.inlineCallFrame); 3901 m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR); 3902 m_jit.sub32(TrustedImm32(1), resultGPR); 3903 integerResult(resultGPR, m_compileIndex); 3904 break; 3905 } 3906 3907 case GetMyArgumentsLengthSafe: { 3908 GPRTemporary result(this); 3909 GPRReg resultGPR = result.gpr(); 3908 3910 3909 3911 JITCompiler::Jump created = m_jit.branchTestPtr( … … 3944 3946 GPRReg resultGPR = result.gpr(); 3945 3947 3946 if (!m_jit.graph().m_executablesWhoseArgumentsEscaped.contains( 3947 m_jit.graph().executableFor(node.codeOrigin))) { 3948 speculationCheck( 3949 ArgumentsEscaped, JSValueRegs(), NoNode, 3950 m_jit.branchTestPtr( 3951 JITCompiler::NonZero, 3952 JITCompiler::addressFor( 3953 m_jit.argumentsRegisterFor(node.codeOrigin)))); 3954 3955 m_jit.add32(TrustedImm32(1), indexGPR, resultGPR); 3956 if (node.codeOrigin.inlineCallFrame) { 3948 3957 speculationCheck( 3949 ArgumentsEscaped, JSValueRegs(), NoNode, 3950 m_jit.branchTestPtr( 3951 JITCompiler::NonZero, 3952 JITCompiler::addressFor( 3953 m_jit.argumentsRegisterFor(node.codeOrigin)))); 3954 3955 m_jit.add32(TrustedImm32(1), indexGPR, resultGPR); 3956 if (node.codeOrigin.inlineCallFrame) { 3957 speculationCheck( 3958 Uncountable, JSValueRegs(), NoNode, 3959 m_jit.branch32( 3960 JITCompiler::AboveOrEqual, 3961 resultGPR, 3962 Imm32(node.codeOrigin.inlineCallFrame->arguments.size()))); 3963 } else { 3964 speculationCheck( 3965 Uncountable, JSValueRegs(), NoNode, 3966 m_jit.branch32( 3967 JITCompiler::AboveOrEqual, 3968 resultGPR, 3969 JITCompiler::payloadFor(RegisterFile::ArgumentCount))); 3970 } 3971 3972 m_jit.neg32(resultGPR); 3973 m_jit.signExtend32ToPtr(resultGPR, resultGPR); 3974 3975 m_jit.loadPtr( 3976 JITCompiler::BaseIndex( 3977 GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, 3978 ((node.codeOrigin.inlineCallFrame 3979 ? node.codeOrigin.inlineCallFrame->stackOffset 3980 : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)), 3981 resultGPR); 3982 3983 jsValueResult(resultGPR, m_compileIndex); 3984 break; 3985 } 3958 Uncountable, JSValueRegs(), NoNode, 3959 m_jit.branch32( 3960 JITCompiler::AboveOrEqual, 3961 resultGPR, 3962 Imm32(node.codeOrigin.inlineCallFrame->arguments.size()))); 3963 } else { 3964 speculationCheck( 3965 Uncountable, JSValueRegs(), NoNode, 3966 m_jit.branch32( 3967 JITCompiler::AboveOrEqual, 3968 resultGPR, 3969 JITCompiler::payloadFor(RegisterFile::ArgumentCount))); 3970 } 3971 3972 m_jit.neg32(resultGPR); 3973 m_jit.signExtend32ToPtr(resultGPR, resultGPR); 3974 3975 m_jit.loadPtr( 3976 JITCompiler::BaseIndex( 3977 GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, 3978 ((node.codeOrigin.inlineCallFrame 3979 ? node.codeOrigin.inlineCallFrame->stackOffset 3980 : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)), 3981 resultGPR); 3982 3983 jsValueResult(resultGPR, m_compileIndex); 3984 break; 3985 } 3986 3987 case GetMyArgumentByValSafe: { 3988 SpeculateStrictInt32Operand index(this, node.child1()); 3989 GPRTemporary result(this); 3990 GPRReg indexGPR = index.gpr(); 3991 GPRReg resultGPR = result.gpr(); 3986 3992 3987 3993 JITCompiler::JumpList slowPath; -
branches/dfgopt/Source/JavaScriptCore/dfg/DFGVariableAccessData.h
r116555 r117542 48 48 , m_flags(0) 49 49 , m_doubleFormatState(EmptyDoubleFormatState) 50 , m_isCaptured(false) 51 , m_isArgumentsAlias(false) 50 52 { 51 53 clearVotes(); … … 59 61 , m_doubleFormatState(EmptyDoubleFormatState) 60 62 , m_isCaptured(isCaptured) 63 , m_isArgumentsAlias(false) 61 64 { 62 65 clearVotes(); … … 86 89 { 87 90 return m_isCaptured; 91 } 92 93 bool mergeIsArgumentsAlias(bool isArgumentsAlias) 94 { 95 bool newIsArgumentsAlias = m_isArgumentsAlias | isArgumentsAlias; 96 if (newIsArgumentsAlias == m_isArgumentsAlias) 97 return false; 98 m_isArgumentsAlias = newIsArgumentsAlias; 99 return true; 100 } 101 102 bool isArgumentsAlias() 103 { 104 return m_isArgumentsAlias; 88 105 } 89 106 … … 238 255 239 256 bool m_isCaptured; 257 bool m_isArgumentsAlias; 240 258 }; 241 259 -
branches/dfgopt/Source/JavaScriptCore/jit/JITOpcodes.cpp
r116467 r117542 1567 1567 stubCall.addArgument(arguments, regT2); 1568 1568 stubCall.addArgument(property, regT2); 1569 stubCall.call (dst);1569 stubCall.callWithValueProfiling(dst); 1570 1570 } 1571 1571
Note:
See TracChangeset
for help on using the changeset viewer.