Commit cf0e6c40 authored by oliver@apple.com's avatar oliver@apple.com

fourthTier: get rid of op_call_put_result

https://bugs.webkit.org/show_bug.cgi?id=117047

Reviewed by Gavin Barraclough.

Work in progress. This still makes like 20 tests crash.

op_call_put_result is an oddball. Its semantics are that it takes the return
value of a call instruction, which is set aside in regT0/regT1, and places them
into some stack slot. This is weird since there is an implicit contract with the
preceding bytecode instruction, and it's even weirder since it means that it
doesn't make sense to jump to it; for example OSR exit from the preceding call
instruction must make sure to jump over the op_call_put_result.

So this patch gets rid of op_call_put_result:

- In bytecode, all calls return a value and we always allocate a temporary for
  that value even if it isn't used.

- The LLInt does the return value saving as part of dispatchAfterCall().

- The JIT and DFG do the return value saving as part of normal code generation.
  The DFG already did the right thing.

- DFG->JIT OSR exit in the case of inlining will make the return PC's point at
  the CallLinkInfo::callReturnLocation, rather than the machine PC associated
  with the op_call_put_result instruction.

- Tons of code gets removed. The DFG had to track whether or not a call had a
  return value in a bunch of places. It had to track the fact that we would
  exit to after the op_call_put_result. It was a mess. That mess is now gone.

* bytecode/CallLinkStatus.cpp:
(JSC::CallLinkStatus::computeFromLLInt):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printCallOp):
(JSC::CodeBlock::dumpArrayProfiling):
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::emitCallVarargs):
(JSC::BytecodeGenerator::emitConstruct):
* bytecompiler/NodesCodegen.cpp:
(JSC::NewExprNode::emitBytecode):
(JSC::FunctionCallValueNode::emitBytecode):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::FunctionCallBracketNode::emitBytecode):
(JSC::FunctionCallDotNode::emitBytecode):
(JSC::CallFunctionCallDotNode::emitBytecode):
(JSC::ApplyFunctionCallDotNode::emitBytecode):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::ByteCodeParser):
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::currentCodeOrigin):
(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
(JSC::DFG::ByteCodeParser::getPrediction):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::handleMinMax):
(JSC::DFG::ByteCodeParser::handleIntrinsic):
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGOSRExitCompiler.cpp:
* dfg/DFGOSRExitCompilerCommon.cpp:
(JSC::DFG::reifyInlinedCallFrames):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
(JIT):
* jit/JITCall.cpp:
(JSC::JIT::emitPutCallResult):
(JSC::JIT::compileLoadVarargs):
(JSC::JIT::compileCallEval):
(JSC::JIT::compileCallEvalSlowCase):
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):
(JSC::JIT::emit_op_call):
(JSC):
(JSC::JIT::emit_op_call_eval):
(JSC::JIT::emit_op_call_varargs):
(JSC::JIT::emit_op_construct):
(JSC::JIT::emitSlow_op_call):
(JSC::JIT::emitSlow_op_call_eval):
(JSC::JIT::emitSlow_op_call_varargs):
(JSC::JIT::emitSlow_op_construct):
* jit/JITCall32_64.cpp:
(JSC::JIT::emitPutCallResult):
(JSC::JIT::compileLoadVarargs):
(JSC::JIT::compileCallEval):
(JSC::JIT::compileCallEvalSlowCase):
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):
* jit/JITOpcodes.cpp:
(JSC):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::genericCall):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter.cpp:
(JSC::CLoop::execute):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153200 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent dc48dc36
2013-05-31 Filip Pizlo <fpizlo@apple.com>
fourthTier: get rid of op_call_put_result
https://bugs.webkit.org/show_bug.cgi?id=117047
Reviewed by Gavin Barraclough.
Work in progress. This still makes like 20 tests crash.
op_call_put_result is an oddball. Its semantics are that it takes the return
value of a call instruction, which is set aside in regT0/regT1, and places them
into some stack slot. This is weird since there is an implicit contract with the
preceding bytecode instruction, and it's even weirder since it means that it
doesn't make sense to jump to it; for example OSR exit from the preceding call
instruction must make sure to jump over the op_call_put_result.
So this patch gets rid of op_call_put_result:
- In bytecode, all calls return a value and we always allocate a temporary for
that value even if it isn't used.
- The LLInt does the return value saving as part of dispatchAfterCall().
- The JIT and DFG do the return value saving as part of normal code generation.
The DFG already did the right thing.
- DFG->JIT OSR exit in the case of inlining will make the return PC's point at
the CallLinkInfo::callReturnLocation, rather than the machine PC associated
with the op_call_put_result instruction.
- Tons of code gets removed. The DFG had to track whether or not a call had a
return value in a bunch of places. It had to track the fact that we would
exit to after the op_call_put_result. It was a mess. That mess is now gone.
* bytecode/CallLinkStatus.cpp:
(JSC::CallLinkStatus::computeFromLLInt):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printCallOp):
(JSC::CodeBlock::dumpArrayProfiling):
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::emitCallVarargs):
(JSC::BytecodeGenerator::emitConstruct):
* bytecompiler/NodesCodegen.cpp:
(JSC::NewExprNode::emitBytecode):
(JSC::FunctionCallValueNode::emitBytecode):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::FunctionCallBracketNode::emitBytecode):
(JSC::FunctionCallDotNode::emitBytecode):
(JSC::CallFunctionCallDotNode::emitBytecode):
(JSC::ApplyFunctionCallDotNode::emitBytecode):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::ByteCodeParser):
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::currentCodeOrigin):
(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
(JSC::DFG::ByteCodeParser::getPrediction):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::handleMinMax):
(JSC::DFG::ByteCodeParser::handleIntrinsic):
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGOSRExitCompiler.cpp:
* dfg/DFGOSRExitCompilerCommon.cpp:
(JSC::DFG::reifyInlinedCallFrames):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
(JIT):
* jit/JITCall.cpp:
(JSC::JIT::emitPutCallResult):
(JSC::JIT::compileLoadVarargs):
(JSC::JIT::compileCallEval):
(JSC::JIT::compileCallEvalSlowCase):
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):
(JSC::JIT::emit_op_call):
(JSC):
(JSC::JIT::emit_op_call_eval):
(JSC::JIT::emit_op_call_varargs):
(JSC::JIT::emit_op_construct):
(JSC::JIT::emitSlow_op_call):
(JSC::JIT::emitSlow_op_call_eval):
(JSC::JIT::emitSlow_op_call_varargs):
(JSC::JIT::emitSlow_op_construct):
* jit/JITCall32_64.cpp:
(JSC::JIT::emitPutCallResult):
(JSC::JIT::compileLoadVarargs):
(JSC::JIT::compileCallEval):
(JSC::JIT::compileCallEvalSlowCase):
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):
* jit/JITOpcodes.cpp:
(JSC):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::genericCall):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter.cpp:
(JSC::CLoop::execute):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
2013-05-30 Filip Pizlo <fpizlo@apple.com>
fourthTier: LLInt shouldn't store an offset call PC during op_call-like calls
......
......@@ -87,7 +87,7 @@ CallLinkStatus CallLinkStatus::computeFromLLInt(CodeBlock* profiledBlock, unsign
UNUSED_PARAM(bytecodeIndex);
#if ENABLE(LLINT)
Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex;
LLIntCallLinkInfo* callLinkInfo = instruction[4].u.callLinkInfo;
LLIntCallLinkInfo* callLinkInfo = instruction[5].u.callLinkInfo;
return CallLinkStatus(callLinkInfo->lastSeenCallee.get());
#else
......
......@@ -417,12 +417,13 @@ void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int l
#endif
}
void CodeBlock::printCallOp(PrintStream& out, ExecState*, int location, const Instruction*& it, const char* op, CacheDumpMode cacheDumpMode)
void CodeBlock::printCallOp(PrintStream& out, ExecState*, int location, const Instruction*& it, const char* op, CacheDumpMode cacheDumpMode, bool& hasPrintedProfiling)
{
int dst = (++it)->u.operand;
int func = (++it)->u.operand;
int argCount = (++it)->u.operand;
int registerOffset = (++it)->u.operand;
out.printf("[%4d] %s\t %s, %d, %d", location, op, registerName(func).data(), argCount, registerOffset);
out.printf("[%4d] %s %s, %s, %d, %d", location, op, registerName(dst).data(), registerName(func).data(), argCount, registerOffset);
if (cacheDumpMode == DumpCaches) {
#if ENABLE(LLINT)
LLIntCallLinkInfo* callLinkInfo = it[1].u.callLinkInfo;
......@@ -442,7 +443,9 @@ void CodeBlock::printCallOp(PrintStream& out, ExecState*, int location, const In
#endif
out.print(" status(", CallLinkStatus::computeFor(this, location), ")");
}
it += 2;
++it;
dumpArrayProfiling(out, it, hasPrintedProfiling);
dumpValueProfiling(out, it, hasPrintedProfiling);
}
void CodeBlock::printPutByIdOp(PrintStream& out, ExecState*, int location, const Instruction*& it, const char* op)
......@@ -662,6 +665,8 @@ void CodeBlock::dumpArrayProfiling(PrintStream& out, const Instruction*& it, boo
++it;
#if ENABLE(VALUE_PROFILER)
if (!it->u.arrayProfile)
return;
CString description = it->u.arrayProfile->briefDescription(locker, this);
if (!description.length())
return;
......@@ -1275,20 +1280,22 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
break;
}
case op_call: {
printCallOp(out, exec, location, it, "call", DumpCaches);
printCallOp(out, exec, location, it, "call", DumpCaches, hasPrintedProfiling);
break;
}
case op_call_eval: {
printCallOp(out, exec, location, it, "call_eval", DontDumpCaches);
printCallOp(out, exec, location, it, "call_eval", DontDumpCaches, hasPrintedProfiling);
break;
}
case op_call_varargs: {
int result = (++it)->u.operand;
int callee = (++it)->u.operand;
int thisValue = (++it)->u.operand;
int arguments = (++it)->u.operand;
int firstFreeRegister = (++it)->u.operand;
++it;
out.printf("[%4d] call_varargs\t %s, %s, %s, %d", location, registerName(callee).data(), registerName(thisValue).data(), registerName(arguments).data(), firstFreeRegister);
out.printf("[%4d] call_varargs\t %s, %s, %s, %s, %d", location, registerName(result).data(), registerName(callee).data(), registerName(thisValue).data(), registerName(arguments).data(), firstFreeRegister);
dumpValueProfiling(out, it, hasPrintedProfiling);
break;
}
case op_tear_off_activation: {
......@@ -1307,12 +1314,6 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
out.printf("[%4d] ret\t\t %s", location, registerName(r0).data());
break;
}
case op_call_put_result: {
int r0 = (++it)->u.operand;
out.printf("[%4d] call_put_result\t\t %s", location, registerName(r0).data());
dumpValueProfiling(out, it, hasPrintedProfiling);
break;
}
case op_ret_object_or_this: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
......@@ -1320,7 +1321,7 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
break;
}
case op_construct: {
printCallOp(out, exec, location, it, "construct", DumpCaches);
printCallOp(out, exec, location, it, "construct", DumpCaches, hasPrintedProfiling);
break;
}
case op_strcat: {
......@@ -1783,7 +1784,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
}
case op_to_this:
case op_get_by_id:
case op_call_put_result:
case op_call_varargs:
case op_get_callee: {
ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand];
ASSERT(profile->m_bytecodeOffset == -1);
......@@ -1883,20 +1884,31 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
case op_call:
case op_call_eval: {
#if ENABLE(DFG_JIT)
int arrayProfileIndex = pc[i + opLength - 1].u.operand;
ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand];
ASSERT(profile->m_bytecodeOffset == -1);
profile->m_bytecodeOffset = i;
instructions[i + opLength - 1] = profile;
int arrayProfileIndex = pc[i + opLength - 2].u.operand;
m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i);
instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex];
instructions[i + opLength - 2] = &m_arrayProfiles[arrayProfileIndex];
#endif
#if ENABLE(LLINT)
instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand];
instructions[i + 5] = &m_llintCallLinkInfos[pc[i + 5].u.operand];
#endif
break;
}
case op_construct:
case op_construct: {
#if ENABLE(LLINT)
instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand];
instructions[i + 5] = &m_llintCallLinkInfos[pc[i + 5].u.operand];
#endif
#if ENABLE(DFG_JIT)
ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand];
ASSERT(profile->m_bytecodeOffset == -1);
profile->m_bytecodeOffset = i;
instructions[i + opLength - 1] = profile;
#endif
break;
}
case op_get_by_id_out_of_line:
case op_get_by_id_self:
case op_get_by_id_proto:
......
......@@ -965,7 +965,7 @@ private:
void printGetByIdOp(PrintStream&, ExecState*, int location, const Instruction*&);
void printGetByIdCacheStatus(PrintStream&, ExecState*, int location);
enum CacheDumpMode { DumpCaches, DontDumpCaches };
void printCallOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode);
void printCallOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode, bool& hasPrintedProfiling);
void printPutByIdOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
void beginDumpProfiling(PrintStream&, bool& hasPrintedProfiling);
void dumpValueProfiling(PrintStream&, const Instruction*&, bool& hasPrintedProfiling);
......
......@@ -177,16 +177,15 @@ namespace JSC {
\
macro(op_new_func, 4) \
macro(op_new_func_exp, 3) \
macro(op_call, 6) \
macro(op_call_eval, 6) \
macro(op_call_varargs, 6) \
macro(op_call, 8) /* has value profiling */ \
macro(op_call_eval, 8) /* has value profiling */ \
macro(op_call_varargs, 8) /* has value profiling */ \
macro(op_tear_off_activation, 2) \
macro(op_tear_off_arguments, 3) \
macro(op_ret, 2) \
macro(op_call_put_result, 3) /* has value profiling */ \
macro(op_ret_object_or_this, 3) \
\
macro(op_construct, 6) \
macro(op_construct, 8) \
macro(op_strcat, 4) \
macro(op_to_primitive, 3) \
\
......
......@@ -1845,7 +1845,10 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi
// Emit call.
UnlinkedArrayProfile arrayProfile = newArrayProfile();
emitOpcode(opcodeID);
UnlinkedValueProfile profile = emitProfiledOpcode(opcodeID);
ASSERT(dst);
ASSERT(dst != ignoredResult());
instructions().append(dst->index()); // result
instructions().append(func->index()); // func
instructions().append(callArguments.argumentCountIncludingThis()); // argCount
instructions().append(callArguments.registerOffset()); // registerOffset
......@@ -1855,11 +1858,7 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi
instructions().append(0);
#endif
instructions().append(arrayProfile);
if (dst != ignoredResult()) {
UnlinkedValueProfile profile = emitProfiledOpcode(op_call_put_result);
instructions().append(kill(dst));
instructions().append(profile);
}
instructions().append(profile);
if (expectedFunction != NoExpectedFunction)
emitLabel(done.get());
......@@ -1883,17 +1882,15 @@ RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func
emitExpressionInfo(divot, startOffset, endOffset, line, lineStart);
// Emit call.
emitOpcode(op_call_varargs);
UnlinkedValueProfile profile = emitProfiledOpcode(op_call_varargs);
ASSERT(dst != ignoredResult());
instructions().append(dst->index());
instructions().append(func->index());
instructions().append(thisRegister->index());
instructions().append(arguments->index());
instructions().append(firstFreeRegister->index());
instructions().append(0); // Pad to make it as big as an op_call.
if (dst != ignoredResult()) {
UnlinkedValueProfile profile = emitProfiledOpcode(op_call_put_result);
instructions().append(kill(dst));
instructions().append(profile);
}
instructions().append(profile);
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_did_call);
instructions().append(profileHookRegister->index());
......@@ -1962,7 +1959,9 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func,
RefPtr<Label> done = newLabel();
expectedFunction = emitExpectedFunctionSnippet(dst, func, expectedFunction, callArguments, done.get());
emitOpcode(op_construct);
UnlinkedValueProfile profile = emitProfiledOpcode(op_construct);
ASSERT(dst != ignoredResult());
instructions().append(dst->index());
instructions().append(func->index()); // func
instructions().append(callArguments.argumentCountIncludingThis()); // argCount
instructions().append(callArguments.registerOffset()); // registerOffset
......@@ -1972,11 +1971,7 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func,
instructions().append(0);
#endif
instructions().append(0);
if (dst != ignoredResult()) {
UnlinkedValueProfile profile = emitProfiledOpcode(op_call_put_result);
instructions().append(kill(dst));
instructions().append(profile);
}
instructions().append(profile);
if (expectedFunction != NoExpectedFunction)
emitLabel(done.get());
......
......@@ -184,7 +184,6 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
case op_loop_hint:
case op_ret:
case op_end:
case op_call_put_result:
case op_new_object:
case op_new_array:
case op_new_array_with_size:
......@@ -208,7 +207,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
return CanCompileAndInline;
case op_call_varargs:
if (codeBlock->usesArguments() && pc[3].u.operand == codeBlock->argumentsRegister())
if (codeBlock->usesArguments() && pc[4].u.operand == codeBlock->argumentsRegister())
return CanInline;
return CannotCompile;
......
......@@ -101,8 +101,8 @@ void compileOSRExit(ExecState* exec)
exit.m_code = FINALIZE_CODE_IF(
shouldShowDisassembly(),
patchBuffer,
("DFG OSR exit #%u (bc#%u, %s) from %s",
exitIndex, exit.m_codeOrigin.bytecodeIndex,
("DFG OSR exit #%u (%s, %s) from %s",
exitIndex, toCString(exit.m_codeOrigin).data(),
exitKindToString(exit.m_kind), toCString(*codeBlock).data()));
}
......
......@@ -77,7 +77,6 @@ void handleExitCounts(CCallHelpers& jit, const OSRExitBase& exit)
void reifyInlinedCallFrames(CCallHelpers& jit, const OSRExitBase& exit)
{
#if USE(JSVALUE64)
ASSERT(jit.baselineCodeBlock()->jitType() == JITCode::BaselineJIT);
jit.storePtr(AssemblyHelpers::TrustedImmPtr(jit.baselineCodeBlock()), AssemblyHelpers::addressFor((VirtualRegister)JSStack::CodeBlock));
......@@ -85,15 +84,12 @@ void reifyInlinedCallFrames(CCallHelpers& jit, const OSRExitBase& exit)
InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(codeOrigin);
CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(inlineCallFrame->caller);
Vector<BytecodeAndMachineOffset>& decodedCodeMap = jit.decodedCodeMapFor(baselineCodeBlockForCaller);
unsigned returnBytecodeIndex = inlineCallFrame->caller.bytecodeIndex + OPCODE_LENGTH(op_call);
BytecodeAndMachineOffset* mapping = binarySearch<BytecodeAndMachineOffset, unsigned>(decodedCodeMap, decodedCodeMap.size(), returnBytecodeIndex, BytecodeAndMachineOffset::getBytecodeIndex);
ASSERT(mapping);
ASSERT(mapping->m_bytecodeIndex == returnBytecodeIndex);
unsigned callBytecodeIndex = inlineCallFrame->caller.bytecodeIndex;
CallLinkInfo& callLinkInfo = baselineCodeBlockForCaller->getCallLinkInfo(callBytecodeIndex);
void* jumpTarget = baselineCodeBlockForCaller->jitCode()->executableAddressAtOffset(mapping->m_machineCodeOffset);
void* jumpTarget = callLinkInfo.callReturnLocation.executableAddress();
#if USE(JSVALUE64)
GPRReg callerFrameGPR;
if (inlineCallFrame->caller.inlineCallFrame) {
jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->caller.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT3);
......@@ -109,24 +105,7 @@ void reifyInlinedCallFrames(CCallHelpers& jit, const OSRExitBase& exit)
jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount)));
if (!inlineCallFrame->isClosureCall())
jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame->callee.get()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
}
#else // USE(JSVALUE64) // so this is the 32-bit part
ASSERT(jit.baselineCodeBlock()->jitType() == JITCode::BaselineJIT);
jit.storePtr(AssemblyHelpers::TrustedImmPtr(jit.baselineCodeBlock()), AssemblyHelpers::addressFor((VirtualRegister)JSStack::CodeBlock));
for (CodeOrigin codeOrigin = exit.m_codeOrigin; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->caller) {
InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(codeOrigin);
CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(inlineCallFrame->caller);
Vector<BytecodeAndMachineOffset>& decodedCodeMap = jit.decodedCodeMapFor(baselineCodeBlockForCaller);
unsigned returnBytecodeIndex = inlineCallFrame->caller.bytecodeIndex + OPCODE_LENGTH(op_call);
BytecodeAndMachineOffset* mapping = binarySearch<BytecodeAndMachineOffset, unsigned>(decodedCodeMap, decodedCodeMap.size(), returnBytecodeIndex, BytecodeAndMachineOffset::getBytecodeIndex);
ASSERT(mapping);
ASSERT(mapping->m_bytecodeIndex == returnBytecodeIndex);
void* jumpTarget = baselineCodeBlockForCaller->jitCode()->executableAddressAtOffset(mapping->m_machineCodeOffset);
GPRReg callerFrameGPR;
if (inlineCallFrame->caller.inlineCallFrame) {
jit.add32(AssemblyHelpers::TrustedImm32(inlineCallFrame->caller.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT3);
......@@ -145,8 +124,8 @@ void reifyInlinedCallFrames(CCallHelpers& jit, const OSRExitBase& exit)
jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
if (!inlineCallFrame->isClosureCall())
jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee.get()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
}
#endif // USE(JSVALUE64) // ending the #else part, so directly above is the 32-bit part
}
}
void adjustAndJumpToTarget(CCallHelpers& jit, const OSRExitBase& exit)
......
......@@ -199,7 +199,7 @@ void JIT::privateCompileMainPass()
OpcodeID opcodeID = m_interpreter->getOpcodeID(currentInstruction->u.opcode);
if (m_compilation && opcodeID != op_call_put_result) {
if (m_compilation) {
add64(
TrustedImm32(1),
AbsoluteAddress(m_compilation->executionCounterFor(Profiler::OriginStack(Profiler::Origin(
......@@ -325,7 +325,6 @@ void JIT::privateCompileMainPass()
DEFINE_OP(op_resolve_with_base)
DEFINE_OP(op_resolve_with_this)
DEFINE_OP(op_ret)
DEFINE_OP(op_call_put_result)
DEFINE_OP(op_ret_object_or_this)
DEFINE_OP(op_rshift)
DEFINE_OP(op_urshift)
......
......@@ -431,8 +431,9 @@ namespace JSC {
void compileOpCall(OpcodeID, Instruction*, unsigned callLinkInfoIndex);
void compileOpCallSlowCase(OpcodeID, Instruction*, Vector<SlowCaseEntry>::iterator&, unsigned callLinkInfoIndex);
void compileLoadVarargs(Instruction*);
void compileCallEval();
void compileCallEvalSlowCase(Vector<SlowCaseEntry>::iterator&);
void compileCallEval(Instruction*);
void compileCallEvalSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitPutCallResult(Instruction*);
enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
void compileOpStrictEq(Instruction* instruction, CompileOpStrictEqType type);
......@@ -643,7 +644,6 @@ namespace JSC {
void emit_op_call(Instruction*);
void emit_op_call_eval(Instruction*);
void emit_op_call_varargs(Instruction*);
void emit_op_call_put_result(Instruction*);
void emit_op_catch(Instruction*);
void emit_op_construct(Instruction*);
void emit_op_get_callee(Instruction*);
......
......@@ -51,20 +51,25 @@ using namespace std;
namespace JSC {
void JIT::emit_op_call_put_result(Instruction* instruction)
void JIT::emitPutCallResult(Instruction* instruction)
{
int dst = instruction[1].u.operand;
emitValueProfilingSite();
emitPutVirtualRegister(dst);
if (canBeOptimizedOrInlined())
killLastResultRegister(); // Make lastResultRegister tracking simpler in the DFG.
if (canBeOptimizedOrInlined()) {
// Make lastResultRegister tracking simpler in the DFG. This is needed because
// the DFG may have the SetLocal corresponding to this Call's return value in
// a different basic block, if inlining happened. The DFG isn't smart enough to
// track the baseline JIT's last result register across basic blocks.
killLastResultRegister();
}
}
void JIT::compileLoadVarargs(Instruction* instruction)
{
int thisValue = instruction[2].u.operand;
int arguments = instruction[3].u.operand;
int firstFreeRegister = instruction[4].u.operand;
int thisValue = instruction[3].u.operand;
int arguments = instruction[4].u.operand;
int firstFreeRegister = instruction[5].u.operand;
killLastResultRegister();
......@@ -124,7 +129,7 @@ void JIT::compileLoadVarargs(Instruction* instruction)
end.link(this);
}
void JIT::compileCallEval()
void JIT::compileCallEval(Instruction* instruction)
{
JITStubCall stubCall(this, cti_op_call_eval); // Initializes ScopeChain; ReturnPC; CodeBlock.
stubCall.call();
......@@ -132,9 +137,11 @@ void JIT::compileCallEval()
emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, callFrameRegister);
sampleCodeBlock(m_codeBlock);
emitPutCallResult(instruction);
}
void JIT::compileCallEvalSlowCase(Vector<SlowCaseEntry>::iterator& iter)
void JIT::compileCallEvalSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
......@@ -142,11 +149,13 @@ void JIT::compileCallEvalSlowCase(Vector<SlowCaseEntry>::iterator& iter)
emitNakedCall(m_vm->getCTIStub(virtualCallGenerator).code());
sampleCodeBlock(m_codeBlock);
emitPutCallResult(instruction);
}
void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
{
int callee = instruction[1].u.operand;
int callee = instruction[2].u.operand;
/* Caller always:
- Updates callFrameRegister to callee callFrame.
......@@ -165,14 +174,14 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
if (opcodeID == op_call_varargs)
compileLoadVarargs(instruction);
else {
int argCount = instruction[2].u.operand;
int registerOffset = instruction[3].u.operand;
int argCount = instruction[3].u.operand;
int registerOffset = instruction[4].u.operand;
if (opcodeID == op_call && shouldEmitProfiling()) {
emitGetVirtualRegister(registerOffset + CallFrame::argumentOffsetIncludingThis(0), regT0);
Jump done = emitJumpIfNotJSCell(regT0);
loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
storePtr(regT0, instruction[5].u.arrayProfile->addressOfLastSeenStructure());
storePtr(regT0, instruction[6].u.arrayProfile->addressOfLastSeenStructure());
done.link(this);
}
......@@ -188,7 +197,7 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
move(regT1, callFrameRegister);
if (opcodeID == op_call_eval) {
compileCallEval();
compileCallEval(instruction);
return;
}
......@@ -209,12 +218,14 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
sampleCodeBlock(m_codeBlock);
emitPutCallResult(instruction);
}
void JIT::compileOpCallSlowCase(OpcodeID opcodeID, Instruction*, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex)
void JIT::compileOpCallSlowCase(OpcodeID opcodeID, Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex)
{
if (opcodeID == op_call_eval) {
compileCallEvalSlowCase(iter);
compileCallEvalSlowCase(instruction, iter);
return;
}
......@@ -223,6 +234,8 @@ void JIT::compileOpCallSlowCase(OpcodeID opcodeID, Instruction*, Vector<SlowCase
m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_vm->getCTIStub(linkConstructGenerator).code() : m_vm->getCTIStub(linkCallGenerator).code());
sampleCodeBlock(m_codeBlock);
emitPutCallResult(instruction);
}
void JIT::privateCompileClosureCall(CallLinkInfo* callLinkInfo, CodeBlock* calleeCodeBlock, Structure* expectedStructure, ExecutableBase* expectedExecutable, MacroAssemblerCodePtr codePtr)
......@@ -271,6 +284,46 @@ void JIT::privateCompileClosureCall(CallLinkInfo* callLinkInfo, CodeBlock* calle
callLinkInfo->stub = stubRoutine.release();
}
void JIT::emit_op_call(Instruction* currentInstruction)
{
compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
}
void JIT::emit_op_call_eval(Instruction* currentInstruction)
{
compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex);
}
void JIT::emit_op_call_varargs(Instruction* currentInstruction)
{
compileOpCall(op_call_varargs, currentInstruction, m_callLinkInfoIndex++);
}
void JIT::emit_op_construct(Instruction* currentInstruction)
{
compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++);
}
void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
compileOpCallSlowCase(op_call, currentInstruction, iter, m_callLinkInfoIndex++);
}
void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
compileOpCallSlowCase(op_call_eval, currentInstruction, iter, m_callLinkInfoIndex);
}
void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
compileOpCallSlowCase(op_call_varargs, currentInstruction, iter, m_callLinkInfoIndex++);
}
void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
compileOpCallSlowCase(op_construct, currentInstruction, iter, m_callLinkInfoIndex++);
}