Changeset 96189 in webkit
- Timestamp:
- Sep 27, 2011 10:33:21 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r96184 r96189 1 2011-09-27 Filip Pizlo <fpizlo@apple.com> 2 3 DFG JIT cannot compile op_new_object, op_new_array, 4 op_new_array_buffer, or op_new_regexp 5 https://bugs.webkit.org/show_bug.cgi?id=68580 6 7 Reviewed by Oliver Hunt. 8 9 This implements all four opcodes, but has op_new_regexp turns off 10 by default because it unveils some bad speculation logic when 11 compiling string-validate-input. 12 13 With op_new_regexp turned off, this is a 5% win on Kraken and a 14 0.7% speed-up on V8. Neutral on SunSpider. 15 16 * dfg/DFGByteCodeParser.cpp: 17 (JSC::DFG::ByteCodeParser::parseBlock): 18 * dfg/DFGCapabilities.h: 19 (JSC::DFG::canCompileOpcode): 20 * dfg/DFGJITCodeGenerator.h: 21 (JSC::DFG::callOperation): 22 * dfg/DFGNode.h: 23 (JSC::DFG::Node::hasConstantBuffer): 24 (JSC::DFG::Node::startConstant): 25 (JSC::DFG::Node::numConstants): 26 (JSC::DFG::Node::hasRegexpIndex): 27 (JSC::DFG::Node::regexpIndex): 28 * dfg/DFGOperations.cpp: 29 * dfg/DFGOperations.h: 30 * dfg/DFGPropagator.cpp: 31 (JSC::DFG::Propagator::propagateNodePredictions): 32 * dfg/DFGSpeculativeJIT.cpp: 33 (JSC::DFG::SpeculativeJIT::emitAllocateJSFinalObject): 34 (JSC::DFG::SpeculativeJIT::compile): 35 * dfg/DFGSpeculativeJIT.h: 36 (JSC::DFG::SpeculativeJIT::isKnownArray): 37 1 38 2011-09-27 Filip Pizlo <fpizlo@apple.com> 2 39 -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r95930 r96189 723 723 set(currentInstruction[1].u.operand, addToGraph(CreateThis, op1)); 724 724 NEXT_OPCODE(op_create_this); 725 } 726 727 case op_new_object: { 728 set(currentInstruction[1].u.operand, addToGraph(NewObject)); 729 NEXT_OPCODE(op_new_object); 730 } 731 732 case op_new_array: { 733 int startOperand = currentInstruction[2].u.operand; 734 int numOperands = currentInstruction[3].u.operand; 735 for (int operandIdx = startOperand; operandIdx < startOperand + numOperands; ++operandIdx) 736 addVarArgChild(get(operandIdx)); 737 set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0))); 738 NEXT_OPCODE(op_new_array); 739 } 740 741 case op_new_array_buffer: { 742 int startConstant = currentInstruction[2].u.operand; 743 int numConstants = currentInstruction[3].u.operand; 744 set(currentInstruction[1].u.operand, addToGraph(NewArrayBuffer, OpInfo(startConstant), OpInfo(numConstants))); 745 NEXT_OPCODE(op_new_array_buffer); 746 } 747 748 case op_new_regexp: { 749 set(currentInstruction[1].u.operand, addToGraph(NewRegexp, OpInfo(currentInstruction[2].u.operand))); 750 NEXT_OPCODE(op_new_regexp); 725 751 } 726 752 … … 1402 1428 1403 1429 default: 1404 // Parse failed! 1405 ASSERT(!canCompileOpcode(opcodeID)); 1430 // Parse failed! This should not happen because the capabilities checker 1431 // should have caught it. 1432 ASSERT_NOT_REACHED(); 1406 1433 return false; 1407 1434 } -
trunk/Source/JavaScriptCore/dfg/DFGCapabilities.h
r95932 r96189 31 31 32 32 namespace JSC { namespace DFG { 33 34 #define ENABLE_DFG_RESTRICTIONS 1 33 35 34 36 #if ENABLE(DFG_JIT) … … 120 122 case op_resolve_base: 121 123 case op_resolve_global: 124 case op_new_object: 125 case op_new_array: 126 case op_new_array_buffer: 122 127 case op_strcat: 123 128 case op_to_primitive: … … 125 130 case op_throw_reference_error: 126 131 return true; 132 133 // Opcodes we support conditionally. Enabling these opcodes currently results in 134 // performance regressions. Each node that we disable under restrictions has a 135 // comment describing what we know about the regression so far. 136 137 // Regresses string-validate-input, probably because it uses comparisons (< and >) 138 // on strings, which currently will cause speculation failures in some cases. 139 case op_new_regexp: 140 #if ENABLE(DFG_RESTRICTIONS) 141 return false; 142 #else 143 return true; 144 #endif 145 127 146 default: 128 147 return false; -
trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h
r96175 r96189 1069 1069 m_jit.move(GPRInfo::returnValueGPR, result); 1070 1070 } 1071 void callOperation(J_DFGOperation_ESS operation, GPRReg result, int startConstant, int numConstants) 1072 { 1073 ASSERT(isFlushed()); 1074 1075 m_jit.move(JITCompiler::TrustedImm32(numConstants), GPRInfo::argumentGPR2); 1076 m_jit.move(JITCompiler::TrustedImm32(startConstant), GPRInfo::argumentGPR1); 1077 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 1078 1079 appendCallWithExceptionCheck(operation); 1080 m_jit.move(GPRInfo::returnValueGPR, result); 1081 } 1071 1082 void callOperation(J_DFGOperation_EJP operation, GPRReg result, GPRReg arg1, void* pointer) 1072 1083 { -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r96184 r96189 288 288 macro(Construct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \ 289 289 \ 290 /* Allocations. */\ 291 macro(NewObject, NodeResultJS) \ 292 macro(NewArray, NodeResultJS | NodeHasVarArgs) \ 293 macro(NewArrayBuffer, NodeResultJS) \ 294 macro(NewRegexp, NodeResultJS) \ 295 \ 290 296 /* Resolve nodes. */\ 291 297 macro(Resolve, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ … … 561 567 } 562 568 569 bool hasConstantBuffer() 570 { 571 return op == NewArrayBuffer; 572 } 573 574 unsigned startConstant() 575 { 576 ASSERT(hasConstantBuffer()); 577 return m_opInfo; 578 } 579 580 unsigned numConstants() 581 { 582 ASSERT(hasConstantBuffer()); 583 return m_opInfo2; 584 } 585 586 bool hasRegexpIndex() 587 { 588 return op == NewRegexp; 589 } 590 591 unsigned regexpIndex() 592 { 593 ASSERT(hasRegexpIndex()); 594 return m_opInfo; 595 } 596 563 597 bool hasVarNumber() 564 598 { -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r96175 r96189 158 158 } 159 159 160 EncodedJSValue operationNewObject(ExecState* exec) 161 { 162 return JSValue::encode(constructEmptyObject(exec)); 163 } 164 160 165 EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 161 166 { … … 791 796 } 792 797 798 EncodedJSValue operationNewArray(ExecState* exec, void* start, size_t size) 799 { 800 ArgList argList(static_cast<Register*>(start), size); 801 return JSValue::encode(constructArray(exec, argList)); 802 } 803 804 EncodedJSValue operationNewArrayBuffer(ExecState* exec, size_t start, size_t size) 805 { 806 ArgList argList(exec->codeBlock()->constantBuffer(start), size); 807 return JSValue::encode(constructArray(exec, argList)); 808 } 809 810 EncodedJSValue operationNewRegexp(ExecState* exec, void* regexpPtr) 811 { 812 RegExp* regexp = static_cast<RegExp*>(regexpPtr); 813 if (!regexp->isValid()) { 814 throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); 815 return JSValue::encode(jsUndefined()); 816 } 817 818 return RegExpObject::create(exec->globalData(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp); 819 } 820 793 821 void operationThrowHasInstanceError(ExecState* exec, EncodedJSValue encodedBase) 794 822 { -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r95901 r96189 51 51 typedef EncodedJSValue (*J_DFGOperation_EP)(ExecState*, void*); 52 52 typedef EncodedJSValue (*J_DFGOperation_EPS)(ExecState*, void*, size_t); 53 typedef EncodedJSValue (*J_DFGOperation_ESS)(ExecState*, size_t, size_t); 53 54 typedef EncodedJSValue (*J_DFGOperation_EI)(ExecState*, Identifier*); 54 55 typedef RegisterSizedBoolean (*Z_DFGOperation_EJ)(ExecState*, EncodedJSValue); … … 63 64 EncodedJSValue operationConvertThis(ExecState*, EncodedJSValue encodedOp1); 64 65 EncodedJSValue operationCreateThis(ExecState*, EncodedJSValue encodedOp1); 66 EncodedJSValue operationNewObject(ExecState*); 65 67 EncodedJSValue operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); 66 68 EncodedJSValue operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); … … 83 85 EncodedJSValue operationToPrimitive(ExecState*, EncodedJSValue); 84 86 EncodedJSValue operationStrCat(ExecState*, void* start, size_t); 87 EncodedJSValue operationNewArray(ExecState*, void* start, size_t); 88 EncodedJSValue operationNewArrayBuffer(ExecState*, size_t, size_t); 89 EncodedJSValue operationNewRegexp(ExecState*, void*); 85 90 void operationThrowHasInstanceError(ExecState*, EncodedJSValue base); 86 91 void operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue); -
trunk/Source/JavaScriptCore/dfg/DFGPropagator.cpp
r96184 r96189 510 510 } 511 511 512 case CreateThis: { 512 case CreateThis: 513 case NewObject: { 513 514 changed |= setPrediction(PredictFinalObject); 515 break; 516 } 517 518 case NewArray: 519 case NewArrayBuffer: { 520 changed |= setPrediction(PredictArray); 521 break; 522 } 523 524 case NewRegexp: { 525 changed |= setPrediction(PredictObjectOther); 514 526 break; 515 527 } … … 539 551 break; 540 552 } 541 553 542 554 case ValueToDouble: 543 555 case GetArrayLength: { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r96184 r96189 686 686 } 687 687 688 template<typename T> 689 void SpeculativeJIT::emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath) 690 { 691 MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject)); 692 693 m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR); 694 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR)); 695 696 // The object is half-allocated: we have what we know is a fresh object, but 697 // it's still on the GC's free list. 698 699 // Ditch the structure by placing it into the structure slot, so that we can reuse 700 // scratchGPR. 701 m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset())); 702 703 // Now that we have scratchGPR back, remove the object from the free list 704 m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR); 705 m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell); 706 707 // Initialize the object's vtable 708 m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR)); 709 710 // Initialize the object's inheritorID. 711 m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID())); 712 713 // Initialize the object's property storage pointer. 714 m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR); 715 m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage())); 716 } 717 688 718 void SpeculativeJIT::compile(Node& node) 689 719 { … … 1387 1417 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). 1388 1418 // If we have predicted the base to be type array, we can skip the check. 1389 Node& baseNode = m_jit.graph()[node.child1()]; 1390 if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local()))) 1419 if (!isKnownArray(node.child1())) 1391 1420 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 1392 1421 speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); … … 1422 1451 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). 1423 1452 // If we have predicted the base to be type array, we can skip the check. 1424 Node& baseNode = m_jit.graph()[node.child1()]; 1425 if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local()))) 1453 if (!isKnownArray(node.child1())) 1426 1454 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 1427 1455 … … 1638 1666 } 1639 1667 1640 case StrCat: { 1641 // We really don't want to grow the register file just to do a StrCat. Say we 1642 // have 50 functions on the stack that all have a StrCat in them that has 1668 case StrCat: 1669 case NewArray: { 1670 // We really don't want to grow the register file just to do a StrCat or NewArray. 1671 // Say we have 50 functions on the stack that all have a StrCat in them that has 1643 1672 // upwards of 10 operands. In the DFG this would mean that each one gets 1644 1673 // some random virtual register, and then to do the StrCat we'd need a second … … 1670 1699 GPRResult result(this); 1671 1700 1672 callOperation(operationStrCat, result.gpr(), buffer, node.numChildren()); 1673 1674 jsValueResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly); 1675 break; 1676 } 1677 1701 callOperation(op == StrCat ? operationStrCat : operationNewArray, result.gpr(), buffer, node.numChildren()); 1702 1703 cellResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly); 1704 break; 1705 } 1706 1707 case NewArrayBuffer: { 1708 flushRegisters(); 1709 GPRResult result(this); 1710 1711 callOperation(operationNewArrayBuffer, result.gpr(), node.startConstant(), node.numConstants()); 1712 1713 cellResult(result.gpr(), m_compileIndex); 1714 break; 1715 } 1716 1717 case NewRegexp: { 1718 flushRegisters(); 1719 GPRResult result(this); 1720 1721 callOperation(operationNewRegexp, result.gpr(), m_jit.codeBlock()->regexp(node.regexpIndex())); 1722 1723 cellResult(result.gpr(), m_compileIndex); 1724 break; 1725 } 1726 1678 1727 case ConvertThis: { 1679 1728 SpeculateCellOperand thisValue(this, node.child1()); … … 1719 1768 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR)); 1720 1769 1721 MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject)); 1722 1723 m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR); 1724 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR)); 1725 1726 // The object is half-allocated: we have what we know is a fresh object, but 1727 // it's still on the GC's free list. 1728 1729 // Ditch the inheritorID by placing it into the structure, so that we can reuse 1730 // scratchGPR. 1731 m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSObject::structureOffset())); 1732 1733 // Now that we have scratchGPR back, remove the object from the free list 1734 m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR); 1735 m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell); 1736 1737 // Initialize the object's vtable 1738 m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR)); 1739 1740 // Initialize the object's inheritorID. 1741 m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID())); 1742 1743 // Initialize the object's property storage pointer. 1744 m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR); 1745 m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage())); 1770 emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath); 1746 1771 1747 1772 MacroAssembler::Jump done = m_jit.jump(); … … 1759 1784 1760 1785 cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly); 1786 break; 1787 } 1788 1789 case NewObject: { 1790 GPRTemporary result(this); 1791 GPRTemporary scratch(this); 1792 1793 GPRReg resultGPR = result.gpr(); 1794 GPRReg scratchGPR = scratch.gpr(); 1795 1796 MacroAssembler::JumpList slowPath; 1797 1798 emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()->emptyObjectStructure()), resultGPR, scratchGPR, slowPath); 1799 1800 MacroAssembler::Jump done = m_jit.jump(); 1801 1802 slowPath.link(&m_jit); 1803 1804 silentSpillAllRegisters(resultGPR); 1805 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 1806 appendCallWithExceptionCheck(operationNewObject); 1807 m_jit.move(GPRInfo::returnValueGPR, resultGPR); 1808 silentFillAllRegisters(resultGPR); 1809 1810 done.link(&m_jit); 1811 1812 cellResult(resultGPR, m_compileIndex); 1761 1813 break; 1762 1814 } … … 1834 1886 1835 1887 case GetArrayLength: { 1836 Node& baseNode = m_jit.graph()[node.child1()];1837 1888 SpeculateCellOperand base(this, node.child1()); 1838 1889 GPRTemporary result(this); … … 1841 1892 GPRReg resultGPR = result.gpr(); 1842 1893 1843 if ( baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))1894 if (!isKnownArray(node.child1())) 1844 1895 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 1845 1896 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r95930 r96189 513 513 } 514 514 515 bool isKnownArray(NodeIndex op1) 516 { 517 Node& node = m_jit.graph()[op1]; 518 switch (node.op) { 519 case GetLocal: 520 return isArrayPrediction(m_jit.graph().getPrediction(node.local())); 521 522 case NewArray: 523 case NewArrayBuffer: 524 return true; 525 526 default: 527 return false; 528 } 529 } 530 515 531 bool compare(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, Z_DFGOperation_EJJ); 516 532 void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition); … … 518 534 void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, void* vptr); 519 535 void compileObjectEquality(Node&, void* vptr); 536 537 // It is acceptable to have structure be equal to scratch, so long as you're fine 538 // with the structure GPR being clobbered. 539 template<typename T> 540 void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath); 520 541 521 542 #if USE(JSVALUE64)
Note: See TracChangeset
for help on using the changeset viewer.