Commit 2b2e1324 authored by oliver@apple.com's avatar oliver@apple.com
Browse files

fourthTier: Introducing the StackIterator class.

This was a non trivial merge as trunk has changed computation of line and column information

Introducing the StackIterator class.
https://bugs.webkit.org/show_bug.cgi?id=117390.

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

The StackIterator class is meant to unify the way we iterate the JS
stack. It also makes it so that we don't have to copy the frame data
into the intermediate StackFrame struct before processing it.
Unfortunately we still can't get rid of StackFrame because it is used
to record frame information for the Exception stack that is expected
to persist beyond when the frames have been popped off the JS stack.

The StackIterator will iterate over all "logical" frames (i.e. including
inlined frames). As it iterates the JS stack, if it encounters a DFG
frame that has inlined frames, the iterator will canonicalize the
inlined frames before returning. Once canonicalized, the frame can be
read like any other frame.

The StackIterator implements a Frame class that inherits from CallFrame.
The StackIterator::Frame serves as reader of the CallFrame that makes
it easier to access information about the frame. The StackIterator::Frame
only adds functions, and no additional data fields.

* API/JSContextRef.cpp:
(JSContextCreateBacktrace):
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* interpreter/CallFrame.cpp:
(JSC::CallFrame::begin):
(JSC::CallFrame::beginAt):
* interpreter/CallFrame.h:
(JSC::ExecState::setInlineCallFrame):
(ExecState):
(JSC::ExecState::end):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::dumpRegisters):
(JSC::Interpreter::unwindCallFrame):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::throwException):
(JSC::Interpreter::debug):
* interpreter/Interpreter.h:
(Interpreter):
* interpreter/StackIterator.cpp: Added.
(JSC::StackIterator::StackIterator):
(JSC::StackIterator::beginAt):
(JSC::StackIterator::gotoNextFrame):
- Based on the deleted Interpreter::findFunctionCallFrameFromVMCode().
(JSC::StackIterator::findFrameForFunction):
- Based on the deleted Interpreter::retrieveCallerFromVMCode().
(JSC::StackIterator::Frame::codeType):
- Based on the deleted getStackFrameCodeType().
(JSC::StackIterator::Frame::functionName):
- Based on StackFrame::friendlyFunctionName().
(JSC::StackIterator::Frame::sourceURL):
- Based on StackFrame::friendlySourceURL().
(JSC::StackIterator::Frame::toString):
- Based on StackFrame::toString().
(JSC::StackIterator::Frame::bytecodeOffset):
(JSC::StackIterator::Frame::line):
- Based on StackFrame::line().
(JSC::StackIterator::Frame::column):
- Based on StackFrame::column().
(JSC::StackIterator::Frame::arguments):
- Based on the deleted Interpreter::retrieveArgumentsFromVMCode().
(JSC::StackIterator::Frame::retrieveExpressionInfo):
- Based on StackFrame::expressionInfo().
(JSC::StackIterator::Frame::logicalFrame):
- Based on the now deleted CallFrame::trueCallFrame().
(JSC::StackIterator::Frame::logicalCallerFrame):
- Based on the now deleted CallFrame::trueCallerFrame().
(JSC::jitTypeName):
(JSC::printIndents):
(JSC::printif):
(JSC::StackIterator::Frame::print):
(debugPrintCallFrame):
- Prints the contents of the frame for debugging purposes.
  There are 2 versions that can be used as follows:

  1. When you have a valid StackIterator, you can print
     the current frame's content using the print instance
     method:
         iter->print(indentLevel);

  2. When you have a CallFrame* that you want to dump from a debugger
     console, you can print its content as follows:
         (gdb) call debugPrintCallFrame(callFrame)

  A sample of the output looks like this:

      frame 0x1510c70b0 {
         name 'shouldBe'
         sourceURL 'testapi.js'
         hostFlag 0
         isInlinedFrame 0
         callee 0x15154efb0
         returnPC 0x10ed0786d
         callerFrame 0x1510c7058
         logicalCallerFrame 0x1510c7058
         rawLocationBits 27 0x1b
         codeBlock 0x7fe79b037200
            bytecodeOffset 27 0x1b / 210
            line 46
            column 20
            jitType 3 <BaselineJIT> isOptimizingJIT 0
            hasCodeOrigins 0
      }

* interpreter/StackIterator.h: Added.
(StackIterator::Frame):
(JSC::StackIterator::Frame::create):
(JSC::StackIterator::Frame::isJSFrame):
(JSC::StackIterator::Frame::callFrame):
* interpreter/StackIteratorPrivate.h: Added.
(StackIterator):
(JSC::StackIterator::operator*):
(JSC::StackIterator::operator->):
(JSC::StackIterator::operator==):
(JSC::StackIterator::operator!=):
(JSC::StackIterator::operator++):
(JSC::StackIterator::end):
(JSC::StackIterator::empty):
* jsc.cpp:
(functionJSCStack):
* profiler/ProfileGenerator.cpp:
(JSC::ProfileGenerator::addParentForConsoleStart):
* profiler/ProfileNode.h:
(ProfileNode):
* runtime/JSFunction.cpp:
(JSC::retrieveArguments):
(JSC::JSFunction::argumentsGetter):
(JSC::skipOverBoundFunctions):
(JSC::retrieveCallerFunction):
(JSC::JSFunction::callerGetter):
(JSC::JSFunction::getOwnPropertyDescriptor):
(JSC::JSFunction::defineOwnProperty):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncProtoGetter):
(JSC::globalFuncProtoSetter):
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorGetPrototypeOf):
* runtime/Operations.h:

Source/WebCore:

No new tests.

* ForwardingHeaders/interpreter/StackIterator.h: Added.
* bindings/js/JSXMLHttpRequestCustom.cpp:
(WebCore::JSXMLHttpRequest::send):
* bindings/js/ScriptCallStackFactory.cpp:
(WebCore::createScriptCallStack):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153218 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 73823ba8
......@@ -53,8 +53,12 @@ JSValueRef numberOfDFGCompiles(JSContextRef context, JSValueRef theFunctionValue
if (!baselineCodeBlock)
return JSValueMakeNumber(context, 0);
#if ENABLE(DFG_JIT)
return JSValueMakeNumber(context, baselineCodeBlock->numberOfDFGCompiles());
#else
return JSValueMakeNumber(context, 1000000.0);
#endif
}
return JSValueMakeUndefined(context);
......
......@@ -28,15 +28,16 @@
#include "JSContextRefPrivate.h"
#include "APICast.h"
#include "CallFrameInlines.h"
#include "InitializeThreading.h"
#include <interpreter/CallFrame.h>
#include <interpreter/Interpreter.h>
#include "JSCallbackObject.h"
#include "JSClassRef.h"
#include "JSGlobalObject.h"
#include "JSObject.h"
#include "Operations.h"
#include "SourceProvider.h"
#include "StackIterator.h"
#include <wtf/text/StringBuilder.h>
#include <wtf/text/StringHash.h>
......@@ -221,38 +222,33 @@ JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
StringBuilder builder;
Vector<StackFrame> stackTrace;
Interpreter::getStackTrace(&exec->vm(), stackTrace, maxStackSize);
for (size_t i = 0; i < stackTrace.size(); i++) {
String urlString;
String functionName;
StackFrame& frame = stackTrace[i];
JSValue function = frame.callee.get();
if (frame.callee)
functionName = frame.friendlyFunctionName(exec);
else {
// Caller is unknown, but if frame is empty we should still add the frame, because
// something called us, and gave us arguments.
if (i)
break;
}
unsigned lineNumber;
unsigned column;
frame.computeLineAndColumn(lineNumber, column);
CallFrame* frame = exec->vm().topCallFrame;
size_t i = 0;
ASSERT(maxStackSize);
for (StackIterator iter = frame->begin(); iter != frame->end() && maxStackSize--; ++iter, ++i) {
JSObject* callee = iter->callee();
// If callee is unknown, but we've not added any frame yet, we should
// still add the frame, because something called us, and gave us arguments.
if (!callee && i)
break;
if (!builder.isEmpty())
builder.append('\n');
builder.append('#');
builder.appendNumber(i);
builder.append(' ');
builder.append(stackTrace[i].friendlyFunctionName(exec));
builder.append(iter->functionName());
builder.appendLiteral("() at ");
builder.append(urlString);
if (frame.codeType != StackFrameNativeCode) {
builder.append(iter->sourceURL());
if (iter->isJSFrame()) {
builder.append(':');
unsigned lineNumber;
unsigned unusedColumn;
iter->computeLineAndColumn(lineNumber, unusedColumn);
builder.appendNumber(lineNumber);
}
if (!function)
if (!callee)
break;
}
......
......@@ -165,6 +165,7 @@ set(JavaScriptCore_SOURCES
interpreter/CallFrame.cpp
interpreter/Interpreter.cpp
interpreter/JSStack.cpp
interpreter/StackIterator.cpp
interpreter/VMInspector.cpp
jit/ClosureCallStubRoutine.cpp
......
2013-06-10 Mark Lam <mark.lam@apple.com>
Introducing the StackIterator class.
https://bugs.webkit.org/show_bug.cgi?id=117390.
Reviewed by Geoffrey Garen.
The StackIterator class is meant to unify the way we iterate the JS
stack. It also makes it so that we don't have to copy the frame data
into the intermediate StackFrame struct before processing it.
Unfortunately we still can't get rid of StackFrame because it is used
to record frame information for the Exception stack that is expected
to persist beyond when the frames have been popped off the JS stack.
The StackIterator will iterate over all "logical" frames (i.e. including
inlined frames). As it iterates the JS stack, if it encounters a DFG
frame that has inlined frames, the iterator will canonicalize the
inlined frames before returning. Once canonicalized, the frame can be
read like any other frame.
The StackIterator implements a Frame class that inherits from CallFrame.
The StackIterator::Frame serves as reader of the CallFrame that makes
it easier to access information about the frame. The StackIterator::Frame
only adds functions, and no additional data fields.
* API/JSContextRef.cpp:
(JSContextCreateBacktrace):
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* interpreter/CallFrame.cpp:
(JSC::CallFrame::begin):
(JSC::CallFrame::beginAt):
* interpreter/CallFrame.h:
(JSC::ExecState::setInlineCallFrame):
(ExecState):
(JSC::ExecState::end):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::dumpRegisters):
(JSC::Interpreter::unwindCallFrame):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::throwException):
(JSC::Interpreter::debug):
* interpreter/Interpreter.h:
(Interpreter):
* interpreter/StackIterator.cpp: Added.
(JSC::StackIterator::StackIterator):
(JSC::StackIterator::beginAt):
(JSC::StackIterator::gotoNextFrame):
- Based on the deleted Interpreter::findFunctionCallFrameFromVMCode().
(JSC::StackIterator::findFrameForFunction):
- Based on the deleted Interpreter::retrieveCallerFromVMCode().
(JSC::StackIterator::Frame::codeType):
- Based on the deleted getStackFrameCodeType().
(JSC::StackIterator::Frame::functionName):
- Based on StackFrame::friendlyFunctionName().
(JSC::StackIterator::Frame::sourceURL):
- Based on StackFrame::friendlySourceURL().
(JSC::StackIterator::Frame::toString):
- Based on StackFrame::toString().
(JSC::StackIterator::Frame::bytecodeOffset):
(JSC::StackIterator::Frame::line):
- Based on StackFrame::line().
(JSC::StackIterator::Frame::column):
- Based on StackFrame::column().
(JSC::StackIterator::Frame::arguments):
- Based on the deleted Interpreter::retrieveArgumentsFromVMCode().
(JSC::StackIterator::Frame::retrieveExpressionInfo):
- Based on StackFrame::expressionInfo().
(JSC::StackIterator::Frame::logicalFrame):
- Based on the now deleted CallFrame::trueCallFrame().
(JSC::StackIterator::Frame::logicalCallerFrame):
- Based on the now deleted CallFrame::trueCallerFrame().
(JSC::jitTypeName):
(JSC::printIndents):
(JSC::printif):
(JSC::StackIterator::Frame::print):
(debugPrintCallFrame):
- Prints the contents of the frame for debugging purposes.
There are 2 versions that can be used as follows:
1. When you have a valid StackIterator, you can print
the current frame's content using the print instance
method:
iter->print(indentLevel);
2. When you have a CallFrame* that you want to dump from a debugger
console, you can print its content as follows:
(gdb) call debugPrintCallFrame(callFrame)
A sample of the output looks like this:
frame 0x1510c70b0 {
name 'shouldBe'
sourceURL 'testapi.js'
hostFlag 0
isInlinedFrame 0
callee 0x15154efb0
returnPC 0x10ed0786d
callerFrame 0x1510c7058
logicalCallerFrame 0x1510c7058
rawLocationBits 27 0x1b
codeBlock 0x7fe79b037200
bytecodeOffset 27 0x1b / 210
line 46
column 20
jitType 3 <BaselineJIT> isOptimizingJIT 0
hasCodeOrigins 0
}
* interpreter/StackIterator.h: Added.
(StackIterator::Frame):
(JSC::StackIterator::Frame::create):
(JSC::StackIterator::Frame::isJSFrame):
(JSC::StackIterator::Frame::callFrame):
* interpreter/StackIteratorPrivate.h: Added.
(StackIterator):
(JSC::StackIterator::operator*):
(JSC::StackIterator::operator->):
(JSC::StackIterator::operator==):
(JSC::StackIterator::operator!=):
(JSC::StackIterator::operator++):
(JSC::StackIterator::end):
(JSC::StackIterator::empty):
* jsc.cpp:
(functionJSCStack):
* profiler/ProfileGenerator.cpp:
(JSC::ProfileGenerator::addParentForConsoleStart):
* profiler/ProfileNode.h:
(ProfileNode):
* runtime/JSFunction.cpp:
(JSC::retrieveArguments):
(JSC::JSFunction::argumentsGetter):
(JSC::skipOverBoundFunctions):
(JSC::retrieveCallerFunction):
(JSC::JSFunction::callerGetter):
(JSC::JSFunction::getOwnPropertyDescriptor):
(JSC::JSFunction::defineOwnProperty):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncProtoGetter):
(JSC::globalFuncProtoSetter):
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorGetPrototypeOf):
* runtime/Operations.h:
2013-06-09 Filip Pizlo <fpizlo@apple.com>
Marge trunk r146653.
......
......@@ -442,6 +442,9 @@ javascriptcore_sources += \
Source/JavaScriptCore/interpreter/JSStack.h \
Source/JavaScriptCore/interpreter/JSStackInlines.h \
Source/JavaScriptCore/interpreter/Register.h \
Source/JavaScriptCore/interpreter/StackIterator.cpp \
Source/JavaScriptCore/interpreter/StackIterator.h \
Source/JavaScriptCore/interpreter/StackIteratorPrivate.h \
Source/JavaScriptCore/interpreter/VMInspector.cpp \
Source/JavaScriptCore/interpreter/VMInspector.h \
Source/JavaScriptCore/JavaScriptCorePrefix.h \
......
......@@ -354,6 +354,7 @@
<ClCompile Include="..\interpreter\CallFrame.cpp" />
<ClCompile Include="..\interpreter\Interpreter.cpp" />
<ClCompile Include="..\interpreter\JSStack.cpp" />
<ClCompile Include="..\interpreter\StackIterator.cpp" />
<ClCompile Include="..\interpreter\VMInspector.cpp" />
<ClCompile Include="..\jit\ClosureCallStubRoutine.cpp" />
<ClCompile Include="..\jit\ExecutableAllocator.cpp" />
......@@ -691,6 +692,8 @@
<ClInclude Include="..\interpreter\JSStack.h" />
<ClInclude Include="..\interpreter\JSStackInlines.h" />
<ClInclude Include="..\interpreter\Register.h" />
<ClInclude Include="..\interpreter\StackIterator.h" />
<ClInclude Include="..\interpreter\StackIteratorPrivate.h" />
<ClInclude Include="..\interpreter\VMInspector.h" />
<ClInclude Include="..\jit\ClosureCallStubRoutine.h" />
<ClInclude Include="..\jit\CompactJITCodeMap.h" />
......
......@@ -291,6 +291,9 @@
<ClCompile Include="..\interpreter\JSStack.cpp">
<Filter>interpreter</Filter>
</ClCompile>
<ClCompile Include="..\interpreter\StackIterator.cpp">
<Filter>interpreter</Filter>
</ClCompile>
<ClCompile Include="..\interpreter\VMInspector.cpp">
<Filter>interpreter</Filter>
</ClCompile>
......@@ -1229,6 +1232,12 @@
<ClInclude Include="..\interpreter\Register.h">
<Filter>interpreter</Filter>
</ClInclude>
<ClInclude Include="..\interpreter\StackIterator.h">
<Filter>interpreter</Filter>
</ClInclude>
<ClInclude Include="..\interpreter\StackIteratorPrivate.h">
<Filter>interpreter</Filter>
</ClInclude>
<ClInclude Include="..\interpreter\VMInspector.h">
<Filter>interpreter</Filter>
</ClInclude>
......
......@@ -796,6 +796,11 @@
A7C0C4AC168103020017011D /* JSScriptRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C0C4AB167C08CD0017011D /* JSScriptRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7C0C4AD1681067E0017011D /* JSScriptRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7C0C4AA167C08CD0017011D /* JSScriptRef.cpp */; };
A7C1E8E4112E72EF00A37F98 /* JITPropertyAccess32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7C1E8C8112E701C00A37F98 /* JITPropertyAccess32_64.cpp */; };
A7C1EAEF17987AB600299DB2 /* CallFrameInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C1EAEA17987AB600299DB2 /* CallFrameInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7C1EAF017987AB600299DB2 /* JSStackInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C1EAEB17987AB600299DB2 /* JSStackInlines.h */; };
A7C1EAF117987AB600299DB2 /* StackIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7C1EAEC17987AB600299DB2 /* StackIterator.cpp */; };
A7C1EAF217987AB600299DB2 /* StackIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C1EAED17987AB600299DB2 /* StackIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7C1EAF317987AB600299DB2 /* StackIteratorPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C1EAEE17987AB600299DB2 /* StackIteratorPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7DCB97312E5193F00911940 /* WriteBarrier.h in Headers */ = {isa = PBXBuildFile; fileRef = A7DCB77912E3D90500911940 /* WriteBarrier.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7E2EA6B0FB460CF00601F06 /* LiteralParser.h in Headers */ = {isa = PBXBuildFile; fileRef = A7E2EA690FB460CF00601F06 /* LiteralParser.h */; };
A7E2EA6C0FB460CF00601F06 /* LiteralParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7E2EA6A0FB460CF00601F06 /* LiteralParser.cpp */; };
......@@ -1826,6 +1831,11 @@
A7C0C4AA167C08CD0017011D /* JSScriptRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSScriptRef.cpp; sourceTree = "<group>"; };
A7C0C4AB167C08CD0017011D /* JSScriptRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSScriptRefPrivate.h; sourceTree = "<group>"; };
A7C1E8C8112E701C00A37F98 /* JITPropertyAccess32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITPropertyAccess32_64.cpp; sourceTree = "<group>"; };
A7C1EAEA17987AB600299DB2 /* CallFrameInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallFrameInlines.h; sourceTree = "<group>"; };
A7C1EAEB17987AB600299DB2 /* JSStackInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStackInlines.h; sourceTree = "<group>"; };
A7C1EAEC17987AB600299DB2 /* StackIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StackIterator.cpp; sourceTree = "<group>"; };
A7C1EAED17987AB600299DB2 /* StackIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackIterator.h; sourceTree = "<group>"; };
A7C1EAEE17987AB600299DB2 /* StackIteratorPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackIteratorPrivate.h; sourceTree = "<group>"; };
A7C225CC139981F100FF1662 /* KeywordLookupGenerator.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = KeywordLookupGenerator.py; sourceTree = "<group>"; };
A7C225CD1399849C00FF1662 /* KeywordLookup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeywordLookup.h; sourceTree = "<group>"; };
A7DCB77912E3D90500911940 /* WriteBarrier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrier.h; sourceTree = "<group>"; };
......@@ -2297,6 +2307,11 @@
1429D77A0ED20D7300B89619 /* interpreter */ = {
isa = PBXGroup;
children = (
A7C1EAEA17987AB600299DB2 /* CallFrameInlines.h */,
A7C1EAEB17987AB600299DB2 /* JSStackInlines.h */,
A7C1EAEC17987AB600299DB2 /* StackIterator.cpp */,
A7C1EAED17987AB600299DB2 /* StackIterator.h */,
A7C1EAEE17987AB600299DB2 /* StackIteratorPrivate.h */,
0F55F0F114D1063600AC7649 /* AbstractPC.cpp */,
0F55F0F214D1063600AC7649 /* AbstractPC.h */,
A7F8690E0F9584A100558697 /* CachedCall.h */,
......@@ -3404,12 +3419,14 @@
0F1E3A471534CBB9000F9456 /* DFGDoubleFormatState.h in Headers */,
0FD3C82814115D4F00FD81CB /* DFGDriver.h in Headers */,
0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */,
A7C1EAF217987AB600299DB2 /* StackIterator.h in Headers */,
0FBC0AE81496C7C700D4FBDD /* DFGExitProfile.h in Headers */,
A78A9775179738B8009DF744 /* DFGFailedFinalizer.h in Headers */,
A78A9777179738B8009DF744 /* DFGFinalizer.h in Headers */,
0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */,
86AE6C4D136A11E400963012 /* DFGFPRInfo.h in Headers */,
86EC9DC61328DF82002B2AD7 /* DFGGenerationInfo.h in Headers */,
A7C1EAF017987AB600299DB2 /* JSStackInlines.h in Headers */,
86AE6C4E136A11E400963012 /* DFGGPRInfo.h in Headers */,
86EC9DC81328DF82002B2AD7 /* DFGGraph.h in Headers */,
0F2BDC21151E803B00CD8910 /* DFGInsertionSet.h in Headers */,
......@@ -3690,6 +3707,7 @@
86F3EEBD168CDE930077B92A /* ObjCCallbackFunction.h in Headers */,
86F3EEBF168CDE930077B92A /* ObjcRuntimeExtras.h in Headers */,
14CA958D16AB50FA00938A06 /* ObjectAllocationProfile.h in Headers */,
A7C1EAF317987AB600299DB2 /* StackIteratorPrivate.h in Headers */,
BC18C4450E16F5CD00B34460 /* ObjectConstructor.h in Headers */,
BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */,
E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */,
......@@ -3779,6 +3797,7 @@
145722861437E140005FDE26 /* StrongInlines.h in Headers */,
BCDE3AB80E6C82F5001453A7 /* Structure.h in Headers */,
7E4EE7090EBB7963005934AA /* StructureChain.h in Headers */,
A7C1EAEF17987AB600299DB2 /* CallFrameInlines.h in Headers */,
0FD2C92416D01EE900C7803F /* StructureInlines.h in Headers */,
C2FE18A416BAEC4000AF3061 /* StructureRareData.h in Headers */,
C20BA92D16BB1C1500B3AEA2 /* StructureRareDataInlines.h in Headers */,
......@@ -4411,6 +4430,7 @@
0F4680A414BA7F8D00BFE272 /* LLIntSlowPaths.cpp in Sources */,
0F0B839C14BCF46300885B4F /* LLIntThunks.cpp in Sources */,
14469DDE107EC7E700650446 /* Lookup.cpp in Sources */,
A7C1EAF117987AB600299DB2 /* StackIterator.cpp in Sources */,
0F4680CC14BBB17A00BFE272 /* LowLevelInterpreter.cpp in Sources */,
14B723B212D7DA46003BD5ED /* MachineStackMarker.cpp in Sources */,
0FEB3ECF16237F6C00AB67AD /* MacroAssembler.cpp in Sources */,
......
......@@ -171,6 +171,7 @@ SOURCES += \
interpreter/CallFrame.cpp \
interpreter/Interpreter.cpp \
interpreter/JSStack.cpp \
interpreter/StackIterator.cpp \
jit/ClosureCallStubRoutine.cpp \
jit/ExecutableAllocatorFixedVMPool.cpp \
jit/ExecutableAllocator.cpp \
......
......@@ -67,98 +67,6 @@ void CallFrame::setCurrentVPC(Instruction* vpc)
#endif
#if ENABLE(DFG_JIT)
CallFrame* CallFrame::trueCallFrame()
{
// Am I an inline call frame? If so, we're done.
if (isInlinedFrame())
return this;
// If I don't have a code block, then I'm not DFG code, so I'm the true call frame.
CodeBlock* machineCodeBlock = codeBlock();
if (!machineCodeBlock)
return this;
// If the code block does not have any code origins, then there was no inlining, so
// I'm done.
if (!machineCodeBlock->hasCodeOrigins())
return this;
// Try to determine the CodeOrigin. If we don't have a pc set then the only way
// that this makes sense is if the CodeOrigin index was set in the call frame.
CodeOrigin codeOrigin;
unsigned index = locationAsCodeOriginIndex();
ASSERT(machineCodeBlock->canGetCodeOrigin(index));
if (!machineCodeBlock->canGetCodeOrigin(index)) {
// See above. In release builds, we try to protect ourselves from crashing even
// though stack walking will be goofed up.
return 0;
}
codeOrigin = machineCodeBlock->codeOrigin(index);
if (!codeOrigin.inlineCallFrame)
return this; // Not currently in inlined code.
CodeOrigin innerMostCodeOrigin = codeOrigin;
for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame;
CallFrame* inlinedCaller = this + inlineCallFrame->stackOffset;
JSFunction* calleeAsFunction = inlineCallFrame->callee.get();
// Fill in the inlinedCaller
inlinedCaller->setCodeBlock(inlineCallFrame->baselineCodeBlock());
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());
inlinedCaller->setLocationAsBytecodeOffset(codeOrigin.bytecodeIndex);
inlinedCaller->setIsInlinedFrame();
if (calleeAsFunction)
inlinedCaller->setCallee(calleeAsFunction);
codeOrigin = inlineCallFrame->caller;
inlineCallFrame = nextInlineCallFrame;
}
return this + innerMostCodeOrigin.inlineCallFrame->stackOffset;
}
CallFrame* CallFrame::trueCallerFrame()
{
CallFrame* callerFrame = this->callerFrame()->removeHostCallFrameFlag();
if (!codeBlock())
return callerFrame;
// this -> The callee; this is either an inlined callee in which case it already has
// a pointer to the true caller. Otherwise it contains current PC in the machine
// caller.
//
// machineCaller -> The caller according to the machine, which may be zero or
// more frames above the true caller due to inlining.
// Am I an inline call frame? If so, we're done.
if (isInlinedFrame())
return callerFrame;
// I am a machine call frame, so the question is: is my caller a machine call frame
// that has inlines or a machine call frame that doesn't?
if (!callerFrame)
return 0;
if (!callerFrame->codeBlock())
return callerFrame;
ASSERT(!callerFrame->isInlinedFrame());
return callerFrame->trueCallFrame()->removeHostCallFrameFlag();
}
unsigned CallFrame::bytecodeOffsetFromCodeOriginIndex()
{
ASSERT(hasLocationAsCodeOriginIndex());
......@@ -189,4 +97,23 @@ Register* CallFrame::frameExtentInternal()
return registers() + codeBlock->m_numCalleeRegisters;
}
StackIterator CallFrame::begin(StackIterator::FrameFilter filter)
{
ASSERT(this);
return StackIterator(this, filter);
}
StackIterator CallFrame::find(JSFunction* calleeFunctionObj, StackIterator::FrameFilter filter)
{
ASSERT(this);
StackIterator iter = StackIterator(this, filter);
iter.find(calleeFunctionObj);
return iter;
}
StackIterator::Frame* CallFrame::end()
{
return StackIterator::end();
}
}
......@@ -28,6 +28,7 @@
#include "JSStack.h"
#include "MacroAssemblerCodeRef.h"
#include "Register.h"
#include "StackIteratorPrivate.h"
namespace JSC {
......@@ -274,21 +275,13 @@ namespace JSC {
#if ENABLE(DFG_JIT)
void setInlineCallFrame(InlineCallFrame* inlineCallFrame) { static_cast<Register*>(this)[JSStack::ReturnPC] = inlineCallFrame; }
// Call this to get the semantically correct JS CallFrame* for the
// currently executing function.
CallFrame* trueCallFrame();
// Call this to get the semantically correct JS CallFrame* corresponding
// to the caller. This resolves issues surrounding inlining and the
// HostCallFrameFlag stuff.
CallFrame* trueCallerFrame();
#else
CallFrame* trueCallFrame() { return this; }
CallFrame* trueCallerFrame() { return callerFrame()->removeHostCallFrameFlag(); }
#endif
CallFrame* callerFrameNoFlags() { return callerFrame()->removeHostCallFrameFlag(); }
JS_EXPORT_PRIVATE StackIterator begin(StackIterator::FrameFilter = nullptr);
JS_EXPORT_PRIVATE StackIterator find(JSFunction* calleeFunctionObj, StackIterator::FrameFilter = nullptr);
JS_EXPORT_PRIVATE StackIterator::Frame* end();
private:
static const intptr_t HostCallFrameFlag = 1;
static const int s_thisArgumentOffset = -1 - JSStack::CallFrameHeaderSize;
......
......@@ -63,6 +63,7 @@
#include "RegExpPrototype.h"
#include "Register.h"
#include "SamplingTool.h"
#include "StackIterator.h"
#include "StrictEvalActivation.h"
#include "StrongInlines.h"
#include "VMStackBounds.h"
......@@ -100,8 +101,6 @@ Interpreter::ErrorHandlingMode::~ErrorHandlingMode()
m_interpreter.stack().disableErrorStackReserve();
}
static CallFrame* getCallerInfo(VM*, CallFrame*, unsigned& bytecodeOffset, CodeBlock*& callerOut);
// Returns the depth of the scope chain within a given call frame.
static int depth(CodeBlock* codeBlock, JSScope* sc)
{
......@@ -321,13 +320,15 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
if (pc.hasJITReturnAddress())
dataLogF("[ReturnJITPC] | %10p | %p \n", it, pc.jitReturnAddress().value());
#endif
unsigned bytecodeOffset = 0;
int line = 0;
CodeBlock* callerCodeBlock = 0;
getCallerInfo(&callFrame->vm(), callFrame, bytecodeOffset, callerCodeBlock);
line = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset);
dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", it, bytecodeOffset, line);
++it;
StackIterator iter = callFrame->begin();
++iter;
if (iter != callFrame->end()) {
unsigned line = 0;
unsigned unusedColumn = 0;
iter->computeLineAndColumn(line, unusedColumn);
dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", it, iter->bytecodeOffset(), line);
++it;
}
dataLogF("[CodeBlock] | %10p | %p \n", it, callFrame->codeBlock());
++it;
dataLogF("-----------------------------------------------------------------------------\n");
......@@ -376,8 +377,10 @@ bool Interpreter::isOpcode(Opcode opcode)
#endif
}
NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)