Changeset 84860 in webkit
- Timestamp:
- Apr 25, 2011 6:40:25 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r84855 r84860 1 2011-04-25 Gavin Barraclough <barraclough@apple.com> 2 3 Reviewed by Geoff Garen. 4 5 https://bugs.webkit.org/show_bug.cgi?id=59405 6 DFG JIT - add type speculation for integer & array types, for vars & args. 7 8 If a var or argument is used as the base for a GetByVal or PutByVal access 9 we are speculating that it is of type Array (we only generate code on the 10 speculative path to perform array accesses). By typing the var or args slot 11 as Array, and checking on entry to the function (in the case of args), and 12 each time the local is written to, we can avoid a type check at each point 13 the array is accessed. This will typically hoist type checks out of loops. 14 15 Similarly, any local that is incremented or decremented, or is the input or 16 output or a bitwise operator, is likely to be an integer. By typing the 17 local as int32 we can avoid speculation checks on access, and tagging when 18 writing to the slot. All accesses can become 32bit instead of 64. 19 20 * dfg/DFGByteCodeParser.cpp: 21 (JSC::DFG::ByteCodeParser::set): 22 (JSC::DFG::ByteCodeParser::predictArray): 23 (JSC::DFG::ByteCodeParser::predictInt32): 24 (JSC::DFG::ByteCodeParser::parseBlock): 25 * dfg/DFGGraph.h: 26 (JSC::DFG::PredictionSlot::PredictionSlot): 27 (JSC::DFG::Graph::Graph): 28 (JSC::DFG::Graph::predict): 29 (JSC::DFG::Graph::getPrediction): 30 * dfg/DFGJITCompiler.cpp: 31 (JSC::DFG::JITCompiler::compileFunction): 32 * dfg/DFGJITCompiler.h: 33 (JSC::DFG::JITCompiler::tagFor): 34 (JSC::DFG::JITCompiler::payloadFor): 35 * dfg/DFGNode.h: 36 * dfg/DFGNonSpeculativeJIT.cpp: 37 (JSC::DFG::NonSpeculativeJIT::compile): 38 * dfg/DFGSpeculativeJIT.cpp: 39 (JSC::DFG::SpeculativeJIT::compile): 40 (JSC::DFG::SpeculativeJIT::checkArgumentTypes): 41 (JSC::DFG::SpeculativeJIT::initializeVariableTypes): 42 * dfg/DFGSpeculativeJIT.h: 43 * runtime/Executable.cpp: 44 (JSC::tryDFGCompile): 45 1 46 2011-04-25 David Levin <levin@chromium.org> 2 47 -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r84846 r84860 92 92 93 93 // Is this an argument? 94 if (operand < 0)94 if (operandIsArgument(operand)) 95 95 return getArgument(operand); 96 96 … … 98 98 return getLocal((unsigned)operand); 99 99 } 100 void set(int operand, NodeIndex value) 101 { 100 void set(int operand, NodeIndex value, PredictedType prediction = PredictNone) 101 { 102 m_graph.predict(operand, prediction); 103 102 104 // Is this an argument? 103 if (operand < 0) {105 if (operandIsArgument(operand)) { 104 106 setArgument(operand, value); 105 107 return; … … 441 443 } 442 444 445 void predictArray(NodeIndex nodeIndex) 446 { 447 Node* nodePtr = &m_graph[nodeIndex]; 448 449 if (nodePtr->op == GetLocal) 450 m_graph.predict(nodePtr->local(), PredictArray); 451 } 452 453 void predictInt32(NodeIndex nodeIndex) 454 { 455 Node* nodePtr = &m_graph[nodeIndex]; 456 457 if (nodePtr->op == ValueToNumber) 458 nodePtr = &m_graph[nodePtr->child1]; 459 460 if (nodePtr->op == ValueToInt32) 461 nodePtr = &m_graph[nodePtr->child1]; 462 463 if (nodePtr->op == NumberToInt32) 464 nodePtr = &m_graph[nodePtr->child1]; 465 466 if (nodePtr->op == GetLocal) 467 m_graph.predict(nodePtr->local(), PredictInt32); 468 } 469 443 470 JSGlobalData* m_globalData; 444 471 CodeBlock* m_codeBlock; … … 561 588 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand); 562 589 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand); 563 set(currentInstruction[1].u.operand, addToGraph(BitAnd, op1, op2)); 590 predictInt32(op1); 591 predictInt32(op2); 592 set(currentInstruction[1].u.operand, addToGraph(BitAnd, op1, op2), PredictInt32); 564 593 NEXT_OPCODE(op_bitand); 565 594 } … … 568 597 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand); 569 598 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand); 570 set(currentInstruction[1].u.operand, addToGraph(BitOr, op1, op2)); 599 predictInt32(op1); 600 predictInt32(op2); 601 set(currentInstruction[1].u.operand, addToGraph(BitOr, op1, op2), PredictInt32); 571 602 NEXT_OPCODE(op_bitor); 572 603 } … … 575 606 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand); 576 607 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand); 577 set(currentInstruction[1].u.operand, addToGraph(BitXor, op1, op2)); 608 predictInt32(op1); 609 predictInt32(op2); 610 set(currentInstruction[1].u.operand, addToGraph(BitXor, op1, op2), PredictInt32); 578 611 NEXT_OPCODE(op_bitxor); 579 612 } … … 582 615 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand); 583 616 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand); 617 predictInt32(op1); 618 predictInt32(op2); 584 619 NodeIndex result; 585 620 // Optimize out shifts by zero. … … 588 623 else 589 624 result = addToGraph(BitRShift, op1, op2); 590 set(currentInstruction[1].u.operand, result );625 set(currentInstruction[1].u.operand, result, PredictInt32); 591 626 NEXT_OPCODE(op_rshift); 592 627 } … … 595 630 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand); 596 631 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand); 632 predictInt32(op1); 633 predictInt32(op2); 597 634 NodeIndex result; 598 635 // Optimize out shifts by zero. … … 601 638 else 602 639 result = addToGraph(BitLShift, op1, op2); 603 set(currentInstruction[1].u.operand, result );640 set(currentInstruction[1].u.operand, result, PredictInt32); 604 641 NEXT_OPCODE(op_lshift); 605 642 } … … 608 645 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand); 609 646 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand); 647 predictInt32(op1); 648 predictInt32(op2); 610 649 NodeIndex result; 611 650 // The result of a zero-extending right shift is treated as an unsigned value. … … 628 667 result = addToGraph(UInt32ToNumber, result); 629 668 } 630 set(currentInstruction[1].u.operand, result );669 set(currentInstruction[1].u.operand, result, PredictInt32); 631 670 NEXT_OPCODE(op_urshift); 632 671 } … … 637 676 unsigned srcDst = currentInstruction[1].u.operand; 638 677 NodeIndex op = getToNumber(srcDst); 678 predictInt32(op); 639 679 set(srcDst, addToGraph(ArithAdd, op, one())); 640 680 NEXT_OPCODE(op_pre_inc); … … 645 685 unsigned srcDst = currentInstruction[2].u.operand; 646 686 NodeIndex op = getToNumber(srcDst); 687 predictInt32(op); 647 688 set(result, op); 648 689 set(srcDst, addToGraph(ArithAdd, op, one())); … … 653 694 unsigned srcDst = currentInstruction[1].u.operand; 654 695 NodeIndex op = getToNumber(srcDst); 696 predictInt32(op); 655 697 set(srcDst, addToGraph(ArithSub, op, one())); 656 698 NEXT_OPCODE(op_pre_dec); … … 661 703 unsigned srcDst = currentInstruction[2].u.operand; 662 704 NodeIndex op = getToNumber(srcDst); 705 predictInt32(op); 663 706 set(result, op); 664 707 set(srcDst, addToGraph(ArithSub, op, one())); … … 795 838 NodeIndex base = get(currentInstruction[2].u.operand); 796 839 NodeIndex property = get(currentInstruction[3].u.operand); 840 predictArray(base); 841 predictInt32(property); 797 842 798 843 NodeIndex getByVal = addToGraph(GetByVal, base, property, aliases.lookupGetByVal(base, property)); … … 807 852 NodeIndex property = get(currentInstruction[2].u.operand); 808 853 NodeIndex value = get(currentInstruction[3].u.operand); 854 predictArray(base); 855 predictInt32(property); 809 856 810 857 NodeIndex aliasedGet = aliases.lookupGetByVal(base, property); -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r84744 r84860 98 98 if (node.hasLocal()) { 99 99 int local = node.local(); 100 if ( local < 0)100 if (operandIsArgument(local)) 101 101 printf("%sarg%u", hasPrinted ? ", " : "", local - codeBlock->thisRegister()); 102 102 else -
trunk/Source/JavaScriptCore/dfg/DFGGraph.h
r84748 r84860 29 29 #if ENABLE(DFG_JIT) 30 30 31 #include <RegisterFile.h> 31 32 #include <dfg/DFGNode.h> 32 33 #include <wtf/Vector.h> … … 38 39 39 40 namespace DFG { 41 42 // helper function to distinguish vars & temporaries from arguments. 43 inline bool operandIsArgument(int operand) { return operand < 0; } 44 45 typedef uint8_t PredictedType; 46 static const PredictedType PredictNone = 0; 47 static const PredictedType PredictCell = 0x01; 48 static const PredictedType PredictArray = 0x03; 49 static const PredictedType PredictInt32 = 0x04; 50 51 struct PredictionSlot { 52 public: 53 PredictionSlot() 54 : m_value(PredictNone) 55 { 56 } 57 PredictedType m_value; 58 }; 40 59 41 60 typedef uint32_t BlockIndex; … … 87 106 class Graph : public Vector<Node, 64> { 88 107 public: 108 Graph(unsigned numArguments, unsigned numVariables) 109 : m_argumentPredictions(numArguments) 110 , m_variablePredictions(numVariables) 111 { 112 } 113 89 114 // Mark a node as being referenced. 90 115 void ref(NodeIndex nodeIndex) … … 102 127 #endif 103 128 104 Vector< OwnPtr<BasicBlock> , 8> m_blocks;105 106 129 BlockIndex blockIndexForBytecodeOffset(unsigned bytecodeBegin) 107 130 { … … 117 140 } 118 141 142 void predict(int operand, PredictedType prediction) 143 { 144 if (operandIsArgument(operand)) { 145 unsigned argument = operand + m_argumentPredictions.size() + RegisterFile::CallFrameHeaderSize; 146 m_argumentPredictions[argument].m_value |= prediction; 147 } else if ((unsigned)operand < m_variablePredictions.size()) 148 m_variablePredictions[operand].m_value |= prediction; 149 150 } 151 152 PredictedType getPrediction(int operand) 153 { 154 if (operandIsArgument(operand)) { 155 unsigned argument = operand + m_argumentPredictions.size() + RegisterFile::CallFrameHeaderSize; 156 return m_argumentPredictions[argument].m_value; 157 } 158 if ((unsigned)operand < m_variablePredictions.size()) 159 return m_variablePredictions[operand].m_value; 160 return PredictNone; 161 } 162 163 Vector< OwnPtr<BasicBlock> , 8> m_blocks; 119 164 private: 165 120 166 // When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa. 121 167 void refChildren(NodeIndex); 168 169 Vector<PredictionSlot, 16> m_argumentPredictions; 170 Vector<PredictionSlot, 16> m_variablePredictions; 122 171 }; 123 172 -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r84675 r84860 265 265 Label speculativePathBegin = label(); 266 266 SpeculativeJIT speculative(*this); 267 #if !DFG_DEBUG_LOCAL_DISBALE_SPECULATIVE 267 268 bool compiledSpeculative = speculative.compile(); 269 #else 270 bool compiledSpeculative = false; 271 #endif 268 272 269 273 // Next, generate the non-speculative path. We pass this a SpeculationCheckIndexIterator -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h
r84462 r84860 206 206 #endif 207 207 208 Address addressForArgument(int32_t argument)209 {210 return Address(callFrameRegister, (argument - (m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize)) * sizeof(Register));211 }212 213 208 static Address addressForGlobalVar(RegisterID global, int32_t varNumber) 214 209 { … … 219 214 { 220 215 return Address(callFrameRegister, virtualRegister * sizeof(Register)); 216 } 217 218 static Address tagFor(VirtualRegister virtualRegister) 219 { 220 return Address(callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); 221 } 222 223 static Address payloadFor(VirtualRegister virtualRegister) 224 { 225 return Address(callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); 221 226 } 222 227 -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r84744 r84860 41 41 // Disable the DFG JIT without having to touch Platform.h! 42 42 #define DFG_DEBUG_LOCAL_DISBALE 0 43 // Disable the SpeculativeJIT without having to touch Platform.h! 44 #define DFG_DEBUG_LOCAL_DISBALE_SPECULATIVE 0 43 45 // Generate stats on how successful we were in making use of the DFG jit, and remaining on the hot path. 44 46 #define DFG_SUCCESS_STATS 0 -
trunk/Source/JavaScriptCore/dfg/DFGNonSpeculativeJIT.cpp
r84744 r84860 174 174 void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, Node& node) 175 175 { 176 // ... 177 if (checkIterator.hasCheckAtIndex(m_compileIndex)) 176 // Check for speculation checks from the corresponding instruction in the 177 // speculative path. Do not check for NodeIndex 0, since this is checked 178 // in the outermost compile layer, at the head of the non-speculative path 179 // (for index 0 we may need to check regardless of whether or not the node 180 // will be generated, since argument type speculation checks will appear 181 // as speculation checks at this index). 182 if (m_compileIndex && checkIterator.hasCheckAtIndex(m_compileIndex)) 178 183 trackEntry(m_jit.label()); 179 184 … … 202 207 m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.registerID()); 203 208 204 // jsValueResult, but don't useChildren! 209 // Like jsValueResult, but don't useChildren - our children are phi nodes, 210 // and don't represent values within this dataflow with virtual registers. 205 211 VirtualRegister virtualRegister = node.virtualRegister(); 206 212 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS); … … 684 690 void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator) 685 691 { 692 // Check for speculation checks added at function entry (checking argument types). 693 if (checkIterator.hasCheckAtIndex(m_compileIndex)) 694 trackEntry(m_jit.label()); 695 686 696 ASSERT(!m_compileIndex); 687 697 for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block) -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r84744 r84860 286 286 case GetLocal: { 287 287 GPRTemporary result(this); 288 m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.registerID()); 289 290 // jsValueResult, but don't useChildren! 291 VirtualRegister virtualRegister = node.virtualRegister(); 292 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS); 293 m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), DataFormatJS); 288 PredictedType prediction = m_jit.graph().getPrediction(node.local()); 289 if (prediction == PredictInt32) { 290 m_jit.load32(JITCompiler::payloadFor(node.local()), result.registerID()); 291 292 // Like integerResult, but don't useChildren - our children are phi nodes, 293 // and don't represent values within this dataflow with virtual registers. 294 VirtualRegister virtualRegister = node.virtualRegister(); 295 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger); 296 m_generationInfo[virtualRegister].initInteger(m_compileIndex, node.refCount(), result.gpr()); 297 } else { 298 m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.registerID()); 299 300 // Like jsValueResult, but don't useChildren - our children are phi nodes, 301 // and don't represent values within this dataflow with virtual registers. 302 VirtualRegister virtualRegister = node.virtualRegister(); 303 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS); 304 m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), (prediction == PredictArray) ? DataFormatJSCell : DataFormatJS); 305 } 294 306 break; 295 307 } 296 308 297 309 case SetLocal: { 298 JSValueOperand value(this, node.child1); 299 m_jit.storePtr(value.registerID(), JITCompiler::addressFor(node.local())); 300 noResult(m_compileIndex); 310 switch (m_jit.graph().getPrediction(node.local())) { 311 case PredictInt32: { 312 SpeculateIntegerOperand value(this, node.child1); 313 m_jit.store32(value.registerID(), JITCompiler::payloadFor(node.local())); 314 noResult(m_compileIndex); 315 break; 316 } 317 case PredictArray: { 318 SpeculateCellOperand cell(this, node.child1); 319 m_jit.storePtr(cell.registerID(), JITCompiler::addressFor(node.local())); 320 noResult(m_compileIndex); 321 break; 322 } 323 324 default: { 325 JSValueOperand value(this, node.child1); 326 m_jit.storePtr(value.registerID(), JITCompiler::addressFor(node.local())); 327 noResult(m_compileIndex); 328 break; 329 } 330 } 301 331 break; 302 332 } … … 631 661 632 662 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). 633 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 663 // If we have predicted the base to be type array, we can skip the check. 664 Node& baseNode = m_jit.graph()[node.child1]; 665 if (baseNode.op != GetLocal || m_jit.graph().getPrediction(baseNode.local()) != PredictArray) 666 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 634 667 speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); 635 668 … … 658 691 659 692 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). 660 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 693 // If we have predicted the base to be type array, we can skip the check. 694 Node& baseNode = m_jit.graph()[node.child1]; 695 if (baseNode.op != GetLocal || m_jit.graph().getPrediction(baseNode.local()) != PredictArray) 696 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 661 697 speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); 662 698 … … 869 905 } 870 906 907 // If we are making type predictions about our arguments then 908 // we need to check that they are correct on function entry. 909 void SpeculativeJIT::checkArgumentTypes() 910 { 911 ASSERT(!m_compileIndex); 912 for (int i = 0; i < m_jit.codeBlock()->m_numParameters; ++i) { 913 VirtualRegister virtualRegister = (VirtualRegister)(m_jit.codeBlock()->thisRegister() + i); 914 if (m_jit.graph().getPrediction(virtualRegister) == PredictInt32) 915 switch (m_jit.graph().getPrediction(virtualRegister)) { 916 case PredictInt32: 917 speculationCheck(m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), JITCompiler::tagTypeNumberRegister)); 918 break; 919 920 case PredictArray: { 921 GPRTemporary temp(this); 922 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.registerID()); 923 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, temp.registerID(), JITCompiler::tagMaskRegister)); 924 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.registerID()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 925 break; 926 } 927 928 default: 929 break; 930 } 931 } 932 } 933 934 // For any vars that we will be treating as numeric, write 0 to 935 // the var on entry. Throughout the block we will only read/write 936 // to the payload, by writing the tag now we prevent the GC from 937 // misinterpreting values as pointers. 938 void SpeculativeJIT::initializeVariableTypes() 939 { 940 ASSERT(!m_compileIndex); 941 for (int var = 0; var < m_jit.codeBlock()->m_numVars; ++var) { 942 if (m_jit.graph().getPrediction(var) == PredictInt32) 943 m_jit.storePtr(JITCompiler::tagTypeNumberRegister, JITCompiler::addressFor((VirtualRegister)var)); 944 } 945 } 946 871 947 bool SpeculativeJIT::compile() 872 948 { 949 checkArgumentTypes(); 950 initializeVariableTypes(); 951 873 952 ASSERT(!m_compileIndex); 874 953 for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block) { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r84705 r84860 136 136 void compile(BasicBlock&); 137 137 138 void checkArgumentTypes(); 139 void initializeVariableTypes(); 140 138 141 bool isDoubleConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out) 139 142 { -
trunk/Source/JavaScriptCore/runtime/Executable.cpp
r84556 r84860 205 205 #endif 206 206 207 DFG::Graph dfg ;207 DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars); 208 208 if (!parse(dfg, globalData, codeBlock)) 209 209 return false;
Note: See TracChangeset
for help on using the changeset viewer.