#include "config.h"
#include "CallFrame.h"
#include "CallFrameInlines.h"
#include "CodeBlock.h"
#include "Interpreter.h"
#include "JSLexicalEnvironment.h"
#include "JSCInlines.h"
#include "VMEntryScope.h"
#include <wtf/StringPrintStream.h>
namespace JSC {
#ifndef NDEBUG
JSStack* CallFrame::stack()
{
return &interpreter()->stack();
}
#endif
#if USE(JSVALUE32_64)
unsigned CallFrame::locationAsBytecodeOffset() const
{
ASSERT(codeBlock());
ASSERT(hasLocationAsBytecodeOffset());
return currentVPC() - codeBlock()->instructions().begin();
}
void CallFrame::setLocationAsBytecodeOffset(unsigned offset)
{
ASSERT(codeBlock());
setCurrentVPC(codeBlock()->instructions().begin() + offset);
ASSERT(hasLocationAsBytecodeOffset());
}
#else
Instruction* CallFrame::currentVPC() const
{
return codeBlock()->instructions().begin() + locationAsBytecodeOffset();
}
void CallFrame::setCurrentVPC(Instruction* vpc)
{
setLocationAsBytecodeOffset(vpc - codeBlock()->instructions().begin());
}
#endif
#if ENABLE(DFG_JIT)
unsigned CallFrame::bytecodeOffsetFromCodeOriginIndex()
{
ASSERT(hasLocationAsCodeOriginIndex());
CodeBlock* codeBlock = this->codeBlock();
ASSERT(codeBlock);
CodeOrigin codeOrigin;
unsigned index = locationAsCodeOriginIndex();
ASSERT(codeBlock->canGetCodeOrigin(index));
codeOrigin = codeBlock->codeOrigin(index);
for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
if (inlineCallFrame->baselineCodeBlock() == codeBlock)
return codeOrigin.bytecodeIndex;
codeOrigin = inlineCallFrame->caller;
inlineCallFrame = codeOrigin.inlineCallFrame;
}
return codeOrigin.bytecodeIndex;
}
#endif // ENABLE(DFG_JIT)
unsigned CallFrame::bytecodeOffset()
{
if (!codeBlock())
return 0;
#if ENABLE(DFG_JIT)
if (hasLocationAsCodeOriginIndex())
return bytecodeOffsetFromCodeOriginIndex();
#endif
return locationAsBytecodeOffset();
}
CodeOrigin CallFrame::codeOrigin()
{
if (!codeBlock())
return CodeOrigin(0);
#if ENABLE(DFG_JIT)
if (hasLocationAsCodeOriginIndex()) {
unsigned index = locationAsCodeOriginIndex();
ASSERT(codeBlock()->canGetCodeOrigin(index));
return codeBlock()->codeOrigin(index);
}
#endif
return CodeOrigin(locationAsBytecodeOffset());
}
Register* CallFrame::topOfFrameInternal()
{
CodeBlock* codeBlock = this->codeBlock();
ASSERT(codeBlock);
return registers() + codeBlock->stackPointerOffset();
}
JSGlobalObject* CallFrame::vmEntryGlobalObject()
{
if (this == lexicalGlobalObject()->globalExec())
return lexicalGlobalObject();
ASSERT(vm().entryScope);
return vm().entryScope->globalObject();
}
CallFrame* CallFrame::callerFrame(VMEntryFrame*& currVMEntryFrame)
{
if (callerFrameOrVMEntryFrame() == currVMEntryFrame) {
VMEntryRecord* currVMEntryRecord = vmEntryRecord(currVMEntryFrame);
currVMEntryFrame = currVMEntryRecord->prevTopVMEntryFrame();
return currVMEntryRecord->prevTopCallFrame();
}
return static_cast<CallFrame*>(callerFrameOrVMEntryFrame());
}
JSLexicalEnvironment* CallFrame::lexicalEnvironment() const
{
CodeBlock* codeBlock = this->codeBlock();
RELEASE_ASSERT(codeBlock->needsActivation());
VirtualRegister activationRegister = codeBlock->activationRegister();
return registers()[activationRegister.offset()].Register::lexicalEnvironment();
}
JSLexicalEnvironment* CallFrame::lexicalEnvironmentOrNullptr() const
{
CodeBlock* codeBlock = this->codeBlock();
return codeBlock->needsActivation() ? lexicalEnvironment() : nullptr;
}
void CallFrame::setActivation(JSLexicalEnvironment* lexicalEnvironment)
{
CodeBlock* codeBlock = this->codeBlock();
RELEASE_ASSERT(codeBlock->needsActivation());
VirtualRegister activationRegister = codeBlock->activationRegister();
registers()[activationRegister.offset()] = lexicalEnvironment;
}
void CallFrame::dump(PrintStream& out)
{
if (CodeBlock* codeBlock = this->codeBlock()) {
out.print(codeBlock->inferredName(), "#", codeBlock->hashAsStringIfPossible(), " [", codeBlock->jitType(), "]");
out.print("(");
thisValue().dumpForBacktrace(out);
for (size_t i = 0; i < argumentCount(); ++i) {
out.print(", ");
JSValue value = argument(i);
value.dumpForBacktrace(out);
}
out.print(")");
return;
}
out.print(returnPC());
}
const char* CallFrame::describeFrame()
{
const size_t bufferSize = 200;
static char buffer[bufferSize + 1];
WTF::StringPrintStream stringStream;
dump(stringStream);
strncpy(buffer, stringStream.toCString().data(), bufferSize);
buffer[bufferSize] = '\0';
return buffer;
}
}