Changeset 190370 in webkit
- Timestamp:
- Sep 30, 2015 3:28:08 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 8 added
- 34 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r190368 r190370 1 2015-09-30 Michael Saboff <msaboff@apple.com> 2 3 Relanding r190289 after fixes tracked in https://bugs.webkit.org/show_bug.cgi?id=149619 4 and https://bugs.webkit.org/show_bug.cgi?id=149621 5 6 Reviewed by Saam Barati. 7 1 8 2015-09-29 Simon Fraser <simon.fraser@apple.com> 2 9 -
trunk/LayoutTests/js/caller-property-expected.txt
r190329 r190370 11 11 PASS strictCaller(nonStrictCallee) threw exception TypeError: Function.caller used to retrieve strict caller. 12 12 PASS strictCaller(strictCallee) threw exception TypeError: Type error. 13 PASS strictTailCaller(nonStrictCallee) is null 14 PASS strictTailCaller(strictCallee) threw exception TypeError: Type error. 13 15 PASS nonStrictCaller(boundNonStrictCallee) is nonStrictCaller 14 16 PASS nonStrictCaller(boundStrictCallee) threw exception TypeError: Type error. 15 17 PASS strictCaller(boundNonStrictCallee) threw exception TypeError: Function.caller used to retrieve strict caller. 16 18 PASS strictCaller(boundStrictCallee) threw exception TypeError: Type error. 19 PASS strictTailCaller(boundNonStrictCallee) is null 20 PASS strictTailCaller(boundStrictCallee) threw exception TypeError: Type error. 17 21 PASS nonStrictGetter(nonStrictAccessor) is nonStrictGetter 18 22 PASS nonStrictSetter(nonStrictAccessor) is true -
trunk/LayoutTests/js/script-tests/caller-property.js
r190329 r190370 24 24 function strictCallee() { "use strict"; return strictCallee.caller; } 25 25 function nonStrictCaller(x) { return x(); } 26 function strictCaller(x) { "use strict"; return x(); } 26 // Tail calls leak and show our caller's caller, which is null here 27 function strictCaller(x) { "use strict"; var result = x(); return result; } 28 function strictTailCaller(x) { "use strict"; return x(); } 27 29 shouldBe("nonStrictCaller(nonStrictCallee)", "nonStrictCaller"); 28 30 shouldThrow("nonStrictCaller(strictCallee)", '"TypeError: Type error"'); 29 31 shouldThrow("strictCaller(nonStrictCallee)", '"TypeError: Function.caller used to retrieve strict caller"'); 30 32 shouldThrow("strictCaller(strictCallee)", '"TypeError: Type error"'); 33 shouldBe("strictTailCaller(nonStrictCallee)", "null"); 34 shouldThrow("strictTailCaller(strictCallee)", '"TypeError: Type error"'); 31 35 32 36 // .caller within a bound function reaches the caller, ignoring the binding. … … 37 41 shouldThrow("strictCaller(boundNonStrictCallee)", '"TypeError: Function.caller used to retrieve strict caller"'); 38 42 shouldThrow("strictCaller(boundStrictCallee)", '"TypeError: Type error"'); 43 shouldBe("strictTailCaller(boundNonStrictCallee)", "null"); 44 shouldThrow("strictTailCaller(boundStrictCallee)", '"TypeError: Type error"'); 39 45 40 46 // Check that .caller works (or throws) as expected, over an accessor call. -
trunk/Source/JavaScriptCore/CMakeLists.txt
r190367 r190370 905 905 ftl/FTLJSCallBase.cpp 906 906 ftl/FTLJSCallVarargs.cpp 907 ftl/FTLJSTailCall.cpp 907 908 ftl/FTLLink.cpp 908 909 ftl/FTLLocation.cpp -
trunk/Source/JavaScriptCore/ChangeLog
r190367 r190370 1 2015-09-30 Michael Saboff <msaboff@apple.com> 2 3 Relanding r190289 with the following two fixes: 4 5 1. REGRESSION(r190289): It made Speedometer/Full.html performance test fail 6 https://bugs.webkit.org/show_bug.cgi?id=149621 7 8 Reviewed by Saam Barati. 9 10 We need to restore callee saves for both the fast and slow paths before making a 11 tail call in the FTL. 12 13 * ftl/FTLJSCallBase.cpp: 14 (JSC::FTL::JSCallBase::emit): 15 16 2. [ARM] REGRESSION(r190289): It made 374 tests crash on 32 bit ARM Linux 17 https://bugs.webkit.org/show_bug.cgi?id=149619 18 19 Reviewed by Filip Pizlo. 20 21 Need to check for ARMv7_TRADITIONAL and ARMv7 in addition to ARM in "if" 22 statement to handle platforms with a link register. 23 24 * llint/LowLevelInterpreter.asm: 25 (prepareForTailCall): 26 1 27 2015-09-30 Keith Miller <keith_miller@apple.com> 2 28 -
trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
r190367 r190370 540 540 <ClCompile Include="..\ftl\FTLJSCallBase.cpp" /> 541 541 <ClCompile Include="..\ftl\FTLJSCallVarargs.cpp" /> 542 <ClCompile Include="..\ftl\FTLJSTailCall.cpp" /> 542 543 <ClCompile Include="..\ftl\FTLLink.cpp" /> 543 544 <ClCompile Include="..\ftl\FTLLocation.cpp" /> … … 1301 1302 <ClInclude Include="..\ftl\FTLJSCallBase.h" /> 1302 1303 <ClInclude Include="..\ftl\FTLJSCallVarargs.h" /> 1304 <ClInclude Include="..\ftl\FTLJSTailCall.h" /> 1303 1305 <ClInclude Include="..\ftl\FTLLink.h" /> 1304 1306 <ClInclude Include="..\ftl\FTLLocation.h" /> -
trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
r190367 r190370 1585 1585 <Filter>ftl</Filter> 1586 1586 </ClCompile> 1587 <ClCompile Include="..\ftl\FTLJSTailCall.cpp"> 1588 <Filter>ftl</Filter> 1589 </ClCompile> 1587 1590 <ClCompile Include="..\ftl\FTLLink.cpp"> 1588 1591 <Filter>ftl</Filter> … … 4152 4155 </ClInclude> 4153 4156 <ClInclude Include="..\ftl\FTLJSCall.h"> 4157 <Filter>ftl</Filter> 4158 </ClInclude> 4159 <ClInclude Include="..\ftl\FTLJSTailCall.h"> 4154 4160 <Filter>ftl</Filter> 4155 4161 </ClInclude> -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r190367 r190370 981 981 627673231B680C1E00FD9F2E /* CallMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 627673211B680C1E00FD9F2E /* CallMode.cpp */; }; 982 982 627673241B680C1E00FD9F2E /* CallMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 627673221B680C1E00FD9F2E /* CallMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 983 62774DAA1B8D4B190006F05A /* FTLJSTailCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62774DA81B8D4B190006F05A /* FTLJSTailCall.cpp */; }; 984 62774DAB1B8D4B190006F05A /* FTLJSTailCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 62774DA91B8D4B190006F05A /* FTLJSTailCall.h */; }; 983 985 62D2D38F1ADF103F000206C1 /* FunctionRareData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */; }; 984 986 62D2D3901ADF103F000206C1 /* FunctionRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = 62D2D38E1ADF103F000206C1 /* FunctionRareData.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 2805 2807 627673211B680C1E00FD9F2E /* CallMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallMode.cpp; sourceTree = "<group>"; }; 2806 2808 627673221B680C1E00FD9F2E /* CallMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallMode.h; sourceTree = "<group>"; }; 2809 62774DA81B8D4B190006F05A /* FTLJSTailCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLJSTailCall.cpp; path = ftl/FTLJSTailCall.cpp; sourceTree = "<group>"; }; 2810 62774DA91B8D4B190006F05A /* FTLJSTailCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLJSTailCall.h; path = ftl/FTLJSTailCall.h; sourceTree = "<group>"; }; 2807 2811 62A9A29E1B0BED4800BD54CA /* DFGLazyNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLazyNode.cpp; path = dfg/DFGLazyNode.cpp; sourceTree = "<group>"; }; 2808 2812 62A9A29F1B0BED4800BD54CA /* DFGLazyNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLazyNode.h; path = dfg/DFGLazyNode.h; sourceTree = "<group>"; }; … … 3983 3987 0FD120311A8C85BD000F5280 /* FTLJSCallVarargs.cpp */, 3984 3988 0FD120321A8C85BD000F5280 /* FTLJSCallVarargs.h */, 3989 62774DA81B8D4B190006F05A /* FTLJSTailCall.cpp */, 3990 62774DA91B8D4B190006F05A /* FTLJSTailCall.h */, 3985 3991 0F8F2B93172E049E007DBDA5 /* FTLLink.cpp */, 3986 3992 0F8F2B94172E049E007DBDA5 /* FTLLink.h */, … … 6331 6337 0FD120301A8AED12000F5280 /* FTLJSCallBase.h in Headers */, 6332 6338 0FD120341A8C85BD000F5280 /* FTLJSCallVarargs.h in Headers */, 6339 62774DAB1B8D4B190006F05A /* FTLJSTailCall.h in Headers */, 6333 6340 0F8F2B96172E04A3007DBDA5 /* FTLLink.h in Headers */, 6334 6341 0FCEFAE0180738C000472CE4 /* FTLLocation.h in Headers */, … … 7703 7710 0FD1202F1A8AED12000F5280 /* FTLJSCallBase.cpp in Sources */, 7704 7711 0FD120331A8C85BD000F5280 /* FTLJSCallVarargs.cpp in Sources */, 7712 62774DAA1B8D4B190006F05A /* FTLJSTailCall.cpp in Sources */, 7705 7713 0F8F2B95172E04A0007DBDA5 /* FTLLink.cpp in Sources */, 7706 7714 0FCEFADF180738C000472CE4 /* FTLLocation.cpp in Sources */, -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r190329 r190370 1883 1883 m_exitOK = true; 1884 1884 processSetLocalQueue(); // This only comes into play for intrinsics, since normal inlined code will leave an empty queue. 1885 addToGraph(Jump); 1885 if (Node* terminal = m_currentBlock->terminal()) 1886 ASSERT_UNUSED(terminal, terminal->op() == TailCall || terminal->op() == TailCallVarargs); 1887 else { 1888 addToGraph(Jump); 1889 landingBlocks.append(m_currentBlock); 1890 } 1886 1891 if (verbose) 1887 1892 dataLog("Marking ", RawPointer(m_currentBlock), " as linked (tail of poly inlinee)\n"); 1888 1893 m_currentBlock->didLink(); 1889 landingBlocks.append(m_currentBlock);1890 1894 1891 1895 if (verbose) … … 1920 1924 m_exitOK = true; // Origin changed, so it's fine to exit again. 1921 1925 processSetLocalQueue(); 1922 addToGraph(Jump); 1923 landingBlocks.append(m_currentBlock); 1926 if (Node* terminal = m_currentBlock->terminal()) 1927 ASSERT_UNUSED(terminal, terminal->op() == TailCall || terminal->op() == TailCallVarargs); 1928 else { 1929 addToGraph(Jump); 1930 landingBlocks.append(m_currentBlock); 1931 } 1924 1932 1925 1933 RefPtr<BasicBlock> continuationBlock = adoptRef( … … 3665 3673 Node* terminal = m_currentBlock->terminal(); 3666 3674 ASSERT_UNUSED(terminal, terminal->op() == TailCall || terminal->op() == TailCallVarargs); 3667 LAST_OPCODE(op_ ret);3675 LAST_OPCODE(op_jmp); 3668 3676 } 3669 3677 int relativeOffset = currentInstruction[1].u.operand; -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r190329 r190370 1036 1036 case ThrowReferenceError: 1037 1037 write(SideState); 1038 read(HeapObjectCount);1039 write(HeapObjectCount);1040 1038 return; 1041 1039 -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r190329 r190370 1117 1117 return false; 1118 1118 } 1119 } 1120 1121 bool isFunctionTerminal() 1122 { 1123 if (isTerminal() && !numSuccessors()) 1124 return true; 1125 1126 return false; 1119 1127 } 1120 1128 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r190329 r190370 772 772 callee.use(); 773 773 774 shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister; 774 775 shuffleData.numLocals = m_jit.graph().frameRegisterCount(); 775 776 shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatJS); … … 869 870 } 870 871 871 callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR);872 callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR); 872 873 m_jit.addJSCall(fastCall, slowCall, targetToCheck, callLinkInfo); 873 874 } -
trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp
r190329 r190370 96 96 97 97 NodeAndIndex terminal = block->findTerminal(); 98 if (terminal.node-> op() == Return) {98 if (terminal.node->isFunctionTerminal()) { 99 99 insertionSet.insertNode( 100 100 terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node->origin); -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r190329 r190370 131 131 case StoreBarrier: 132 132 case Call: 133 case TailCall: 134 case TailCallInlinedCaller: 133 135 case Construct: 134 136 case CallVarargs: 137 case TailCallVarargs: 138 case TailCallVarargsInlinedCaller: 139 case ConstructVarargs: 135 140 case CallForwardVarargs: 136 case ConstructVarargs: 141 case TailCallForwardVarargs: 142 case TailCallForwardVarargsInlinedCaller: 137 143 case ConstructForwardVarargs: 138 144 case LoadVarargs: -
trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp
r190329 r190370 619 619 }); 620 620 } 621 622 adjustCallICsForStackmaps(state.jsTailCalls, recordMap); 623 624 for (unsigned i = state.jsTailCalls.size(); i--;) { 625 JSTailCall& call = state.jsTailCalls[i]; 626 627 CCallHelpers fastPathJIT(&vm, codeBlock); 628 call.emit(*state.jitCode.get(), fastPathJIT); 629 630 char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset; 631 size_t sizeOfIC = call.estimatedSize(); 632 633 generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "tail call inline cache", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) { 634 call.link(vm, linkBuffer); 635 }); 636 } 621 637 622 638 auto iter = recordMap.find(state.handleStackOverflowExceptionStackmapID); -
trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp
r190329 r190370 83 83 } 84 84 85 size_t sizeOfTailCallVarargs() 86 { 87 #if CPU(ARM64) 88 return 188 + sizeOfCallVarargs(); 89 #else 90 return 151 + sizeOfCallVarargs(); 91 #endif 92 } 93 85 94 size_t sizeOfCallForwardVarargs() 86 95 { … … 89 98 #else 90 99 return 262; 100 #endif 101 } 102 103 size_t sizeOfTailCallForwardVarargs() 104 { 105 #if CPU(ARM64) 106 return 188 + sizeOfCallForwardVarargs(); 107 #else 108 return 151 + sizeOfCallForwardVarargs(); 91 109 #endif 92 110 } … … 122 140 return sizeOfCall(); 123 141 case CallVarargs: 142 case TailCallVarargsInlinedCaller: 124 143 return sizeOfCallVarargs(); 144 case TailCallVarargs: 145 return sizeOfTailCallVarargs(); 125 146 case CallForwardVarargs: 147 case TailCallForwardVarargsInlinedCaller: 126 148 return sizeOfCallForwardVarargs(); 149 case TailCallForwardVarargs: 150 return sizeOfTailCallForwardVarargs(); 127 151 case ConstructVarargs: 128 152 return sizeOfConstructVarargs(); … … 132 156 return sizeOfIn(); 133 157 default: 134 return 0;158 RELEASE_ASSERT_NOT_REACHED(); 135 159 } 136 160 } -
trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h
r190329 r190370 41 41 size_t sizeOfCall(); 42 42 size_t sizeOfCallVarargs(); 43 size_t sizeOfTailCallVarargs(); 43 44 size_t sizeOfCallForwardVarargs(); 45 size_t sizeOfTailCallForwardVarargs(); 44 46 size_t sizeOfConstructVarargs(); 45 47 size_t sizeOfConstructForwardVarargs(); -
trunk/Source/JavaScriptCore/ftl/FTLJSCall.cpp
r190329 r190370 49 49 , m_instructionOffset(0) 50 50 { 51 ASSERT(node->op() == Call || node->op() == Construct );51 ASSERT(node->op() == Call || node->op() == Construct || node->op() == TailCallInlinedCaller); 52 52 } 53 53 -
trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp
r190329 r190370 53 53 m_callLinkInfo = jit.codeBlock()->addCallLinkInfo(); 54 54 55 if (CallLinkInfo::callModeFor(m_type) == CallMode::Tail) 56 jit.emitRestoreCalleeSaves(); 57 55 58 CCallHelpers::Jump slowPath = jit.branchPtrWithPatch( 56 59 CCallHelpers::NotEqual, GPRInfo::regT0, m_targetToCheck, 57 60 CCallHelpers::TrustedImmPtr(0)); 58 59 m_fastCall = jit.nearCall(); 60 CCallHelpers::Jump done = jit.jump(); 61 61 62 CCallHelpers::Jump done; 63 64 if (CallLinkInfo::callModeFor(m_type) == CallMode::Tail) { 65 jit.prepareForTailCallSlow(); 66 m_fastCall = jit.nearTailCall(); 67 } else { 68 m_fastCall = jit.nearCall(); 69 done = jit.jump(); 70 } 71 62 72 slowPath.link(&jit); 63 73 64 74 jit.move(CCallHelpers::TrustedImmPtr(m_callLinkInfo), GPRInfo::regT2); 65 75 m_slowCall = jit.nearCall(); 66 67 done.link(&jit); 76 77 if (CallLinkInfo::callModeFor(m_type) == CallMode::Tail) 78 jit.abortWithReason(JITDidReturnFromTailCall); 79 else 80 done.link(&jit); 81 82 m_callLinkInfo->setUpCall(m_type, m_origin, GPRInfo::regT0); 68 83 } 69 84 … … 73 88 m_slowCall, FunctionPtr(vm.getCTIStub(linkCallThunkGenerator).code().executableAddress())); 74 89 75 m_callLinkInfo->setUpCallFromFTL(m_type, m_origin, linkBuffer.locationOfNearCall(m_slowCall), 76 linkBuffer.locationOf(m_targetToCheck), linkBuffer.locationOfNearCall(m_fastCall), 77 GPRInfo::regT0); 90 m_callLinkInfo->setCallLocations(linkBuffer.locationOfNearCall(m_slowCall), 91 linkBuffer.locationOf(m_targetToCheck), linkBuffer.locationOfNearCall(m_fastCall)); 78 92 } 79 93 -
trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.h
r190329 r190370 51 51 void link(VM&, LinkBuffer&); 52 52 53 pr ivate:53 protected: 54 54 CallLinkInfo::CallType m_type; 55 55 CodeOrigin m_origin; -
trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp
r190329 r190370 52 52 , m_callBase( 53 53 (node->op() == ConstructVarargs || node->op() == ConstructForwardVarargs) 54 ? CallLinkInfo::ConstructVarargs : CallLinkInfo::CallVarargs, 54 ? CallLinkInfo::ConstructVarargs : (node->op() == TailCallVarargs || node->op() == TailCallForwardVarargs) 55 ? CallLinkInfo::TailCallVarargs : CallLinkInfo::CallVarargs, 55 56 node->origin.semantic) 56 57 , m_instructionOffset(0) … … 58 59 ASSERT( 59 60 node->op() == CallVarargs || node->op() == CallForwardVarargs 61 || node->op() == TailCallVarargsInlinedCaller || node->op() == TailCallForwardVarargsInlinedCaller 62 || node->op() == TailCallVarargs || node->op() == TailCallForwardVarargs 60 63 || node->op() == ConstructVarargs || node->op() == ConstructForwardVarargs); 61 64 } … … 84 87 switch (m_node->op()) { 85 88 case CallVarargs: 89 case TailCallVarargs: 90 case TailCallVarargsInlinedCaller: 86 91 case ConstructVarargs: 87 92 argumentsGPR = GPRInfo::argumentGPR1; … … 89 94 break; 90 95 case CallForwardVarargs: 96 case TailCallForwardVarargs: 97 case TailCallForwardVarargsInlinedCaller: 91 98 case ConstructForwardVarargs: 92 99 thisGPR = GPRInfo::argumentGPR1; … … 197 204 // stack frame to already be set up, which it is. 198 205 jit.store64(GPRInfo::regT0, CCallHelpers::calleeFrameSlot(JSStack::Callee)); 199 206 200 207 m_callBase.emit(jit); 201 208 -
trunk/Source/JavaScriptCore/ftl/FTLLocation.h
r190329 r190370 121 121 } 122 122 123 bool operator!() const { return kind() == Unprocessed && !u.variable.offset; } 123 explicit operator bool() const { return kind() != Unprocessed || u.variable.offset; } 124 125 bool operator!() const { return !static_cast<bool>(*this); } 124 126 125 127 bool isHashTableDeletedValue() const { return kind() == Unprocessed && u.variable.offset; } -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
r190329 r190370 174 174 switch (node->op()) { 175 175 case CallVarargs: 176 case TailCallVarargs: 177 case TailCallVarargsInlinedCaller: 176 178 case CallForwardVarargs: 179 case TailCallForwardVarargs: 180 case TailCallForwardVarargsInlinedCaller: 177 181 case ConstructVarargs: 178 182 case ConstructForwardVarargs: … … 724 728 break; 725 729 case Call: 730 case TailCallInlinedCaller: 726 731 case Construct: 727 732 compileCallOrConstruct(); 728 733 break; 734 case TailCall: 735 compileTailCall(); 736 break; 729 737 case CallVarargs: 730 738 case CallForwardVarargs: 739 case TailCallVarargs: 740 case TailCallVarargsInlinedCaller: 741 case TailCallForwardVarargs: 742 case TailCallForwardVarargsInlinedCaller: 731 743 case ConstructVarargs: 732 744 case ConstructForwardVarargs: … … 4401 4413 setJSValue(call); 4402 4414 } 4415 4416 void compileTailCall() 4417 { 4418 int numArgs = m_node->numChildren() - 1; 4419 ExitArgumentList exitArguments; 4420 exitArguments.reserveCapacity(numArgs + 6); 4421 4422 unsigned stackmapID = m_stackmapIDs++; 4423 exitArguments.append(lowJSValue(m_graph.varArgChild(m_node, 0))); 4424 exitArguments.append(m_tagTypeNumber); 4425 4426 Vector<ExitValue> callArguments(numArgs); 4427 4428 bool needsTagTypeNumber { false }; 4429 for (int i = 0; i < numArgs; ++i) { 4430 callArguments[i] = 4431 exitValueForTailCall(exitArguments, m_graph.varArgChild(m_node, 1 + i).node()); 4432 if (callArguments[i].dataFormat() == DataFormatInt32) 4433 needsTagTypeNumber = true; 4434 } 4435 4436 JSTailCall tailCall(stackmapID, m_node, WTF::move(callArguments)); 4437 4438 exitArguments.insert(0, m_out.constInt32(needsTagTypeNumber ? 2 : 1)); 4439 exitArguments.insert(0, constNull(m_out.ref8)); 4440 exitArguments.insert(0, m_out.constInt32(tailCall.estimatedSize())); 4441 exitArguments.insert(0, m_out.constInt64(stackmapID)); 4442 4443 LValue call = 4444 m_out.call(m_out.patchpointVoidIntrinsic(), exitArguments); 4445 setInstructionCallingConvention(call, LLVMAnyRegCallConv); 4446 m_out.unreachable(); 4447 4448 m_ftlState.jsTailCalls.append(tailCall); 4449 } 4403 4450 4404 4451 void compileCallOrConstructVarargs() … … 4411 4458 switch (m_node->op()) { 4412 4459 case CallVarargs: 4460 case TailCallVarargs: 4461 case TailCallVarargsInlinedCaller: 4413 4462 case ConstructVarargs: 4414 4463 jsArguments = lowJSValue(m_node->child2()); 4415 4464 break; 4416 4465 case CallForwardVarargs: 4466 case TailCallForwardVarargs: 4467 case TailCallForwardVarargsInlinedCaller: 4417 4468 case ConstructForwardVarargs: 4418 4469 break; … … 4441 4492 4442 4493 m_ftlState.jsCallVarargses.append(JSCallVarargs(stackmapID, m_node)); 4443 4444 setJSValue(call); 4494 4495 switch (m_node->op()) { 4496 case TailCallVarargs: 4497 case TailCallForwardVarargs: 4498 m_out.unreachable(); 4499 break; 4500 4501 default: 4502 setJSValue(call); 4503 } 4445 4504 } 4446 4505 … … 8257 8316 void callPreflight() 8258 8317 { 8259 callPreflight(m_node->origin.semantic); 8318 CodeOrigin codeOrigin = m_node->origin.semantic; 8319 8320 if (m_node->op() == TailCallInlinedCaller 8321 || m_node->op() == TailCallVarargsInlinedCaller 8322 || m_node->op() == TailCallForwardVarargsInlinedCaller) 8323 codeOrigin =*codeOrigin.inlineCallFrame->getCallerSkippingDeadFrames(); 8324 8325 callPreflight(codeOrigin); 8260 8326 } 8261 8327 … … 8528 8594 return ExitValue::dead(); 8529 8595 } 8530 8596 8531 8597 ExitValue exitArgument(ExitArgumentList& arguments, DataFormat format, LValue value) 8532 8598 { … … 8534 8600 arguments.append(value); 8535 8601 return result; 8602 } 8603 8604 ExitValue exitValueForTailCall(ExitArgumentList& arguments, Node* node) 8605 { 8606 ASSERT(node->shouldGenerate()); 8607 ASSERT(node->hasResult()); 8608 8609 switch (node->op()) { 8610 case JSConstant: 8611 case Int52Constant: 8612 case DoubleConstant: 8613 return ExitValue::constant(node->asJSValue()); 8614 8615 default: 8616 break; 8617 } 8618 8619 LoweredNodeValue value = m_jsValueValues.get(node); 8620 if (isValid(value)) 8621 return exitArgument(arguments, DataFormatJS, value.value()); 8622 8623 value = m_int32Values.get(node); 8624 if (isValid(value)) 8625 return exitArgument(arguments, DataFormatInt32, value.value()); 8626 8627 value = m_booleanValues.get(node); 8628 if (isValid(value)) { 8629 LValue valueToPass = m_out.zeroExt(value.value(), m_out.int32); 8630 return exitArgument(arguments, DataFormatBoolean, valueToPass); 8631 } 8632 8633 // Doubles and Int52 have been converted by ValueRep() 8634 DFG_CRASH(m_graph, m_node, toCString("Cannot find value for node: ", node).data()); 8536 8635 } 8537 8636 -
trunk/Source/JavaScriptCore/ftl/FTLState.h
r190329 r190370 38 38 #include "FTLJSCall.h" 39 39 #include "FTLJSCallVarargs.h" 40 #include "FTLJSTailCall.h" 40 41 #include "FTLStackMaps.h" 41 42 #include "FTLState.h" … … 80 81 Vector<JSCall> jsCalls; 81 82 Vector<JSCallVarargs> jsCallVarargses; 83 Vector<JSTailCall> jsTailCalls; 82 84 Vector<CString> codeSectionNames; 83 85 Vector<CString> dataSectionNames; -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
r190329 r190370 339 339 if (width == NormalJumpWidth) 340 340 return result; 341 341 342 342 PatchableJump realJump = patchableJump(); 343 343 result.link(this); -
trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h
r190329 r190370 40 40 #if USE(JSVALUE64) 41 41 RegisterMap<ValueRecovery> registers; 42 GPRReg tagTypeNumber { InvalidGPRReg }; 42 43 43 44 void setupCalleeSaveRegisters(CodeBlock*); -
trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp
r190329 r190370 72 72 addNew(reg.fpr(), data.registers[reg]); 73 73 } 74 75 m_tagTypeNumber = data.tagTypeNumber; 76 if (m_tagTypeNumber != InvalidGPRReg) 77 lockGPR(m_tagTypeNumber); 74 78 #endif 75 79 } … … 81 85 static const char* dangerBoundsDelimiter = " XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX "; 82 86 static const char* emptySpace = " "; 83 ASSERT(m_alignedNewFrameSize <= numLocals());84 87 out.print(" "); 85 88 out.print(" Old frame "); 86 89 out.print(" New frame "); 87 90 out.print("\n"); 88 for (int i = 0; i < m_alignedOldFrameSize + numLocals() + 3; ++i) { 91 int totalSize = m_alignedOldFrameSize + std::max(numLocals(), m_alignedNewFrameSize) + 3; 92 for (int i = 0; i < totalSize; ++i) { 89 93 VirtualRegister old { m_alignedOldFrameSize - i - 1 }; 90 94 VirtualRegister newReg { old + m_frameDelta }; … … 205 209 if (m_newFrameOffset) 206 210 out.print(" New frame offset is ", m_newFrameOffset, "\n"); 211 #if USE(JSVALUE64) 212 if (m_tagTypeNumber != InvalidGPRReg) 213 out.print(" TagTypeNumber is currently in ", m_tagTypeNumber, "\n"); 214 #endif 207 215 } 208 216 … … 248 256 249 257 VirtualRegister spillSlot { 0 }; 250 for (VirtualRegister slot = firstOld(); slot <= lastOld(); slot -= 1) { 251 ASSERT(slot < newAsOld(firstNew())); 258 for (VirtualRegister slot = firstOld(); slot <= lastOld(); slot += 1) { 259 if (slot >= newAsOld(firstNew())) 260 break; 261 252 262 if (getOld(slot)) 253 263 continue; … … 256 266 break; 257 267 } 258 // We must have enough slots to be able to fit the whole 259 // callee's frame for the slow path. 260 RELEASE_ASSERT(spillSlot.isLocal()); 268 // We must have enough slots to be able to fit the whole callee's 269 // frame for the slow path - unless we are in the FTL. In that 270 // case, we are allowed to extend the frame *once*, since we are 271 // guaranteed to have enough available space for that. 272 if (spillSlot >= newAsOld(firstNew()) || !spillSlot.isLocal()) { 273 RELEASE_ASSERT(!m_didExtendFrame); 274 extendFrameIfNeeded(); 275 spill(cachedRecovery); 276 return; 277 } 261 278 262 279 if (verbose) … … 287 304 } 288 305 306 void CallFrameShuffler::extendFrameIfNeeded() 307 { 308 ASSERT(!m_didExtendFrame); 309 ASSERT(!isUndecided()); 310 311 VirtualRegister firstRead { firstOld() }; 312 for (; firstRead <= virtualRegisterForLocal(0); firstRead += 1) { 313 if (getOld(firstRead)) 314 break; 315 } 316 size_t availableSize = static_cast<size_t>(firstRead.offset() - firstOld().offset()); 317 size_t wantedSize = m_newFrame.size() + m_newFrameOffset; 318 319 if (availableSize < wantedSize) { 320 size_t delta = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), wantedSize - availableSize); 321 m_oldFrame.grow(m_oldFrame.size() + delta); 322 for (size_t i = 0; i < delta; ++i) 323 m_oldFrame[m_oldFrame.size() - i - 1] = nullptr; 324 m_jit.subPtr(MacroAssembler::TrustedImm32(delta * sizeof(Register)), MacroAssembler::stackPointerRegister); 325 326 if (isSlowPath()) 327 m_frameDelta = numLocals() + JSStack::CallerFrameAndPCSize; 328 else 329 m_oldFrameOffset = numLocals(); 330 331 if (verbose) 332 dataLogF(" Not enough space - extending the old frame %zu slot\n", delta); 333 } 334 335 m_didExtendFrame = true; 336 } 337 289 338 void CallFrameShuffler::prepareForSlowPath() 290 339 { … … 297 346 298 347 if (verbose) 299 dataLog("\n\nPreparing frame for slow path call:\n", *this); 348 dataLog("\n\nPreparing frame for slow path call:\n"); 349 350 // When coming from the FTL, we need to extend the frame. In other 351 // cases, we may end up extending the frame if we previously 352 // spilled things (e.g. in polymorphic cache). 353 extendFrameIfNeeded(); 354 355 if (verbose) 356 dataLog(*this); 300 357 301 358 prepareAny(); … … 647 704 } 648 705 706 #if USE(JSVALUE64) 707 if (m_tagTypeNumber != InvalidGPRReg && m_newRegisters[m_tagTypeNumber]) 708 releaseGPR(m_tagTypeNumber); 709 #endif 710 649 711 // Handle 2) by loading all registers. We don't have to do any 650 712 // writes, since they have been taken care of above. … … 660 722 ASSERT(cachedRecovery->targets().isEmpty()); 661 723 } 724 725 #if USE(JSVALUE64) 726 if (m_tagTypeNumber != InvalidGPRReg) 727 releaseGPR(m_tagTypeNumber); 728 #endif 662 729 663 730 // At this point, we have read everything we cared about from the -
trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h
r190329 r190370 72 72 } 73 73 m_lockedRegisters.clear(gpr); 74 } 75 76 void restoreGPR(GPRReg gpr) 77 { 78 if (!m_newRegisters[gpr]) 79 return; 80 81 ensureGPR(); 82 #if USE(JSVALUE32_64) 83 GPRReg tempGPR { getFreeGPR() }; 84 lockGPR(tempGPR); 85 ensureGPR(); 86 releaseGPR(tempGPR); 87 #endif 88 emitDisplace(*m_newRegisters[gpr]); 74 89 } 75 90 … … 310 325 } 311 326 327 bool m_didExtendFrame { false }; 328 329 void extendFrameIfNeeded(); 330 312 331 // This stores, for each slot in the new frame, information about 313 332 // the recovery for the value that should eventually go into that … … 386 405 // ensure that we have at least 2 available registers for loading 387 406 // a pair on 32bits. 388 RegisterSet m_lockedRegisters;407 mutable RegisterSet m_lockedRegisters; 389 408 390 409 // This stores the current recoveries present in registers. A null … … 392 411 // care about it. 393 412 RegisterMap<CachedRecovery*> m_registers; 413 414 #if USE(JSVALUE64) 415 mutable GPRReg m_tagTypeNumber; 416 417 bool tryAcquireTagTypeNumber(); 418 #endif 394 419 395 420 // This stores, for each register, information about the recovery … … 422 447 } 423 448 } 449 450 #if USE(JSVALUE64) 451 if (!nonTemp && m_tagTypeNumber != InvalidGPRReg && check(Reg { m_tagTypeNumber })) { 452 ASSERT(m_lockedRegisters.get(m_tagTypeNumber)); 453 m_lockedRegisters.clear(m_tagTypeNumber); 454 nonTemp = Reg { m_tagTypeNumber }; 455 m_tagTypeNumber = InvalidGPRReg; 456 } 457 #endif 424 458 return nonTemp; 459 } 460 461 GPRReg getFreeTempGPR() const 462 { 463 Reg freeTempGPR { getFreeRegister([this] (Reg reg) { return reg.isGPR() && !m_newRegisters[reg]; }) }; 464 if (!freeTempGPR) 465 return InvalidGPRReg; 466 return freeTempGPR.gpr(); 425 467 } 426 468 … … 520 562 } 521 563 564 void ensureTempGPR() 565 { 566 if (getFreeTempGPR() != InvalidGPRReg) 567 return; 568 569 if (verbose) 570 dataLog(" Finding a temp GPR to spill\n"); 571 ensureRegister( 572 [this] (const CachedRecovery& cachedRecovery) { 573 if (cachedRecovery.recovery().isInGPR()) { 574 return !m_lockedRegisters.get(cachedRecovery.recovery().gpr()) 575 && !m_newRegisters[cachedRecovery.recovery().gpr()]; 576 } 577 #if USE(JSVALUE32_64) 578 if (cachedRecovery.recovery().technique() == InPair) { 579 return !m_lockedRegisters.get(cachedRecovery.recovery().tagGPR()) 580 && !m_lockedRegisters.get(cachedRecovery.recovery().payloadGPR()) 581 && !m_newRegisters[cachedRecovery.recovery().tagGPR()] 582 && !m_newRegisters[cachedRecovery.recovery().payloadGPR()]; 583 } 584 #endif 585 return false; 586 }); 587 } 588 522 589 void ensureGPR() 523 590 { … … 574 641 ASSERT(jsValueRegs && !getNew(jsValueRegs)); 575 642 CachedRecovery* cachedRecovery = addCachedRecovery(recovery); 576 ASSERT(!cachedRecovery->wantedJSValueRegs());577 cachedRecovery->setWantedJSValueRegs(jsValueRegs);578 643 #if USE(JSVALUE64) 644 if (cachedRecovery->wantedJSValueRegs()) 645 m_newRegisters[cachedRecovery->wantedJSValueRegs().gpr()] = nullptr; 579 646 m_newRegisters[jsValueRegs.gpr()] = cachedRecovery; 580 647 #else 648 if (JSValueRegs oldRegs { cachedRecovery->wantedJSValueRegs() }) { 649 if (oldRegs.payloadGPR()) 650 m_newRegisters[oldRegs.payloadGPR()] = nullptr; 651 if (oldRegs.tagGPR()) 652 m_newRegisters[oldRegs.tagGPR()] = nullptr; 653 } 581 654 if (jsValueRegs.payloadGPR() != InvalidGPRReg) 582 655 m_newRegisters[jsValueRegs.payloadGPR()] = cachedRecovery; … … 584 657 m_newRegisters[jsValueRegs.tagGPR()] = cachedRecovery; 585 658 #endif 659 ASSERT(!cachedRecovery->wantedJSValueRegs()); 660 cachedRecovery->setWantedJSValueRegs(jsValueRegs); 586 661 } 587 662 -
trunk/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp
r190329 r190370 88 88 cachedRecovery.recovery().gpr(), 89 89 cachedRecovery.recovery().gpr()); 90 // We have to do this the hard way. 91 m_jit.or64(MacroAssembler::TrustedImm64(TagTypeNumber), 92 cachedRecovery.recovery().gpr()); 90 m_lockedRegisters.set(cachedRecovery.recovery().gpr()); 91 if (tryAcquireTagTypeNumber()) 92 m_jit.or64(m_tagTypeNumber, cachedRecovery.recovery().gpr()); 93 else { 94 // We have to do this the hard way 95 m_jit.or64(MacroAssembler::TrustedImm64(TagTypeNumber), 96 cachedRecovery.recovery().gpr()); 97 } 98 m_lockedRegisters.clear(cachedRecovery.recovery().gpr()); 93 99 cachedRecovery.setRecovery( 94 100 ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatJS)); … … 142 148 m_jit.purifyNaN(cachedRecovery.recovery().fpr()); 143 149 m_jit.moveDoubleTo64(cachedRecovery.recovery().fpr(), resultGPR); 144 m_jit.sub64(MacroAssembler::TrustedImm64(TagTypeNumber), resultGPR); 150 m_lockedRegisters.set(resultGPR); 151 if (tryAcquireTagTypeNumber()) 152 m_jit.sub64(m_tagTypeNumber, resultGPR); 153 else 154 m_jit.sub64(MacroAssembler::TrustedImm64(TagTypeNumber), resultGPR); 155 m_lockedRegisters.clear(resultGPR); 145 156 updateRecovery(cachedRecovery, ValueRecovery::inGPR(resultGPR, DataFormatJS)); 146 157 if (verbose) … … 338 349 ASSERT(m_registers[wantedReg] == &cachedRecovery); 339 350 } 351 352 bool CallFrameShuffler::tryAcquireTagTypeNumber() 353 { 354 if (m_tagTypeNumber != InvalidGPRReg) 355 return true; 356 357 m_tagTypeNumber = getFreeGPR(); 358 359 if (m_tagTypeNumber == InvalidGPRReg) 360 return false; 361 362 m_lockedRegisters.set(m_tagTypeNumber); 363 m_jit.move(MacroAssembler::TrustedImm64(TagTypeNumber), m_tagTypeNumber); 364 return true; 365 } 340 366 341 367 } // namespace JSC -
trunk/Source/JavaScriptCore/jit/JITCall.cpp
r190329 r190370 194 194 if (opcodeID == op_tail_call) { 195 195 CallFrameShuffleData shuffleData; 196 shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister; 196 197 shuffleData.numLocals = 197 198 instruction[4].u.operand - sizeof(CallerFrameAndPC) / sizeof(Register); -
trunk/Source/JavaScriptCore/jit/Reg.h
r190329 r190370 56 56 { 57 57 } 58 59 Reg(WTF::HashTableDeletedValueType) 60 : m_index(deleted()) 61 { 62 } 58 63 59 64 Reg(MacroAssembler::RegisterID reg) … … 103 108 bool operator!() const { return !isSet(); } 104 109 explicit operator bool() const { return isSet(); } 110 111 bool isHashTableDeletedValue() const { return m_index == deleted(); } 105 112 106 113 bool isGPR() const … … 166 173 private: 167 174 static uint8_t invalid() { return 0xff; } 175 176 static uint8_t deleted() { return 0xfe; } 168 177 169 178 uint8_t m_index; 170 179 }; 171 180 181 struct RegHash { 182 static unsigned hash(const Reg& key) { return key.hash(); } 183 static bool equal(const Reg& a, const Reg& b) { return a == b; } 184 static const bool safeToCompareToEmptyOrDeleted = true; 185 }; 186 172 187 } // namespace JSC 173 188 189 namespace WTF { 190 191 template<typename T> struct DefaultHash; 192 template<> struct DefaultHash<JSC::Reg> { 193 typedef JSC::RegHash Hash; 194 }; 195 196 template<typename T> struct HashTraits; 197 template<> struct HashTraits<JSC::Reg> : SimpleClassHashTraits<JSC::Reg> { 198 static const bool emptyValueIsZero = false; 199 }; 200 201 } // namespace WTF 202 174 203 #endif // ENABLE(JIT) 175 204 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r190076 r190370 754 754 andi ~StackAlignmentMask, temp2 755 755 756 if ARM or SH4 or ARM64 or C_LOOP or MIPS756 if ARM or ARMv7_TRADITIONAL or ARMv7 or SH4 or ARM64 or C_LOOP or MIPS 757 757 addp 2 * PtrSize, sp 758 758 subi 2 * PtrSize, temp2 -
trunk/Source/JavaScriptCore/runtime/Options.h
r190329 r190370 129 129 \ 130 130 v(bool, enableFunctionDotArguments, true, nullptr) \ 131 v(bool, enableTailCalls, false, nullptr) \131 v(bool, enableTailCalls, true, nullptr) \ 132 132 \ 133 133 /* showDisassembly implies showDFGDisassembly. */ \ -
trunk/Source/JavaScriptCore/tests/es6.yaml
r190367 r190370 878 878 cmd: runES6 :fail 879 879 - path: es6/proper_tail_calls_tail_call_optimisation_direct_recursion.js 880 cmd: runES6 : fail880 cmd: runES6 :normal 881 881 - path: es6/proper_tail_calls_tail_call_optimisation_mutual_recursion.js 882 cmd: runES6 : fail882 cmd: runES6 :normal 883 883 - path: es6/prototype_of_bound_functions_arrow_functions.js 884 884 cmd: runES6 :fail
Note: See TracChangeset
for help on using the changeset viewer.