#include "config.h"
#include "CallFrame.h"
#include "CodeBlock.h"
#include "Interpreter.h"
#include "Operations.h"
namespace JSC {
#ifndef NDEBUG
void CallFrame::dumpCaller()
{
int signedLineNumber;
intptr_t sourceID;
String urlString;
JSValue function;
interpreter()->retrieveLastCaller(this, signedLineNumber, sourceID, urlString, function);
dataLogF("Callpoint => %s:%d\n", urlString.utf8().data(), signedLineNumber);
}
JSStack* CallFrame::stack()
{
return &interpreter()->stack();
}
#endif
#if USE(JSVALUE32_64)
unsigned CallFrame::bytecodeOffsetForNonDFGCode() const
{
ASSERT(codeBlock());
return currentVPC() - codeBlock()->instructions().begin();
}
void CallFrame::setBytecodeOffsetForNonDFGCode(unsigned offset)
{
ASSERT(codeBlock());
setCurrentVPC(codeBlock()->instructions().begin() + offset);
}
#else
Instruction* CallFrame::currentVPC() const
{
return codeBlock()->instructions().begin() + bytecodeOffsetForNonDFGCode();
}
void CallFrame::setCurrentVPC(Instruction* vpc)
{
setBytecodeOffsetForNonDFGCode(vpc - codeBlock()->instructions().begin());
}
#endif
#if ENABLE(DFG_JIT)
bool CallFrame::isInlineCallFrameSlow()
{
if (!callee())
return false;
JSCell* calleeAsFunctionCell = getJSFunction(callee());
if (!calleeAsFunctionCell)
return false;
JSFunction* calleeAsFunction = jsCast<JSFunction*>(calleeAsFunctionCell);
return calleeAsFunction->executable() != codeBlock()->ownerExecutable();
}
CallFrame* CallFrame::trueCallFrame(AbstractPC pc)
{
if (isInlineCallFrame())
return this;
CodeBlock* machineCodeBlock = codeBlock();
if (!machineCodeBlock)
return this;
if (!machineCodeBlock->hasCodeOrigins())
return this;
ASSERT(pc.hasJITReturnAddress() || !pc);
CodeOrigin codeOrigin;
if (pc.isSet()) {
ReturnAddressPtr currentReturnPC = pc.jitReturnAddress();
bool hasCodeOrigin = machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin);
ASSERT(hasCodeOrigin);
if (!hasCodeOrigin) {
return 0;
}
} else {
unsigned index = codeOriginIndexForDFG();
ASSERT(machineCodeBlock->canGetCodeOrigin(index));
if (!machineCodeBlock->canGetCodeOrigin(index)) {
return 0;
}
codeOrigin = machineCodeBlock->codeOrigin(index);
}
if (!codeOrigin.inlineCallFrame)
return this;
for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame;
CallFrame* inlinedCaller = this + inlineCallFrame->stackOffset;
JSFunction* calleeAsFunction = inlineCallFrame->callee.get();
inlinedCaller->setCodeBlock(machineCodeBlock);
if (calleeAsFunction)
inlinedCaller->setScope(calleeAsFunction->scope());
if (nextInlineCallFrame)
inlinedCaller->setCallerFrame(this + nextInlineCallFrame->stackOffset);
else
inlinedCaller->setCallerFrame(this);
inlinedCaller->setInlineCallFrame(inlineCallFrame);
inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size());
if (calleeAsFunction)
inlinedCaller->setCallee(calleeAsFunction);
inlineCallFrame = nextInlineCallFrame;
}
return this + codeOrigin.inlineCallFrame->stackOffset;
}
CallFrame* CallFrame::trueCallerFrame()
{
if (!codeBlock())
return callerFrame()->removeHostCallFrameFlag();
if (isInlineCallFrame())
return callerFrame()->removeHostCallFrameFlag();
CallFrame* machineCaller = callerFrame()->removeHostCallFrameFlag();
if (!machineCaller)
return 0;
ASSERT(!machineCaller->isInlineCallFrame());
if (!hasReturnPC() || returnAddressIsInCtiTrampoline(returnPC()))
return machineCaller->trueCallFrameFromVMCode()->removeHostCallFrameFlag();
return machineCaller->trueCallFrame(returnPC())->removeHostCallFrameFlag();
}
CodeBlock* CallFrame::someCodeBlockForPossiblyInlinedCode()
{
if (!isInlineCallFrame())
return codeBlock();
return jsCast<FunctionExecutable*>(inlineCallFrame()->executable.get())->baselineCodeBlockFor(
inlineCallFrame()->isCall ? CodeForCall : CodeForConstruct);
}
#endif
Register* CallFrame::frameExtentInternal()
{
CodeBlock* codeBlock = this->codeBlock();
ASSERT(codeBlock);
return registers() + codeBlock->m_numCalleeRegisters;
}
}