Changeset 187791 in webkit
- Timestamp:
- Aug 3, 2015 5:39:19 PM (9 years ago)
- Location:
- branches/jsc-tailcall/Source/JavaScriptCore
- Files:
-
- 1 added
- 29 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/jsc-tailcall/Source/JavaScriptCore/ChangeLog
r187767 r187791 1 2015-07-31 Basile Clement <basile_clement@apple.com> 2 3 jsc-tailcall: Implement the tail call opcodes in the DFG 4 https://bugs.webkit.org/show_bug.cgi?id=146850 5 6 Reviewed by Michael Saboff. 7 8 This patch adds support for tail calls in the DFG. This requires a slightly high number of nodes: 9 10 - TailCall and TailCallVarargs are straightforward. They are terminal 11 nodes and have the semantics of an actual tail call. 12 13 - TailCallInlinedCaller and TailCallVarargsInlinedCaller are here to perform a 14 tail call inside an inlined function. They are non terminal nodes, 15 and are performing the call as a regular call after popping an 16 appropriate number of inlined tail call frames. 17 18 - TailCallForwardVarargs and TailCallForwardVarargsInlinedCaller are the 19 extension of TailCallVarargs and TailCallVarargsInlinedCaller to enable 20 the varargs forwarding optimization so that we don't lose 21 performance with a tail call instead of a regular call. 22 23 This also required two broad kind of changes: 24 25 - Changes in the JIT itself (DFGSpeculativeJIT) are pretty 26 straightforward since they are just an extension of the baseline JIT 27 changes introduced previously. 28 29 - Changes in the runtime are mostly related with handling inline call 30 frames. The idea here is that we have a special TailCall type for 31 call frames that indicates to the various pieces of code walking the 32 inline call frame that they should (recursively) skip the caller in 33 their analysis. 34 35 * bytecode/CallMode.h: 36 (JSC::specializationKindFor): 37 * bytecode/CodeOrigin.cpp: 38 (JSC::CodeOrigin::inlineDepthForCallFrame): 39 (JSC::CodeOrigin::isApproximatelyEqualTo): 40 (JSC::CodeOrigin::approximateHash): 41 (JSC::CodeOrigin::inlineStack): 42 (JSC::InlineCallFrame::dumpInContext): 43 (WTF::printInternal): 44 * bytecode/CodeOrigin.h: 45 (JSC::InlineCallFrame::callModeFor): 46 (JSC::InlineCallFrame::kindFor): 47 (JSC::InlineCallFrame::varargsKindFor): 48 (JSC::InlineCallFrame::specializationKindFor): 49 (JSC::InlineCallFrame::isVarargs): 50 (JSC::InlineCallFrame::isTail): 51 (JSC::InlineCallFrame::computeCallerSkippingDeadFrames): 52 (JSC::InlineCallFrame::getCallerSkippingDeadFrames): 53 (JSC::InlineCallFrame::getCallerInlineFrameSkippingDeadFrames): 54 * dfg/DFGAbstractInterpreterInlines.h: 55 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 56 * dfg/DFGArgumentsEliminationPhase.cpp: 57 * dfg/DFGBasicBlock.h: 58 (JSC::DFG::BasicBlock::findTerminal): 59 * dfg/DFGByteCodeParser.cpp: 60 (JSC::DFG::ByteCodeParser::allInlineFramesAreTailCalls): 61 (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult): 62 (JSC::DFG::ByteCodeParser::addCall): 63 (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit): 64 (JSC::DFG::ByteCodeParser::getPrediction): 65 (JSC::DFG::ByteCodeParser::handleCall): 66 (JSC::DFG::ByteCodeParser::handleVarargsCall): 67 (JSC::DFG::ByteCodeParser::inliningCost): 68 (JSC::DFG::ByteCodeParser::inlineCall): 69 (JSC::DFG::ByteCodeParser::attemptToInlineCall): 70 (JSC::DFG::ByteCodeParser::parseBlock): 71 (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): 72 (JSC::DFG::ByteCodeParser::parseCodeBlock): 73 * dfg/DFGCapabilities.cpp: 74 (JSC::DFG::capabilityLevel): 75 * dfg/DFGClobberize.h: 76 (JSC::DFG::clobberize): 77 * dfg/DFGDoesGC.cpp: 78 (JSC::DFG::doesGC): 79 * dfg/DFGFixupPhase.cpp: 80 (JSC::DFG::FixupPhase::fixupNode): 81 * dfg/DFGGraph.cpp: 82 (JSC::DFG::Graph::isLiveInBytecode): 83 * dfg/DFGGraph.h: 84 (JSC::DFG::Graph::forAllLocalsLiveInBytecode): 85 * dfg/DFGInPlaceAbstractState.cpp: 86 (JSC::DFG::InPlaceAbstractState::mergeToSuccessors): 87 * dfg/DFGNode.h: 88 (JSC::DFG::Node::hasCallVarargsData): 89 (JSC::DFG::Node::isTerminal): 90 (JSC::DFG::Node::hasHeapPrediction): 91 * dfg/DFGNodeType.h: 92 * dfg/DFGOSRExitCompilerCommon.cpp: 93 (JSC::DFG::handleExitCounts): 94 (JSC::DFG::reifyInlinedCallFrames): 95 * dfg/DFGOSRExitPreparation.cpp: 96 (JSC::DFG::prepareCodeOriginForOSRExit): 97 * dfg/DFGOperations.cpp: 98 * dfg/DFGPreciseLocalClobberize.h: 99 (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop): 100 * dfg/DFGPredictionPropagationPhase.cpp: 101 (JSC::DFG::PredictionPropagationPhase::propagate): 102 * dfg/DFGSafeToExecute.h: 103 (JSC::DFG::safeToExecute): 104 * dfg/DFGSpeculativeJIT32_64.cpp: 105 (JSC::DFG::SpeculativeJIT::emitCall): 106 * dfg/DFGSpeculativeJIT64.cpp: 107 (JSC::DFG::SpeculativeJIT::emitCall): 108 (JSC::DFG::SpeculativeJIT::compile): 109 * dfg/DFGVarargsForwardingPhase.cpp: 110 * interpreter/CallFrame.cpp: 111 (JSC::CallFrame::bytecodeOffsetFromCodeOriginIndex): 112 * interpreter/StackVisitor.cpp: 113 (JSC::StackVisitor::gotoNextFrame): 114 * jit/CCallHelpers.h: 115 * tests/stress/dfg-tail-calls.js: Added. 116 1 117 2015-08-03 Basile Clement <basile_clement@apple.com> 2 118 -
branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallMode.h
r187629 r187791 27 27 #define CallMode_h 28 28 29 #include "CodeSpecializationKind.h" 30 29 31 namespace JSC { 30 32 … … 32 34 33 35 enum FrameAction { KeepTheFrame = 0, ReuseTheFrame }; 36 37 inline CodeSpecializationKind specializationKindFor(CallMode callMode) 38 { 39 switch (callMode) { 40 case CallMode::Tail: 41 case CallMode::Regular: 42 return CodeForCall; 43 44 case CallMode::Construct: 45 return CodeForConstruct; 46 } 47 } 34 48 35 49 } // namespace JSC -
branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.cpp
r185768 r187791 37 37 { 38 38 unsigned result = 1; 39 for (InlineCallFrame* current = inlineCallFrame; current; current = current-> caller.inlineCallFrame)39 for (InlineCallFrame* current = inlineCallFrame; current; current = current->directCaller.inlineCallFrame) 40 40 result++; 41 41 return result; … … 78 78 return false; 79 79 80 a = a.inlineCallFrame-> caller;81 b = b.inlineCallFrame-> caller;80 a = a.inlineCallFrame->directCaller; 81 b = b.inlineCallFrame->directCaller; 82 82 } 83 83 } … … 100 100 result += WTF::PtrHash<JSCell*>::hash(codeOrigin.inlineCallFrame->executable.get()); 101 101 102 codeOrigin = codeOrigin.inlineCallFrame-> caller;102 codeOrigin = codeOrigin.inlineCallFrame->directCaller; 103 103 } 104 104 } … … 109 109 result.last() = *this; 110 110 unsigned index = result.size() - 2; 111 for (InlineCallFrame* current = inlineCallFrame; current; current = current-> caller.inlineCallFrame)112 result[index--] = current-> caller;111 for (InlineCallFrame* current = inlineCallFrame; current; current = current->directCaller.inlineCallFrame) 112 result[index--] = current->directCaller; 113 113 RELEASE_ASSERT(!result[0].inlineCallFrame); 114 114 return result; … … 191 191 if (executable->isStrictMode()) 192 192 out.print(" (StrictMode)"); 193 out.print(", bc#", caller.bytecodeIndex, ", ", kind);193 out.print(", bc#", directCaller.bytecodeIndex, ", ", static_cast<Kind>(kind)); 194 194 if (isClosureCall) 195 195 out.print(", closure call"); … … 219 219 out.print("Construct"); 220 220 return; 221 case JSC::InlineCallFrame::TailCall: 222 out.print("TailCall"); 223 return; 221 224 case JSC::InlineCallFrame::CallVarargs: 222 225 out.print("CallVarargs"); … … 225 228 out.print("ConstructVarargs"); 226 229 return; 230 case JSC::InlineCallFrame::TailCallVarargs: 231 out.print("TailCallVarargs"); 232 return; 227 233 case JSC::InlineCallFrame::GetterCall: 228 234 out.print("GetterCall"); -
branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.h
r182759 r187791 27 27 #define CodeOrigin_h 28 28 29 #include "CallMode.h" 29 30 #include "CodeBlockHash.h" 30 31 #include "CodeSpecializationKind.h" … … 121 122 Call, 122 123 Construct, 124 TailCall, 123 125 CallVarargs, 124 126 ConstructVarargs, 127 TailCallVarargs, 125 128 126 129 // For these, the stackOffset incorporates the argument count plus the true return PC … … 129 132 SetterCall 130 133 }; 131 132 static Kind kindFor(CodeSpecializationKind kind) 133 { 134 switch (kind) { 135 case CodeForCall: 136 return Call; 137 case CodeForConstruct: 138 return Construct; 139 } 140 RELEASE_ASSERT_NOT_REACHED(); 141 return Call; 142 } 143 144 static Kind varargsKindFor(CodeSpecializationKind kind) 145 { 146 switch (kind) { 147 case CodeForCall: 148 return CallVarargs; 149 case CodeForConstruct: 150 return ConstructVarargs; 151 } 152 RELEASE_ASSERT_NOT_REACHED(); 153 return Call; 154 } 155 156 static CodeSpecializationKind specializationKindFor(Kind kind) 134 135 static CallMode callModeFor(Kind kind) 157 136 { 158 137 switch (kind) { 159 138 case Call: 160 139 case CallVarargs: 140 case GetterCall: 141 case SetterCall: 142 return CallMode::Regular; 143 case TailCall: 144 case TailCallVarargs: 145 return CallMode::Tail; 146 case Construct: 147 case ConstructVarargs: 148 return CallMode::Construct; 149 } 150 } 151 152 static Kind kindFor(CallMode callMode) 153 { 154 switch (callMode) { 155 case CallMode::Regular: 156 return Call; 157 case CallMode::Construct: 158 return Construct; 159 case CallMode::Tail: 160 return TailCall; 161 } 162 RELEASE_ASSERT_NOT_REACHED(); 163 } 164 165 static Kind varargsKindFor(CallMode callMode) 166 { 167 switch (callMode) { 168 case CallMode::Regular: 169 return CallVarargs; 170 case CallMode::Construct: 171 return ConstructVarargs; 172 case CallMode::Tail: 173 return TailCallVarargs; 174 } 175 RELEASE_ASSERT_NOT_REACHED(); 176 } 177 178 static CodeSpecializationKind specializationKindFor(Kind kind) 179 { 180 switch (kind) { 181 case Call: 182 case CallVarargs: 183 case TailCall: 184 case TailCallVarargs: 161 185 case GetterCall: 162 186 case SetterCall: … … 167 191 } 168 192 RELEASE_ASSERT_NOT_REACHED(); 169 return CodeForCall;170 193 } 171 194 … … 175 198 case CallVarargs: 176 199 case ConstructVarargs: 200 case TailCallVarargs: 177 201 return true; 178 202 default: … … 184 208 return isVarargs(static_cast<Kind>(kind)); 185 209 } 210 211 static bool isTail(Kind kind) 212 { 213 switch (kind) { 214 case TailCall: 215 case TailCallVarargs: 216 return true; 217 default: 218 return false; 219 } 220 } 221 bool isTail() const 222 { 223 return isTail(static_cast<Kind>(kind)); 224 } 225 226 static CodeOrigin* computeCallerSkippingDeadFrames(InlineCallFrame* inlineCallFrame) 227 { 228 CodeOrigin* codeOrigin; 229 bool tailCallee; 230 do { 231 tailCallee = inlineCallFrame->isTail(); 232 codeOrigin = &inlineCallFrame->directCaller; 233 inlineCallFrame = codeOrigin->inlineCallFrame; 234 } while (inlineCallFrame && tailCallee); 235 if (tailCallee) 236 return nullptr; 237 return codeOrigin; 238 } 239 CodeOrigin* getCallerSkippingDeadFrames() 240 { 241 return computeCallerSkippingDeadFrames(this); 242 } 243 InlineCallFrame* getCallerInlineFrameSkippingDeadFrames() 244 { 245 CodeOrigin* caller = getCallerSkippingDeadFrames(); 246 return caller ? caller->inlineCallFrame : nullptr; 247 } 186 248 187 249 Vector<ValueRecovery> arguments; // Includes 'this'. 188 250 WriteBarrier<ScriptExecutable> executable; 189 251 ValueRecovery calleeRecovery; 190 CodeOrigin caller;252 CodeOrigin directCaller; 191 253 192 254 signed stackOffset : 28; -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r185239 r187791 1443 1443 m_state.setIsValid(false); 1444 1444 break; 1445 1446 case TailCall: 1447 case TailCallVarargs: 1448 case TailCallForwardVarargs: 1449 clobberWorld(node->origin.semantic, clobberLimit); 1450 m_state.setIsValid(false); 1451 break; 1445 1452 1446 1453 case Throw: … … 2254 2261 2255 2262 case Call: 2263 case TailCallInlinedCaller: 2256 2264 case Construct: 2257 2265 case NativeCall: … … 2259 2267 case CallVarargs: 2260 2268 case CallForwardVarargs: 2269 case TailCallVarargsInlinedCaller: 2261 2270 case ConstructVarargs: 2262 2271 case ConstructForwardVarargs: 2272 case TailCallForwardVarargsInlinedCaller: 2263 2273 clobberWorld(node->origin.semantic, clobberLimit); 2264 2274 forNode(node).makeHeapTop(); -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp
r184781 r187791 168 168 case CallVarargs: 169 169 case ConstructVarargs: 170 case TailCallVarargs: 171 case TailCallVarargsInlinedCaller: 170 172 escape(node->child1()); 171 173 escape(node->child3()); … … 554 556 555 557 case CallVarargs: 556 case ConstructVarargs: { 558 case ConstructVarargs: 559 case TailCallVarargs: 560 case TailCallVarargsInlinedCaller: { 557 561 Node* candidate = node->child2().node(); 558 562 if (!m_candidates.contains(candidate)) … … 579 583 for (Node* argument : arguments) 580 584 m_graph.m_varArgChildren.append(Edge(argument)); 581 node->setOpAndDefaultFlags( 582 node->op() == CallVarargs ? Call : Construct); 585 switch (node->op()) { 586 case CallVarargs: 587 node->setOpAndDefaultFlags(Call); 588 break; 589 case ConstructVarargs: 590 node->setOpAndDefaultFlags(Construct); 591 break; 592 case TailCallVarargs: 593 node->setOpAndDefaultFlags(TailCall); 594 break; 595 case TailCallVarargsInlinedCaller: 596 node->setOpAndDefaultFlags(TailCallInlinedCaller); 597 break; 598 default: 599 RELEASE_ASSERT_NOT_REACHED(); 600 } 583 601 node->children = AdjacencyList( 584 602 AdjacencyList::Variable, … … 587 605 } 588 606 589 node->setOpAndDefaultFlags( 590 node->op() == CallVarargs ? CallForwardVarargs : ConstructForwardVarargs); 607 switch (node->op()) { 608 case CallVarargs: 609 node->setOpAndDefaultFlags(CallForwardVarargs); 610 break; 611 case ConstructVarargs: 612 node->setOpAndDefaultFlags(ConstructForwardVarargs); 613 break; 614 case TailCallVarargs: 615 node->setOpAndDefaultFlags(TailCallForwardVarargs); 616 break; 617 case TailCallVarargsInlinedCaller: 618 node->setOpAndDefaultFlags(TailCallForwardVarargsInlinedCaller); 619 break; 620 default: 621 RELEASE_ASSERT_NOT_REACHED(); 622 } 591 623 break; 592 624 } -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGBasicBlock.h
r183497 r187791 93 93 case Switch: 94 94 case Return: 95 case TailCall: 96 case TailCallVarargs: 95 97 case Unreachable: 96 98 return NodeAndIndex(node, i); -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r187767 r187791 181 181 SpeculatedType prediction); 182 182 void handleCall( 183 int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize,183 int result, NodeType op, CallMode, unsigned instructionSize, 184 184 Node* callTarget, int argCount, int registerOffset, CallLinkStatus); 185 void handleCall(int result, NodeType op, C odeSpecializationKind, unsigned instructionSize, int callee, int argCount, int registerOffset);186 void handleCall(Instruction* pc, NodeType op, C odeSpecializationKind);187 void handleVarargsCall(Instruction* pc, NodeType op, C odeSpecializationKind);185 void handleCall(int result, NodeType op, CallMode, unsigned instructionSize, int callee, int argCount, int registerOffset); 186 void handleCall(Instruction* pc, NodeType op, CallMode); 187 void handleVarargsCall(Instruction* pc, NodeType op, CallMode); 188 188 void emitFunctionChecks(CallVariant, Node* callTarget, VirtualRegister thisArgumnt); 189 189 void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis); 190 unsigned inliningCost(CallVariant, int argumentCountIncludingThis, C odeSpecializationKind); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1.190 unsigned inliningCost(CallVariant, int argumentCountIncludingThis, CallMode); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1. 191 191 // Handle inlining. Return true if it succeeded, false if we need to plant a call. 192 192 bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, VirtualRegister thisArgument, VirtualRegister argumentsArgument, unsigned argumentsOffset, int argumentCountIncludingThis, unsigned nextOffset, NodeType callOp, InlineCallFrame::Kind, SpeculatedType prediction); … … 601 601 } 602 602 603 bool allInlineFramesAreTailCalls() 604 { 605 return !inlineCallFrame() || !inlineCallFrame()->getCallerSkippingDeadFrames(); 606 } 607 603 608 CodeOrigin currentCodeOrigin() 604 609 { … … 681 686 Node* addCallWithoutSettingResult( 682 687 NodeType op, OpInfo opInfo, Node* callee, int argCount, int registerOffset, 683 SpeculatedTypeprediction)688 OpInfo prediction) 684 689 { 685 690 addVarArgChild(callee); … … 694 699 addVarArgChild(get(virtualRegisterForArgument(i, registerOffset))); 695 700 696 return addToGraph(Node::VarArg, op, opInfo, OpInfo(prediction));701 return addToGraph(Node::VarArg, op, opInfo, prediction); 697 702 } 698 703 … … 701 706 SpeculatedType prediction) 702 707 { 708 if (op == TailCall) { 709 if (allInlineFramesAreTailCalls()) 710 return addCallWithoutSettingResult(op, OpInfo(), callee, argCount, registerOffset, OpInfo()); 711 op = TailCallInlinedCaller; 712 } 713 714 703 715 Node* call = addCallWithoutSettingResult( 704 op, opInfo, callee, argCount, registerOffset, prediction);716 op, opInfo, callee, argCount, registerOffset, OpInfo(prediction)); 705 717 VirtualRegister resultReg(result); 706 718 if (resultReg.isValid()) … … 718 730 SpeculatedType getPredictionWithoutOSRExit(unsigned bytecodeIndex) 719 731 { 720 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 721 return m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(locker, bytecodeIndex); 732 SpeculatedType prediction; 733 CodeBlock* profiledBlock = nullptr; 734 735 { 736 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 737 prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(locker, bytecodeIndex); 738 739 if (prediction == SpecNone) { 740 // If we have no information about the values this 741 // node generates, we check if by any chance it is 742 // a tail call opcode. In that case, we walk up the 743 // inline frames to find a call higher in the call 744 // chain and use its prediction. If we only have 745 // inlined tail call frames, we use SpecFullTop 746 // to avoid a spurious OSR exit. 747 Instruction* instruction = m_inlineStackTop->m_profiledBlock->instructions().begin() + bytecodeIndex; 748 OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(instruction->u.opcode); 749 750 switch (opcodeID) { 751 case op_tail_call: 752 case op_tail_call_varargs: { 753 if (!inlineCallFrame()) { 754 prediction = SpecFullTop; 755 break; 756 } 757 CodeOrigin* codeOrigin = inlineCallFrame()->getCallerSkippingDeadFrames(); 758 if (!codeOrigin) { 759 prediction = SpecFullTop; 760 break; 761 } 762 InlineStackEntry* stack = m_inlineStackTop; 763 while (stack->m_inlineCallFrame != codeOrigin->inlineCallFrame) 764 stack = stack->m_caller; 765 bytecodeIndex = codeOrigin->bytecodeIndex; 766 profiledBlock = stack->m_profiledBlock; 767 break; 768 } 769 770 default: 771 break; 772 } 773 } 774 } 775 776 if (profiledBlock) { 777 ConcurrentJITLocker locker(profiledBlock->m_lock); 778 prediction = profiledBlock->valueProfilePredictionForBytecodeOffset(locker, bytecodeIndex); 779 } 780 781 return prediction; 722 782 } 723 783 … … 725 785 { 726 786 SpeculatedType prediction = getPredictionWithoutOSRExit(bytecodeIndex); 727 787 728 788 if (prediction == SpecNone) { 729 789 // We have no information about what values this node generates. Give up … … 1015 1075 return shouldContinueParsing 1016 1076 1017 void ByteCodeParser::handleCall(Instruction* pc, NodeType op, C odeSpecializationKind kind)1077 void ByteCodeParser::handleCall(Instruction* pc, NodeType op, CallMode callMode) 1018 1078 { 1019 1079 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); 1080 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_tail_call)); 1020 1081 handleCall( 1021 pc[1].u.operand, op, kind, OPCODE_LENGTH(op_call),1082 pc[1].u.operand, op, callMode, OPCODE_LENGTH(op_call), 1022 1083 pc[2].u.operand, pc[3].u.operand, -pc[4].u.operand); 1023 1084 } 1024 1085 1025 1086 void ByteCodeParser::handleCall( 1026 int result, NodeType op, C odeSpecializationKind kind, unsigned instructionSize,1087 int result, NodeType op, CallMode callMode, unsigned instructionSize, 1027 1088 int callee, int argumentCountIncludingThis, int registerOffset) 1028 1089 { … … 1034 1095 1035 1096 handleCall( 1036 result, op, InlineCallFrame::kindFor(kind), instructionSize, callTarget,1097 result, op, callMode, instructionSize, callTarget, 1037 1098 argumentCountIncludingThis, registerOffset, callLinkStatus); 1038 1099 } 1039 1100 1040 1101 void ByteCodeParser::handleCall( 1041 int result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize,1102 int result, NodeType op, CallMode callMode, unsigned instructionSize, 1042 1103 Node* callTarget, int argumentCountIncludingThis, int registerOffset, 1043 1104 CallLinkStatus callLinkStatus) 1044 1105 { 1045 1106 handleCall( 1046 result, op, kind, instructionSize, callTarget, argumentCountIncludingThis,1107 result, op, InlineCallFrame::kindFor(callMode), instructionSize, callTarget, argumentCountIncludingThis, 1047 1108 registerOffset, callLinkStatus, getPrediction()); 1048 1109 } … … 1064 1125 // Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically 1065 1126 // that we cannot optimize them. 1066 1127 1067 1128 addCall(result, op, OpInfo(), callTarget, argumentCountIncludingThis, registerOffset, prediction); 1068 1129 return; … … 1097 1158 } 1098 1159 #endif 1099 1160 1100 1161 addCall(result, op, callOpInfo, callTarget, argumentCountIncludingThis, registerOffset, prediction); 1101 1162 } 1102 1163 1103 void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, C odeSpecializationKind kind)1164 void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CallMode callMode) 1104 1165 { 1105 1166 ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_construct_varargs)); 1167 ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_tail_call_varargs)); 1106 1168 1107 1169 int result = pc[1].u.operand; … … 1126 1188 1127 1189 if (callLinkStatus.canOptimize() 1128 && handleInlining(callTarget, result, callLinkStatus, firstFreeReg, VirtualRegister(thisReg), VirtualRegister(arguments), firstVarArgOffset, 0, m_currentIndex + OPCODE_LENGTH(op_call_varargs), op, InlineCallFrame::varargsKindFor( kind), prediction)) {1190 && handleInlining(callTarget, result, callLinkStatus, firstFreeReg, VirtualRegister(thisReg), VirtualRegister(arguments), firstVarArgOffset, 0, m_currentIndex + OPCODE_LENGTH(op_call_varargs), op, InlineCallFrame::varargsKindFor(callMode), prediction)) { 1129 1191 if (m_graph.compilation()) 1130 1192 m_graph.compilation()->noticeInlinedCall(); … … 1136 1198 1137 1199 Node* thisChild = get(VirtualRegister(thisReg)); 1138 1200 1201 if (op == TailCallVarargs) { 1202 if (allInlineFramesAreTailCalls()) { 1203 addToGraph(op, OpInfo(data), OpInfo(), callTarget, get(VirtualRegister(arguments)), thisChild); 1204 return; 1205 } 1206 op = TailCallVarargsInlinedCaller; 1207 } 1208 1139 1209 Node* call = addToGraph(op, OpInfo(data), OpInfo(prediction), callTarget, get(VirtualRegister(arguments)), thisChild); 1140 1210 VirtualRegister resultReg(result); … … 1171 1241 } 1172 1242 1173 unsigned ByteCodeParser::inliningCost(CallVariant callee, int argumentCountIncludingThis, C odeSpecializationKind kind)1243 unsigned ByteCodeParser::inliningCost(CallVariant callee, int argumentCountIncludingThis, CallMode callMode) 1174 1244 { 1245 CodeSpecializationKind kind = specializationKindFor(callMode); 1175 1246 if (verbose) 1176 1247 dataLog("Considering inlining ", callee, " into ", currentCodeOrigin(), "\n"); … … 1214 1285 codeBlock, kind, callee.isClosureCall()); 1215 1286 if (verbose) { 1216 dataLog(" Kind: ", kind, "\n");1287 dataLog(" Call mode: ", callMode, "\n"); 1217 1288 dataLog(" Is closure call: ", callee.isClosureCall(), "\n"); 1218 1289 dataLog(" Capability level: ", capabilityLevel, "\n"); … … 1285 1356 CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind); 1286 1357 1287 ASSERT(inliningCost(callee, argumentCountIncludingThis, specializationKind) != UINT_MAX);1358 ASSERT(inliningCost(callee, argumentCountIncludingThis, InlineCallFrame::callModeFor(kind)) != UINT_MAX); 1288 1359 1289 1360 CodeBlock* codeBlock = callee.functionExecutable()->baselineCodeBlockFor(specializationKind); … … 1380 1451 return; 1381 1452 } 1382 1453 1383 1454 if (Options::verboseDFGByteCodeParsing()) 1384 1455 dataLog(" Creating new block after inlining.\n"); … … 1487 1558 } 1488 1559 1489 unsigned myInliningCost = inliningCost(callee, argumentCountIncludingThis, specializationKind);1560 unsigned myInliningCost = inliningCost(callee, argumentCountIncludingThis, InlineCallFrame::callModeFor(kind)); 1490 1561 if (myInliningCost > inliningBalance) 1491 1562 return false; … … 3355 3426 3356 3427 case op_ret: 3428 if (m_currentBlock->terminal()) { 3429 // We could be the dummy return after a non-inlined, non-emulated tail call 3430 Node* terminal = m_currentBlock->terminal(); 3431 ASSERT_UNUSED(terminal, terminal->op() == Return || terminal->op() == TailCall || terminal->op() == TailCallVarargs); 3432 LAST_OPCODE(op_ret); 3433 } 3357 3434 if (inlineCallFrame()) { 3358 3435 flushForReturn(); … … 3402 3479 3403 3480 case op_call: 3404 handleCall(currentInstruction, Call, C odeForCall);3481 handleCall(currentInstruction, Call, CallMode::Regular); 3405 3482 // Verify that handleCall(), which could have inlined the callee, didn't trash m_currentInstruction 3406 3483 ASSERT(m_currentInstruction == currentInstruction); 3407 3484 NEXT_OPCODE(op_call); 3408 3485 3486 case op_tail_call: 3487 flushForReturn(); 3488 handleCall(currentInstruction, TailCall, CallMode::Tail); 3489 // Verify that handleCall(), which could have inlined the callee, didn't trash m_currentInstruction 3490 ASSERT(m_currentInstruction == currentInstruction); 3491 // We let the following op_ret handle cases related to 3492 // inlining to keep things simple. 3493 NEXT_OPCODE(op_tail_call); 3494 3409 3495 case op_construct: 3410 handleCall(currentInstruction, Construct, C odeForConstruct);3496 handleCall(currentInstruction, Construct, CallMode::Construct); 3411 3497 NEXT_OPCODE(op_construct); 3412 3498 3413 3499 case op_call_varargs: { 3414 handleVarargsCall(currentInstruction, CallVarargs, C odeForCall);3500 handleVarargsCall(currentInstruction, CallVarargs, CallMode::Regular); 3415 3501 NEXT_OPCODE(op_call_varargs); 3416 3502 } 3503 3504 case op_tail_call_varargs: { 3505 flushForReturn(); 3506 handleVarargsCall(currentInstruction, TailCallVarargs, CallMode::Tail); 3507 NEXT_OPCODE(op_tail_call_varargs); 3508 } 3417 3509 3418 3510 case op_construct_varargs: { 3419 handleVarargsCall(currentInstruction, ConstructVarargs, C odeForConstruct);3511 handleVarargsCall(currentInstruction, ConstructVarargs, CallMode::Construct); 3420 3512 NEXT_OPCODE(op_construct_varargs); 3421 3513 } … … 4039 4131 } else 4040 4132 m_inlineCallFrame->isClosureCall = true; 4041 m_inlineCallFrame-> caller = byteCodeParser->currentCodeOrigin();4133 m_inlineCallFrame->directCaller = byteCodeParser->currentCodeOrigin(); 4042 4134 m_inlineCallFrame->arguments.resizeToFit(argumentCountIncludingThis); // Set the number of arguments including this, but don't configure the value recoveries, yet. 4043 4135 m_inlineCallFrame->kind = kind; … … 4114 4206 Vector<DeferredSourceDump>& deferredSourceDump = m_graph.m_plan.callback->ensureDeferredSourceDump(); 4115 4207 if (inlineCallFrame()) { 4116 DeferredSourceDump dump(codeBlock->baselineVersion(), m_codeBlock, JITCode::DFGJIT, inlineCallFrame()-> caller);4208 DeferredSourceDump dump(codeBlock->baselineVersion(), m_codeBlock, JITCode::DFGJIT, inlineCallFrame()->directCaller); 4117 4209 deferredSourceDump.append(dump); 4118 4210 } else … … 4125 4217 dataLog( 4126 4218 " for inlining at ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), 4127 " ", inlineCallFrame()-> caller);4219 " ", inlineCallFrame()->directCaller); 4128 4220 } 4129 4221 dataLog( … … 4209 4301 } 4210 4302 4211 m_currentBlock = 0;4303 m_currentBlock = nullptr; 4212 4304 } while (m_currentIndex < limit); 4213 4305 } -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
r183373 r187791 180 180 case op_throw_static_error: 181 181 case op_call: 182 case op_tail_call: 182 183 case op_construct: 183 184 case op_call_varargs: 185 case op_tail_call_varargs: 184 186 case op_construct_varargs: 185 187 case op_create_direct_arguments: -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGClobberize.h
r185566 r187791 377 377 case ArrayPop: 378 378 case Call: 379 case TailCallInlinedCaller: 379 380 case Construct: 380 381 case NativeCall: … … 382 383 case CallVarargs: 383 384 case CallForwardVarargs: 385 case TailCallVarargsInlinedCaller: 386 case TailCallForwardVarargsInlinedCaller: 384 387 case ConstructVarargs: 385 388 case ConstructForwardVarargs: … … 389 392 read(World); 390 393 write(Heap); 394 return; 395 396 case TailCall: 397 case TailCallVarargs: 398 case TailCallForwardVarargs: 399 read(World); 400 write(SideState); 391 401 return; 392 402 -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r184511 r187791 118 118 case CompareStrictEq: 119 119 case Call: 120 case TailCallInlinedCaller: 120 121 case Construct: 121 122 case CallVarargs: 123 case TailCallVarargsInlinedCaller: 122 124 case ConstructVarargs: 123 125 case LoadVarargs: 124 126 case CallForwardVarargs: 125 127 case ConstructForwardVarargs: 128 case TailCallForwardVarargs: 129 case TailCallForwardVarargsInlinedCaller: 126 130 case NativeCall: 127 131 case NativeConstruct: … … 150 154 case Switch: 151 155 case Return: 156 case TailCall: 157 case TailCallVarargs: 152 158 case Throw: 153 159 case CountExecution: -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r185920 r187791 1279 1279 case VarInjectionWatchpoint: 1280 1280 case Call: 1281 case TailCallInlinedCaller: 1281 1282 case Construct: 1282 1283 case CallVarargs: 1284 case TailCallVarargsInlinedCaller: 1283 1285 case ConstructVarargs: 1284 1286 case CallForwardVarargs: 1285 1287 case ConstructForwardVarargs: 1288 case TailCallForwardVarargs: 1289 case TailCallForwardVarargsInlinedCaller: 1286 1290 case LoadVarargs: 1287 1291 case ProfileControlFlow: … … 1303 1307 case Jump: 1304 1308 case Return: 1309 case TailCall: 1310 case TailCallVarargs: 1305 1311 case Throw: 1306 1312 case ThrowReferenceError: -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.cpp
r186215 r187791 885 885 bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin) 886 886 { 887 CodeOrigin* codeOriginPtr = &codeOrigin; 887 888 for (;;) { 888 889 VirtualRegister reg = VirtualRegister( 889 operand.offset() - codeOrigin .stackOffset());890 891 if (operand.offset() < codeOrigin .stackOffset() + JSStack::CallFrameHeaderSize) {890 operand.offset() - codeOriginPtr->stackOffset()); 891 892 if (operand.offset() < codeOriginPtr->stackOffset() + JSStack::CallFrameHeaderSize) { 892 893 if (reg.isArgument()) { 893 894 RELEASE_ASSERT(reg.offset() < JSStack::CallFrameHeaderSize); 894 895 895 if (codeOrigin .inlineCallFrame->isClosureCall896 if (codeOriginPtr->inlineCallFrame->isClosureCall 896 897 && reg.offset() == JSStack::Callee) 897 898 return true; 898 899 899 if (codeOrigin .inlineCallFrame->isVarargs()900 if (codeOriginPtr->inlineCallFrame->isVarargs() 900 901 && reg.offset() == JSStack::ArgumentCount) 901 902 return true; … … 904 905 } 905 906 906 return livenessFor(codeOrigin .inlineCallFrame).operandIsLive(907 reg.offset(), codeOrigin .bytecodeIndex);908 } 909 910 InlineCallFrame* inlineCallFrame = codeOrigin .inlineCallFrame;907 return livenessFor(codeOriginPtr->inlineCallFrame).operandIsLive( 908 reg.offset(), codeOriginPtr->bytecodeIndex); 909 } 910 911 InlineCallFrame* inlineCallFrame = codeOriginPtr->inlineCallFrame; 911 912 if (!inlineCallFrame) 912 913 break; … … 918 919 return true; 919 920 920 codeOrigin = inlineCallFrame->caller; 921 codeOriginPtr = inlineCallFrame->getCallerSkippingDeadFrames(); 922 923 // The first inline call frame could be an inline tail call 924 if (!codeOriginPtr) 925 break; 921 926 } 922 927 -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.h
r186279 r187791 697 697 VirtualRegister exclusionStart; 698 698 VirtualRegister exclusionEnd; 699 700 CodeOrigin* codeOriginPtr = &codeOrigin; 699 701 700 702 for (;;) { 701 InlineCallFrame* inlineCallFrame = codeOrigin .inlineCallFrame;703 InlineCallFrame* inlineCallFrame = codeOriginPtr->inlineCallFrame; 702 704 VirtualRegister stackOffset(inlineCallFrame ? inlineCallFrame->stackOffset : 0); 703 705 … … 711 713 CodeBlock* codeBlock = baselineCodeBlockFor(inlineCallFrame); 712 714 FullBytecodeLiveness& fullLiveness = livenessFor(codeBlock); 713 const FastBitVector& liveness = fullLiveness.getLiveness(codeOrigin .bytecodeIndex);715 const FastBitVector& liveness = fullLiveness.getLiveness(codeOriginPtr->bytecodeIndex); 714 716 for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) { 715 717 VirtualRegister reg = stackOffset + virtualRegisterForLocal(relativeLocal); … … 738 740 functor(reg); 739 741 740 codeOrigin = inlineCallFrame->caller; 742 codeOriginPtr = inlineCallFrame->getCallerSkippingDeadFrames(); 743 744 // The first inline call frame could be an inline tail call 745 if (!codeOriginPtr) 746 break; 741 747 } 742 748 } -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
r184318 r187791 394 394 395 395 case Return: 396 case TailCall: 397 case TailCallVarargs: 396 398 case Unreachable: 397 399 ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection); -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNode.h
r186136 r187791 996 996 case CallVarargs: 997 997 case CallForwardVarargs: 998 case TailCallVarargs: 999 case TailCallForwardVarargs: 1000 case TailCallVarargsInlinedCaller: 1001 case TailCallForwardVarargsInlinedCaller: 998 1002 case ConstructVarargs: 999 1003 case ConstructForwardVarargs: … … 1093 1097 case Switch: 1094 1098 case Return: 1099 case TailCall: 1100 case TailCallVarargs: 1095 1101 case Unreachable: 1096 1102 return true; … … 1243 1249 case GetByVal: 1244 1250 case Call: 1251 case TailCallInlinedCaller: 1245 1252 case Construct: 1246 1253 case CallVarargs: 1254 case TailCallVarargsInlinedCaller: 1247 1255 case ConstructVarargs: 1248 1256 case CallForwardVarargs: 1257 case TailCallForwardVarargsInlinedCaller: 1249 1258 case NativeCall: 1250 1259 case NativeConstruct: -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNodeType.h
r184511 r187791 240 240 macro(ConstructVarargs, NodeResultJS | NodeMustGenerate) \ 241 241 macro(ConstructForwardVarargs, NodeResultJS | NodeMustGenerate) \ 242 macro(TailCallInlinedCaller, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \ 243 macro(TailCallVarargsInlinedCaller, NodeResultJS | NodeMustGenerate) \ 244 macro(TailCallForwardVarargsInlinedCaller, NodeResultJS | NodeMustGenerate) \ 242 245 macro(NativeCall, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \ 243 246 macro(NativeConstruct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \ … … 305 308 macro(Switch, NodeMustGenerate) \ 306 309 macro(Return, NodeMustGenerate) \ 310 macro(TailCall, NodeMustGenerate | NodeHasVarArgs) \ 311 macro(TailCallVarargs, NodeMustGenerate) \ 312 macro(TailCallForwardVarargs, NodeMustGenerate) \ 307 313 macro(Unreachable, NodeMustGenerate) \ 308 314 \ -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp
r187639 r187791 65 65 AssemblyHelpers::JumpList loopThreshold; 66 66 67 for (InlineCallFrame* inlineCallFrame = exit.m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame-> caller.inlineCallFrame) {67 for (InlineCallFrame* inlineCallFrame = exit.m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) { 68 68 loopThreshold.append( 69 69 jit.branchTest8( … … 137 137 void reifyInlinedCallFrames(CCallHelpers& jit, const OSRExitBase& exit) 138 138 { 139 // FIXME: We shouldn't leave holes on the stack when performing an OSR exit 140 // in presence of inlined tail calls. 141 // https://bugs.webkit.org/show_bug.cgi?id=147511 139 142 ASSERT(jit.baselineCodeBlock()->jitType() == JITCode::BaselineJIT); 140 143 jit.storePtr(AssemblyHelpers::TrustedImmPtr(jit.baselineCodeBlock()), AssemblyHelpers::addressFor((VirtualRegister)JSStack::CodeBlock)); 141 144 142 CodeOrigin codeOrigin; 143 for (codeOrigin = exit.m_codeOrigin; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->caller) { 144 InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; 145 CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(codeOrigin); 146 CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(inlineCallFrame->caller); 147 void* jumpTarget = nullptr; 145 const CodeOrigin* codeOrigin; 146 for (codeOrigin = &exit.m_codeOrigin; codeOrigin && codeOrigin->inlineCallFrame; codeOrigin = codeOrigin->inlineCallFrame->getCallerSkippingDeadFrames()) { 147 InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame; 148 CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(*codeOrigin); 149 CodeOrigin* trueCaller = inlineCallFrame->getCallerSkippingDeadFrames(); 148 150 void* trueReturnPC = nullptr; 149 150 unsigned callBytecodeIndex = inlineCallFrame->caller.bytecodeIndex; 151 152 switch (inlineCallFrame->kind) { 153 case InlineCallFrame::Call: 154 case InlineCallFrame::Construct: 155 case InlineCallFrame::CallVarargs: 156 case InlineCallFrame::ConstructVarargs: { 157 CallLinkInfo* callLinkInfo = 158 baselineCodeBlockForCaller->getCallLinkInfoForBytecodeIndex(callBytecodeIndex); 159 RELEASE_ASSERT(callLinkInfo); 160 161 jumpTarget = callLinkInfo->callReturnLocation().executableAddress(); 162 break; 163 } 164 165 case InlineCallFrame::GetterCall: 166 case InlineCallFrame::SetterCall: { 167 StructureStubInfo* stubInfo = 168 baselineCodeBlockForCaller->findStubInfo(CodeOrigin(callBytecodeIndex)); 169 RELEASE_ASSERT(stubInfo); 170 151 GPRReg callerFrameGPR = GPRInfo::callFrameRegister; 152 153 if (!trueCaller) { 154 ASSERT(inlineCallFrame->isTail()); 155 jit.loadPtr(AssemblyHelpers::Address(GPRInfo::callFrameRegister, CallFrame::returnPCOffset()), GPRInfo::regT3); 156 jit.storePtr(GPRInfo::regT3, AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset())); 157 jit.loadPtr(AssemblyHelpers::Address(GPRInfo::callFrameRegister, CallFrame::callerFrameOffset()), GPRInfo::regT3); 158 callerFrameGPR = GPRInfo::regT3; 159 } else { 160 CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(*trueCaller); 161 unsigned callBytecodeIndex = trueCaller->bytecodeIndex; 162 void* jumpTarget = nullptr; 163 171 164 switch (inlineCallFrame->kind) { 172 case InlineCallFrame::GetterCall: 173 jumpTarget = jit.vm()->getCTIStub(baselineGetterReturnThunkGenerator).code().executableAddress(); 174 break; 175 case InlineCallFrame::SetterCall: 176 jumpTarget = jit.vm()->getCTIStub(baselineSetterReturnThunkGenerator).code().executableAddress(); 177 break; 178 default: 179 RELEASE_ASSERT_NOT_REACHED(); 165 case InlineCallFrame::Call: 166 case InlineCallFrame::Construct: 167 case InlineCallFrame::CallVarargs: 168 case InlineCallFrame::ConstructVarargs: 169 case InlineCallFrame::TailCall: 170 case InlineCallFrame::TailCallVarargs: { 171 CallLinkInfo* callLinkInfo = 172 baselineCodeBlockForCaller->getCallLinkInfoForBytecodeIndex(callBytecodeIndex); 173 RELEASE_ASSERT(callLinkInfo); 174 175 jumpTarget = callLinkInfo->callReturnLocation().executableAddress(); 180 176 break; 181 177 } 182 183 trueReturnPC = stubInfo->callReturnLocation.labelAtOffset( 184 stubInfo->patch.deltaCallToDone).executableAddress(); 185 break; 186 } } 187 188 GPRReg callerFrameGPR; 189 if (inlineCallFrame->caller.inlineCallFrame) { 190 jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->caller.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT3); 191 callerFrameGPR = GPRInfo::regT3; 192 } else 193 callerFrameGPR = GPRInfo::callFrameRegister; 194 195 jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset())); 178 179 case InlineCallFrame::GetterCall: 180 case InlineCallFrame::SetterCall: { 181 StructureStubInfo* stubInfo = 182 baselineCodeBlockForCaller->findStubInfo(CodeOrigin(callBytecodeIndex)); 183 RELEASE_ASSERT(stubInfo); 184 185 switch (inlineCallFrame->kind) { 186 case InlineCallFrame::GetterCall: 187 jumpTarget = jit.vm()->getCTIStub(baselineGetterReturnThunkGenerator).code().executableAddress(); 188 break; 189 case InlineCallFrame::SetterCall: 190 jumpTarget = jit.vm()->getCTIStub(baselineSetterReturnThunkGenerator).code().executableAddress(); 191 break; 192 default: 193 RELEASE_ASSERT_NOT_REACHED(); 194 break; 195 } 196 197 trueReturnPC = stubInfo->callReturnLocation.labelAtOffset( 198 stubInfo->patch.deltaCallToDone).executableAddress(); 199 break; 200 } } 201 202 if (trueCaller->inlineCallFrame) { 203 jit.addPtr( 204 AssemblyHelpers::TrustedImm32(trueCaller->inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), 205 GPRInfo::callFrameRegister, 206 GPRInfo::regT3); 207 callerFrameGPR = GPRInfo::regT3; 208 } 209 210 jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset())); 211 } 212 196 213 if (trueReturnPC) 197 214 jit.storePtr(AssemblyHelpers::TrustedImmPtr(trueReturnPC), AssemblyHelpers::addressFor(inlineCallFrame->stackOffset + virtualRegisterForArgument(inlineCallFrame->arguments.size()).offset())); … … 203 220 #if USE(JSVALUE64) 204 221 jit.store64(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame->callerFrameOffset())); 205 uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin .bytecodeIndex);222 uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin->bytecodeIndex); 206 223 jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); 207 224 if (!inlineCallFrame->isClosureCall) … … 209 226 #else // USE(JSVALUE64) // so this is the 32-bit part 210 227 jit.storePtr(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame->callerFrameOffset())); 211 Instruction* instruction = baselineCodeBlock->instructions().begin() + codeOrigin .bytecodeIndex;228 Instruction* instruction = baselineCodeBlock->instructions().begin() + codeOrigin->bytecodeIndex; 212 229 uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction); 213 230 jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); … … 218 235 } 219 236 237 // Don't need to set the toplevel code origin if we only did inline tail calls 238 if (codeOrigin) { 220 239 #if USE(JSVALUE64) 221 uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin.bytecodeIndex);240 uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin->bytecodeIndex); 222 241 #else 223 Instruction* instruction = jit.baselineCodeBlock()->instructions().begin() + codeOrigin.bytecodeIndex; 224 uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction); 225 #endif 226 jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(JSStack::ArgumentCount))); 242 Instruction* instruction = jit.baselineCodeBlock()->instructions().begin() + codeOrigin->bytecodeIndex; 243 uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction); 244 #endif 245 jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(JSStack::ArgumentCount))); 246 } 227 247 } 228 248 -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitPreparation.cpp
r171362 r187791 42 42 DeferGC deferGC(vm.heap); 43 43 44 for (; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame-> caller) {44 for (; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->directCaller) { 45 45 FunctionExecutable* executable = 46 46 static_cast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get()); -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOperations.cpp
r186279 r187791 1277 1277 1278 1278 bool didTryToEnterIntoInlinedLoops = false; 1279 for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame-> caller.inlineCallFrame) {1279 for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) { 1280 1280 if (inlineCallFrame->executable->didTryToEnterInLoop()) { 1281 1281 didTryToEnterIntoInlinedLoops = true; -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h
r184776 r187791 112 112 case ForwardVarargs: 113 113 case CallForwardVarargs: 114 case ConstructForwardVarargs: { 114 case ConstructForwardVarargs: 115 case TailCallForwardVarargs: 116 case TailCallForwardVarargsInlinedCaller: { 115 117 InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame; 116 118 if (!inlineCallFrame) { … … 139 141 140 142 // Read all of the inline arguments and call frame headers that we didn't already capture. 141 for (InlineCallFrame* inlineCallFrame = m_node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame-> caller.inlineCallFrame) {143 for (InlineCallFrame* inlineCallFrame = m_node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->getCallerInlineFrameSkippingDeadFrames()) { 142 144 for (unsigned i = inlineCallFrame->arguments.size(); i-- > 1;) 143 145 m_read(VirtualRegister(inlineCallFrame->stackOffset + virtualRegisterForArgument(i).offset())); -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r184933 r187791 195 195 case GetDirectPname: 196 196 case Call: 197 case TailCallInlinedCaller: 197 198 case Construct: 198 199 case CallVarargs: 200 case TailCallVarargsInlinedCaller: 199 201 case ConstructVarargs: 200 202 case CallForwardVarargs: 201 203 case ConstructForwardVarargs: 204 case TailCallForwardVarargsInlinedCaller: 202 205 case NativeCall: 203 206 case NativeConstruct: … … 631 634 case PutToArguments: 632 635 case Return: 636 case TailCall: 637 case TailCallVarargs: 638 case TailCallForwardVarargs: 633 639 case Throw: 634 640 case PutById: -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r185239 r187791 192 192 case CompareStrictEq: 193 193 case Call: 194 case TailCallInlinedCaller: 194 195 case Construct: 195 196 case CallVarargs: 197 case TailCallVarargsInlinedCaller: 198 case TailCallForwardVarargsInlinedCaller: 196 199 case ConstructVarargs: 197 200 case LoadVarargs: … … 236 239 case Switch: 237 240 case Return: 241 case TailCall: 242 case TailCallVarargs: 243 case TailCallForwardVarargs: 238 244 case Throw: 239 245 case ThrowReferenceError: -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r187639 r187791 645 645 bool isVarargs = false; 646 646 bool isForwardVarargs = false; 647 bool isTail = false; 648 bool isEmulatedTail = false; 647 649 switch (node->op()) { 648 650 case Call: 649 651 callType = CallLinkInfo::Call; 650 652 break; 653 case TailCall: 654 callType = CallLinkInfo::TailCall; 655 isTail = true; 656 break; 657 case TailCallInlinedCaller: 658 callType = CallLinkInfo::Call; 659 isEmulatedTail = true; 660 break; 651 661 case Construct: 652 662 callType = CallLinkInfo::Construct; … … 656 666 isVarargs = true; 657 667 break; 668 case TailCallVarargs: 669 callType = CallLinkInfo::TailCallVarargs; 670 isVarargs = true; 671 isTail = true; 672 break; 673 case TailCallVarargsInlinedCaller: 674 callType = CallLinkInfo::CallVarargs; 675 isVarargs = true; 676 isEmulatedTail = true; 677 break; 658 678 case ConstructVarargs: 659 679 callType = CallLinkInfo::ConstructVarargs; … … 662 682 case CallForwardVarargs: 663 683 callType = CallLinkInfo::CallVarargs; 684 isForwardVarargs = true; 685 break; 686 case TailCallForwardVarargs: 687 callType = CallLinkInfo::TailCallVarargs; 688 isTail = true; 689 isForwardVarargs = true; 690 break; 691 case TailCallForwardVarargsInlinedCaller: 692 callType = CallLinkInfo::CallVarargs; 693 isEmulatedTail = true; 664 694 isForwardVarargs = true; 665 695 break; … … 786 816 m_jit.store32(calleeTagGPR, m_jit.calleeFrameTagSlot(JSStack::Callee)); 787 817 788 flushRegisters(); 818 // FIXME: We should do an efficient move of the arguments into 819 // their target stack position instead of building then memmoving 820 // the callee frame. 821 // https://bugs.webkit.org/show_bug.cgi?id=147508 822 if (isTail) 823 ASSERT(isFlushed()); 824 else 825 flushRegisters(); 789 826 790 827 GPRFlushedCallResult resultPayload(this); … … 796 833 JITCompiler::JumpList slowPath; 797 834 798 m_jit.emitStoreCodeOrigin(node->origin.semantic); 835 CodeOrigin staticOrigin = node->origin.semantic; 836 ASSERT(!isTail || !staticOrigin.inlineCallFrame || !staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames()); 837 ASSERT(!isEmulatedTail || (staticOrigin.inlineCallFrame && staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames())); 838 CodeOrigin dynamicOrigin = 839 isEmulatedTail ? *staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames() : staticOrigin; 840 841 m_jit.emitStoreCodeOrigin(dynamicOrigin); 799 842 800 843 CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo(); … … 803 846 slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck)); 804 847 805 JITCompiler::Call fastCall = m_jit.nearCall(); 848 if (isTail) { 849 m_jit.emitRestoreCalleeSaves(); 850 // FIXME: We should do an efficient move of the arguments into 851 // their target stack position instead of building then memmoving 852 // the callee frame. 853 // https://bugs.webkit.org/show_bug.cgi?id=147508 854 m_jit.prepareForTailCallSlow(); 855 } 856 857 JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall(); 806 858 807 859 JITCompiler::Jump done = m_jit.jump(); … … 826 878 done.link(&m_jit); 827 879 828 m_jit.setupResults(resultPayloadGPR, resultTagGPR); 829 830 jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly); 880 if (isTail) 881 m_jit.breakpoint(); 882 else { 883 m_jit.setupResults(resultPayloadGPR, resultTagGPR); 884 885 jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly); 886 887 // After the calls are done, we need to reestablish our stack 888 // pointer. We rely on this for varargs calls, calls with arity 889 // mismatch (the callframe is slided) and tail calls. 890 m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister); 891 } 831 892 832 893 info->setUpCall(callType, node->origin.semantic, calleePayloadGPR); 833 894 m_jit.addJSCall(fastCall, slowCall, targetToCheck, info); 834 835 // After the calls are done, we need to reestablish our stack 836 // pointer. We rely on this for varargs calls, calls with arity 837 // mismatch (the callframe is slided) and tail calls. 838 m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister); 895 839 896 } 840 897 … … 4220 4277 4221 4278 case Call: 4279 case TailCall: 4280 case TailCallInlinedCaller: 4222 4281 case Construct: 4223 4282 case CallVarargs: 4283 case TailCallVarargs: 4284 case TailCallVarargsInlinedCaller: 4285 case ConstructVarargs: 4224 4286 case CallForwardVarargs: 4225 case ConstructVarargs: 4287 case TailCallForwardVarargs: 4288 case TailCallForwardVarargsInlinedCaller: 4226 4289 case ConstructForwardVarargs: 4227 4290 emitCall(node); -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r187639 r187791 631 631 bool isVarargs = false; 632 632 bool isForwardVarargs = false; 633 bool isTail = false; 634 bool isEmulatedTail = false; 633 635 switch (node->op()) { 634 636 case Call: 635 637 callType = CallLinkInfo::Call; 636 638 break; 639 case TailCall: 640 callType = CallLinkInfo::TailCall; 641 isTail = true; 642 break; 643 case TailCallInlinedCaller: 644 callType = CallLinkInfo::Call; 645 isEmulatedTail = true; 646 break; 637 647 case Construct: 638 648 callType = CallLinkInfo::Construct; … … 642 652 isVarargs = true; 643 653 break; 654 case TailCallVarargs: 655 callType = CallLinkInfo::TailCallVarargs; 656 isVarargs = true; 657 isTail = true; 658 break; 659 case TailCallVarargsInlinedCaller: 660 callType = CallLinkInfo::CallVarargs; 661 isVarargs = true; 662 isEmulatedTail = true; 663 break; 644 664 case ConstructVarargs: 645 665 callType = CallLinkInfo::ConstructVarargs; … … 652 672 case ConstructForwardVarargs: 653 673 callType = CallLinkInfo::ConstructVarargs; 674 isForwardVarargs = true; 675 break; 676 case TailCallForwardVarargs: 677 callType = CallLinkInfo::TailCallVarargs; 678 isTail = true; 679 isForwardVarargs = true; 680 break; 681 case TailCallForwardVarargsInlinedCaller: 682 callType = CallLinkInfo::CallVarargs; 683 isEmulatedTail = true; 654 684 isForwardVarargs = true; 655 685 break; … … 762 792 callee.use(); 763 793 m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(JSStack::Callee)); 764 765 flushRegisters(); 794 795 // FIXME: We should do an efficient move of the arguments into 796 // their target stack position instead of building then memmoving 797 // the callee frame. 798 // https://bugs.webkit.org/show_bug.cgi?id=147508 799 if (isTail) 800 ASSERT(isFlushed()); 801 else 802 flushRegisters(); 766 803 767 804 GPRFlushedCallResult result(this); 768 805 GPRReg resultGPR = result.gpr(); 769 806 807 CodeOrigin staticOrigin = node->origin.semantic; 808 ASSERT(!isTail || !staticOrigin.inlineCallFrame || !staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames()); 809 ASSERT(!isEmulatedTail || (staticOrigin.inlineCallFrame && staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames())); 810 CodeOrigin dynamicOrigin = 811 isEmulatedTail ? *staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames() : staticOrigin; 812 813 m_jit.emitStoreCodeOrigin(dynamicOrigin); 814 815 CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo(); 816 770 817 JITCompiler::DataLabelPtr targetToCheck; 771 JITCompiler::Jump slowPath; 772 773 m_jit.emitStoreCodeOrigin(node->origin.semantic); 774 775 CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo(); 776 777 slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(0)); 778 779 JITCompiler::Call fastCall = m_jit.nearCall(); 818 JITCompiler::Jump slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(0)); 819 820 if (isTail) { 821 m_jit.emitRestoreCalleeSaves(); 822 // FIXME: We should do an efficient move of the arguments into 823 // their target stack position instead of building then memmoving 824 // the callee frame. 825 // https://bugs.webkit.org/show_bug.cgi?id=147508 826 m_jit.prepareForTailCallSlow(); 827 } 828 829 JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall(); 780 830 781 831 JITCompiler::Jump done = m_jit.jump(); … … 786 836 m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2 787 837 JITCompiler::Call slowCall = m_jit.nearCall(); 788 838 789 839 done.link(&m_jit); 790 791 m_jit.move(GPRInfo::returnValueGPR, resultGPR); 792 793 jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly); 794 840 841 if (isTail) 842 m_jit.breakpoint(); 843 else { 844 m_jit.move(GPRInfo::returnValueGPR, resultGPR); 845 846 jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly); 847 848 // After the calls are done, we need to reestablish our stack 849 // pointer. We rely on this for varargs calls, calls with arity 850 // mismatch (the callframe is slided) and tail calls. 851 m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister); 852 } 853 795 854 callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR); 796 855 m_jit.addJSCall(fastCall, slowCall, targetToCheck, callLinkInfo); 797 856 798 // After the calls are done, we need to reestablish our stack799 // pointer. We rely on this for varargs calls, calls with arity800 // mismatch (the callframe is slided) and tail calls.801 m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);802 857 } 803 858 … … 4232 4287 4233 4288 case Call: 4289 case TailCall: 4290 case TailCallInlinedCaller: 4234 4291 case Construct: 4235 4292 case CallVarargs: 4293 case TailCallVarargs: 4294 case TailCallVarargsInlinedCaller: 4236 4295 case CallForwardVarargs: 4237 4296 case ConstructVarargs: 4238 4297 case ConstructForwardVarargs: 4298 case TailCallForwardVarargs: 4299 case TailCallForwardVarargsInlinedCaller: 4239 4300 emitCall(node); 4240 4301 break; 4241 4302 4242 4303 case LoadVarargs: { 4243 4304 LoadVarargsData* data = node->loadVarargsData(); -
branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp
r184288 r187791 136 136 case CallVarargs: 137 137 case ConstructVarargs: 138 case TailCallVarargs: 139 case TailCallVarargsInlinedCaller: 138 140 if (node->child1() == candidate || node->child3() == candidate) { 139 141 if (verbose) … … 283 285 node->setOpAndDefaultFlags(ConstructForwardVarargs); 284 286 break; 285 287 288 case TailCallVarargs: 289 if (node->child2() != candidate) 290 break; 291 node->setOpAndDefaultFlags(TailCallForwardVarargs); 292 break; 293 294 case TailCallVarargsInlinedCaller: 295 if (node->child2() != candidate) 296 break; 297 node->setOpAndDefaultFlags(TailCallForwardVarargsInlinedCaller); 298 break; 299 286 300 case SetLocal: 287 301 // This is super odd. We don't have to do anything here, since in DFG IR, the phantom -
branches/jsc-tailcall/Source/JavaScriptCore/interpreter/CallFrame.cpp
r178143 r187791 86 86 return codeOrigin.bytecodeIndex; 87 87 88 codeOrigin = inlineCallFrame->caller;88 codeOrigin = *inlineCallFrame->getCallerSkippingDeadFrames(); 89 89 inlineCallFrame = codeOrigin.inlineCallFrame; 90 90 } -
branches/jsc-tailcall/Source/JavaScriptCore/interpreter/StackVisitor.cpp
r182934 r187791 60 60 if (m_frame.isInlinedFrame()) { 61 61 InlineCallFrame* inlineCallFrame = m_frame.inlineCallFrame(); 62 CodeOrigin* callerCodeOrigin = &inlineCallFrame->caller; 63 readInlinedFrame(m_frame.callFrame(), callerCodeOrigin); 62 CodeOrigin* callerCodeOrigin = inlineCallFrame->getCallerSkippingDeadFrames(); 63 if (!callerCodeOrigin) { 64 while (inlineCallFrame) { 65 readInlinedFrame(m_frame.callFrame(), &inlineCallFrame->directCaller); 66 inlineCallFrame = m_frame.inlineCallFrame(); 67 } 68 m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame; 69 readFrame(m_frame.callerFrame()); 70 } else 71 readInlinedFrame(m_frame.callFrame(), callerCodeOrigin); 64 72 return; 65 73 } -
branches/jsc-tailcall/Source/JavaScriptCore/jit/CCallHelpers.h
r187676 r187791 2068 2068 COMPILE_ASSERT(sizeof(void*) * 2 == sizeof(Register), Register_is_two_pointers_sized); 2069 2069 lshift32(TrustedImm32(1), temp2); 2070 #else 2071 COMPILE_ASSERT(sizeof(void*) == sizeof(Register), Register_is_one_pointer_sized); 2070 2072 #endif 2071 2073
Note: See TracChangeset
for help on using the changeset viewer.