|
Lines 176-193
private:
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec1
|
| 176 |
// Helper for min and max. |
176 |
// Helper for min and max. |
| 177 |
template<typename ChecksFunctor> |
177 |
template<typename ChecksFunctor> |
| 178 |
bool handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& insertChecks); |
178 |
bool handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& insertChecks); |
| 179 |
|
179 |
|
| 180 |
// Handle calls. This resolves issues surrounding inlining and intrinsics. |
180 |
// Handle calls. This resolves issues surrounding inlining and intrinsics. |
| 181 |
void handleCall( |
181 |
enum Terminality { Terminal, NonTerminal }; |
|
|
182 |
Terminality handleCall( |
| 182 |
int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize, |
183 |
int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize, |
| 183 |
Node* callTarget, int argCount, int registerOffset, CallLinkStatus, |
184 |
Node* callTarget, int argCount, int registerOffset, CallLinkStatus, |
| 184 |
SpeculatedType prediction); |
185 |
SpeculatedType prediction); |
| 185 |
void handleCall( |
186 |
Terminality handleCall( |
| 186 |
int result, NodeType op, CallMode, unsigned instructionSize, |
187 |
int result, NodeType op, CallMode, unsigned instructionSize, |
| 187 |
Node* callTarget, int argCount, int registerOffset, CallLinkStatus); |
188 |
Node* callTarget, int argCount, int registerOffset, CallLinkStatus); |
| 188 |
void handleCall(int result, NodeType op, CallMode, unsigned instructionSize, int callee, int argCount, int registerOffset); |
189 |
Terminality handleCall(int result, NodeType op, CallMode, unsigned instructionSize, int callee, int argCount, int registerOffset); |
| 189 |
void handleCall(Instruction* pc, NodeType op, CallMode); |
190 |
Terminality handleCall(Instruction* pc, NodeType op, CallMode); |
| 190 |
void handleVarargsCall(Instruction* pc, NodeType op, CallMode); |
191 |
Terminality handleVarargsCall(Instruction* pc, NodeType op, CallMode); |
| 191 |
void emitFunctionChecks(CallVariant, Node* callTarget, VirtualRegister thisArgumnt); |
192 |
void emitFunctionChecks(CallVariant, Node* callTarget, VirtualRegister thisArgumnt); |
| 192 |
void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis); |
193 |
void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis); |
| 193 |
unsigned inliningCost(CallVariant, int argumentCountIncludingThis, CallMode); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1. |
194 |
unsigned inliningCost(CallVariant, int argumentCountIncludingThis, CallMode); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1. |
|
Lines 1131-1146
private:
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec2
|
| 1131 |
m_exitOK = false; \ |
1132 |
m_exitOK = false; \ |
| 1132 |
return shouldContinueParsing |
1133 |
return shouldContinueParsing |
| 1133 |
|
1134 |
|
| 1134 |
void ByteCodeParser::handleCall(Instruction* pc, NodeType op, CallMode callMode) |
1135 |
ByteCodeParser::Terminality ByteCodeParser::handleCall(Instruction* pc, NodeType op, CallMode callMode) |
| 1135 |
{ |
1136 |
{ |
| 1136 |
ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); |
1137 |
ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); |
| 1137 |
ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_tail_call)); |
1138 |
ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_tail_call)); |
| 1138 |
handleCall( |
1139 |
return handleCall( |
| 1139 |
pc[1].u.operand, op, callMode, OPCODE_LENGTH(op_call), |
1140 |
pc[1].u.operand, op, callMode, OPCODE_LENGTH(op_call), |
| 1140 |
pc[2].u.operand, pc[3].u.operand, -pc[4].u.operand); |
1141 |
pc[2].u.operand, pc[3].u.operand, -pc[4].u.operand); |
| 1141 |
} |
1142 |
} |
| 1142 |
|
1143 |
|
| 1143 |
void ByteCodeParser::handleCall( |
1144 |
ByteCodeParser::Terminality ByteCodeParser::handleCall( |
| 1144 |
int result, NodeType op, CallMode callMode, unsigned instructionSize, |
1145 |
int result, NodeType op, CallMode callMode, unsigned instructionSize, |
| 1145 |
int callee, int argumentCountIncludingThis, int registerOffset) |
1146 |
int callee, int argumentCountIncludingThis, int registerOffset) |
| 1146 |
{ |
1147 |
{ |
|
Lines 1150-1171
void ByteCodeParser::handleCall(
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec3
|
| 1150 |
m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), |
1151 |
m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), |
| 1151 |
m_inlineStackTop->m_callLinkInfos, m_callContextMap); |
1152 |
m_inlineStackTop->m_callLinkInfos, m_callContextMap); |
| 1152 |
|
1153 |
|
| 1153 |
handleCall( |
1154 |
return handleCall( |
| 1154 |
result, op, callMode, instructionSize, callTarget, |
1155 |
result, op, callMode, instructionSize, callTarget, |
| 1155 |
argumentCountIncludingThis, registerOffset, callLinkStatus); |
1156 |
argumentCountIncludingThis, registerOffset, callLinkStatus); |
| 1156 |
} |
1157 |
} |
| 1157 |
|
1158 |
|
| 1158 |
void ByteCodeParser::handleCall( |
1159 |
ByteCodeParser::Terminality ByteCodeParser::handleCall( |
| 1159 |
int result, NodeType op, CallMode callMode, unsigned instructionSize, |
1160 |
int result, NodeType op, CallMode callMode, unsigned instructionSize, |
| 1160 |
Node* callTarget, int argumentCountIncludingThis, int registerOffset, |
1161 |
Node* callTarget, int argumentCountIncludingThis, int registerOffset, |
| 1161 |
CallLinkStatus callLinkStatus) |
1162 |
CallLinkStatus callLinkStatus) |
| 1162 |
{ |
1163 |
{ |
| 1163 |
handleCall( |
1164 |
return handleCall( |
| 1164 |
result, op, InlineCallFrame::kindFor(callMode), instructionSize, callTarget, argumentCountIncludingThis, |
1165 |
result, op, InlineCallFrame::kindFor(callMode), instructionSize, callTarget, argumentCountIncludingThis, |
| 1165 |
registerOffset, callLinkStatus, getPrediction()); |
1166 |
registerOffset, callLinkStatus, getPrediction()); |
| 1166 |
} |
1167 |
} |
| 1167 |
|
1168 |
|
| 1168 |
void ByteCodeParser::handleCall( |
1169 |
ByteCodeParser::Terminality ByteCodeParser::handleCall( |
| 1169 |
int result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize, |
1170 |
int result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize, |
| 1170 |
Node* callTarget, int argumentCountIncludingThis, int registerOffset, |
1171 |
Node* callTarget, int argumentCountIncludingThis, int registerOffset, |
| 1171 |
CallLinkStatus callLinkStatus, SpeculatedType prediction) |
1172 |
CallLinkStatus callLinkStatus, SpeculatedType prediction) |
|
Lines 1182-1189
void ByteCodeParser::handleCall(
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec4
|
| 1182 |
// Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically |
1183 |
// Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically |
| 1183 |
// that we cannot optimize them. |
1184 |
// that we cannot optimize them. |
| 1184 |
|
1185 |
|
| 1185 |
addCall(result, op, OpInfo(), callTarget, argumentCountIncludingThis, registerOffset, prediction); |
1186 |
Node* callNode = addCall(result, op, OpInfo(), callTarget, argumentCountIncludingThis, registerOffset, prediction); |
| 1186 |
return; |
1187 |
if (callNode->op() == TailCall) |
|
|
1188 |
return Terminal; |
| 1189 |
ASSERT(callNode->op() != TailCallVarargs); |
| 1190 |
return NonTerminal; |
| 1187 |
} |
1191 |
} |
| 1188 |
|
1192 |
|
| 1189 |
unsigned nextOffset = m_currentIndex + instructionSize; |
1193 |
unsigned nextOffset = m_currentIndex + instructionSize; |
|
Lines 1193-1205
void ByteCodeParser::handleCall(
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec5
|
| 1193 |
if (handleInlining(callTarget, result, callLinkStatus, registerOffset, virtualRegisterForArgument(0, registerOffset), VirtualRegister(), 0, argumentCountIncludingThis, nextOffset, op, kind, prediction)) { |
1197 |
if (handleInlining(callTarget, result, callLinkStatus, registerOffset, virtualRegisterForArgument(0, registerOffset), VirtualRegister(), 0, argumentCountIncludingThis, nextOffset, op, kind, prediction)) { |
| 1194 |
if (m_graph.compilation()) |
1198 |
if (m_graph.compilation()) |
| 1195 |
m_graph.compilation()->noticeInlinedCall(); |
1199 |
m_graph.compilation()->noticeInlinedCall(); |
| 1196 |
return; |
1200 |
return NonTerminal; |
| 1197 |
} |
1201 |
} |
| 1198 |
|
1202 |
|
| 1199 |
addCall(result, op, callOpInfo, callTarget, argumentCountIncludingThis, registerOffset, prediction); |
1203 |
Node* callNode = addCall(result, op, callOpInfo, callTarget, argumentCountIncludingThis, registerOffset, prediction); |
|
|
1204 |
if (callNode->op() == TailCall) |
| 1205 |
return Terminal; |
| 1206 |
ASSERT(callNode->op() != TailCallVarargs); |
| 1207 |
return NonTerminal; |
| 1200 |
} |
1208 |
} |
| 1201 |
|
1209 |
|
| 1202 |
void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CallMode callMode) |
1210 |
ByteCodeParser::Terminality ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CallMode callMode) |
| 1203 |
{ |
1211 |
{ |
| 1204 |
ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_construct_varargs)); |
1212 |
ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_construct_varargs)); |
| 1205 |
ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_tail_call_varargs)); |
1213 |
ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_tail_call_varargs)); |
|
Lines 1228-1234
void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CallMode ca
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec6
|
| 1228 |
&& handleInlining(callTarget, result, callLinkStatus, firstFreeReg, VirtualRegister(thisReg), VirtualRegister(arguments), firstVarArgOffset, 0, m_currentIndex + OPCODE_LENGTH(op_call_varargs), op, InlineCallFrame::varargsKindFor(callMode), prediction)) { |
1236 |
&& handleInlining(callTarget, result, callLinkStatus, firstFreeReg, VirtualRegister(thisReg), VirtualRegister(arguments), firstVarArgOffset, 0, m_currentIndex + OPCODE_LENGTH(op_call_varargs), op, InlineCallFrame::varargsKindFor(callMode), prediction)) { |
| 1229 |
if (m_graph.compilation()) |
1237 |
if (m_graph.compilation()) |
| 1230 |
m_graph.compilation()->noticeInlinedCall(); |
1238 |
m_graph.compilation()->noticeInlinedCall(); |
| 1231 |
return; |
1239 |
return NonTerminal; |
| 1232 |
} |
1240 |
} |
| 1233 |
|
1241 |
|
| 1234 |
CallVarargsData* data = m_graph.m_callVarargsData.add(); |
1242 |
CallVarargsData* data = m_graph.m_callVarargsData.add(); |
|
Lines 1239-1245
void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CallMode ca
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec7
|
| 1239 |
if (op == TailCallVarargs) { |
1247 |
if (op == TailCallVarargs) { |
| 1240 |
if (allInlineFramesAreTailCalls()) { |
1248 |
if (allInlineFramesAreTailCalls()) { |
| 1241 |
addToGraph(op, OpInfo(data), OpInfo(), callTarget, get(VirtualRegister(arguments)), thisChild); |
1249 |
addToGraph(op, OpInfo(data), OpInfo(), callTarget, get(VirtualRegister(arguments)), thisChild); |
| 1242 |
return; |
1250 |
return Terminal; |
| 1243 |
} |
1251 |
} |
| 1244 |
op = TailCallVarargsInlinedCaller; |
1252 |
op = TailCallVarargsInlinedCaller; |
| 1245 |
} |
1253 |
} |
|
Lines 1248-1253
void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CallMode ca
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec8
|
| 1248 |
VirtualRegister resultReg(result); |
1256 |
VirtualRegister resultReg(result); |
| 1249 |
if (resultReg.isValid()) |
1257 |
if (resultReg.isValid()) |
| 1250 |
set(resultReg, call); |
1258 |
set(resultReg, call); |
|
|
1259 |
return NonTerminal; |
| 1251 |
} |
1260 |
} |
| 1252 |
|
1261 |
|
| 1253 |
void ByteCodeParser::emitFunctionChecks(CallVariant callee, Node* callTarget, VirtualRegister thisArgumentReg) |
1262 |
void ByteCodeParser::emitFunctionChecks(CallVariant callee, Node* callTarget, VirtualRegister thisArgumentReg) |
|
Lines 3180-3188
bool ByteCodeParser::parseBlock(unsigned limit)
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec9
|
| 3180 |
// to be true. |
3189 |
// to be true. |
| 3181 |
// We also don't insert a jump if the block already has a terminal, |
3190 |
// We also don't insert a jump if the block already has a terminal, |
| 3182 |
// which could happen after a tail call. |
3191 |
// which could happen after a tail call. |
| 3183 |
ASSERT(m_currentBlock->isEmpty() || !m_currentBlock->terminal() |
3192 |
ASSERT(m_currentBlock->isEmpty() || !m_currentBlock->terminal()); |
| 3184 |
|| m_currentBlock->terminal()->op() == TailCall || m_currentBlock->terminal()->op() == TailCallVarargs); |
3193 |
if (!m_currentBlock->isEmpty()) |
| 3185 |
if (!m_currentBlock->isEmpty() && !m_currentBlock->terminal()) |
|
|
| 3186 |
addToGraph(Jump, OpInfo(m_currentIndex)); |
3194 |
addToGraph(Jump, OpInfo(m_currentIndex)); |
| 3187 |
return shouldContinueParsing; |
3195 |
return shouldContinueParsing; |
| 3188 |
} |
3196 |
} |
|
Lines 3796-3807
bool ByteCodeParser::parseBlock(unsigned limit)
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec10
|
| 3796 |
// === Block terminators. === |
3804 |
// === Block terminators. === |
| 3797 |
|
3805 |
|
| 3798 |
case op_jmp: { |
3806 |
case op_jmp: { |
| 3799 |
if (m_currentBlock->terminal()) { |
3807 |
ASSERT(!m_currentBlock->terminal()); |
| 3800 |
// We could be the dummy jump to a return after a non-inlined, non-emulated tail call in a ternary operator |
|
|
| 3801 |
Node* terminal = m_currentBlock->terminal(); |
| 3802 |
ASSERT_UNUSED(terminal, terminal->op() == TailCall || terminal->op() == TailCallVarargs); |
| 3803 |
LAST_OPCODE(op_jmp); |
| 3804 |
} |
| 3805 |
int relativeOffset = currentInstruction[1].u.operand; |
3808 |
int relativeOffset = currentInstruction[1].u.operand; |
| 3806 |
addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset)); |
3809 |
addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset)); |
| 3807 |
if (relativeOffset <= 0) |
3810 |
if (relativeOffset <= 0) |
|
Lines 3973-3984
bool ByteCodeParser::parseBlock(unsigned limit)
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec11
|
| 3973 |
} |
3976 |
} |
| 3974 |
|
3977 |
|
| 3975 |
case op_ret: |
3978 |
case op_ret: |
| 3976 |
if (m_currentBlock->terminal()) { |
3979 |
ASSERT(!m_currentBlock->terminal()); |
| 3977 |
// We could be the dummy return after a non-inlined, non-emulated tail call |
|
|
| 3978 |
Node* terminal = m_currentBlock->terminal(); |
| 3979 |
ASSERT_UNUSED(terminal, terminal->op() == TailCall || terminal->op() == TailCallVarargs); |
| 3980 |
LAST_OPCODE(op_ret); |
| 3981 |
} |
| 3982 |
if (inlineCallFrame()) { |
3980 |
if (inlineCallFrame()) { |
| 3983 |
flushForReturn(); |
3981 |
flushForReturn(); |
| 3984 |
if (m_inlineStackTop->m_returnValue.isValid()) |
3982 |
if (m_inlineStackTop->m_returnValue.isValid()) |
|
Lines 4031-4048
bool ByteCodeParser::parseBlock(unsigned limit)
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec12
|
| 4031 |
|
4029 |
|
| 4032 |
case op_call: |
4030 |
case op_call: |
| 4033 |
handleCall(currentInstruction, Call, CallMode::Regular); |
4031 |
handleCall(currentInstruction, Call, CallMode::Regular); |
| 4034 |
// Verify that handleCall(), which could have inlined the callee, didn't trash m_currentInstruction |
4032 |
// Verify that handleCall(), which could have inlined the callee, didn't trash m_currentInstruction. |
| 4035 |
ASSERT(m_currentInstruction == currentInstruction); |
4033 |
ASSERT(m_currentInstruction == currentInstruction); |
| 4036 |
NEXT_OPCODE(op_call); |
4034 |
NEXT_OPCODE(op_call); |
| 4037 |
|
4035 |
|
| 4038 |
case op_tail_call: |
4036 |
case op_tail_call: { |
| 4039 |
flushForReturn(); |
4037 |
flushForReturn(); |
| 4040 |
handleCall(currentInstruction, TailCall, CallMode::Tail); |
4038 |
Terminality terminality = handleCall(currentInstruction, TailCall, CallMode::Tail); |
| 4041 |
// Verify that handleCall(), which could have inlined the callee, didn't trash m_currentInstruction |
4039 |
// Verify that handleCall(), which could have inlined the callee, didn't trash m_currentInstruction. |
| 4042 |
ASSERT(m_currentInstruction == currentInstruction); |
4040 |
ASSERT(m_currentInstruction == currentInstruction); |
| 4043 |
// We let the following op_ret handle cases related to |
4041 |
// If the call is terminal then we should not parse any further bytecodes as the TailCall will exit the function. |
| 4044 |
// inlining to keep things simple. |
4042 |
// If the call is not terminal, however, then we want the subsequent op_ret/op_jumpt to update metadata and clean |
| 4045 |
NEXT_OPCODE(op_tail_call); |
4043 |
// things up. |
|
|
4044 |
if (terminality == NonTerminal) { |
| 4045 |
NEXT_OPCODE(op_tail_call); |
| 4046 |
} else { |
| 4047 |
LAST_OPCODE(op_tail_call); |
| 4048 |
} |
| 4049 |
} |
| 4046 |
|
4050 |
|
| 4047 |
case op_construct: |
4051 |
case op_construct: |
| 4048 |
handleCall(currentInstruction, Construct, CallMode::Construct); |
4052 |
handleCall(currentInstruction, Construct, CallMode::Construct); |
|
Lines 4055-4062
bool ByteCodeParser::parseBlock(unsigned limit)
a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec13
|
| 4055 |
|
4059 |
|
| 4056 |
case op_tail_call_varargs: { |
4060 |
case op_tail_call_varargs: { |
| 4057 |
flushForReturn(); |
4061 |
flushForReturn(); |
| 4058 |
handleVarargsCall(currentInstruction, TailCallVarargs, CallMode::Tail); |
4062 |
Terminality terminality = handleVarargsCall(currentInstruction, TailCallVarargs, CallMode::Tail); |
| 4059 |
NEXT_OPCODE(op_tail_call_varargs); |
4063 |
// If the call is terminal then we should not parse any further bytecodes as the TailCall will exit the function. |
|
|
4064 |
// If the call is not terminal, however, then we want the subsequent op_ret/op_jumpt to update metadata and clean |
| 4065 |
// things up. |
| 4066 |
if (terminality == NonTerminal) { |
| 4067 |
NEXT_OPCODE(op_tail_call_varargs); |
| 4068 |
} else { |
| 4069 |
LAST_OPCODE(op_tail_call_varargs); |
| 4070 |
} |
| 4060 |
} |
4071 |
} |
| 4061 |
|
4072 |
|
| 4062 |
case op_construct_varargs: { |
4073 |
case op_construct_varargs: { |