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
diff --git a/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp b/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp
index 3942467..6ac77c5 100644
--- a/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp
+++ b/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp
@@ -53,8 +53,12 @@
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);
diff --git a/Source/JavaScriptCore/API/JSContextRef.cpp b/Source/JavaScriptCore/API/JSContextRef.cpp
index 48a0b44..1c1f134 100644
--- a/Source/JavaScriptCore/API/JSContextRef.cpp
+++ b/Source/JavaScriptCore/API/JSContextRef.cpp
@@ -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 @@
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
StringBuilder builder;
- Vector<StackFrame> stackTrace;
- Interpreter::getStackTrace(&exec->vm(), stackTrace, maxStackSize);
+ 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;
- 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);
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;
}
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index d465568..145eedd 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -165,6 +165,7 @@
interpreter/CallFrame.cpp
interpreter/Interpreter.cpp
interpreter/JSStack.cpp
+ interpreter/StackIterator.cpp
interpreter/VMInspector.cpp
jit/ClosureCallStubRoutine.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 124e3c5..4579253 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,152 @@
+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.
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index ec825ab..2fc74c6 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -442,6 +442,9 @@
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 \
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
index 5397104..2e10fc8 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
@@ -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" />
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
index d8b6e58..c0a2a47 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
@@ -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>
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 073286b..c950477 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -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 */,
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index 0683aa8..a55a175 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -171,6 +171,7 @@
interpreter/CallFrame.cpp \
interpreter/Interpreter.cpp \
interpreter/JSStack.cpp \
+ interpreter/StackIterator.cpp \
jit/ClosureCallStubRoutine.cpp \
jit/ExecutableAllocatorFixedVMPool.cpp \
jit/ExecutableAllocator.cpp \
diff --git a/Source/JavaScriptCore/interpreter/CallFrame.cpp b/Source/JavaScriptCore/interpreter/CallFrame.cpp
index 621b444..769ec8b 100644
--- a/Source/JavaScriptCore/interpreter/CallFrame.cpp
+++ b/Source/JavaScriptCore/interpreter/CallFrame.cpp
@@ -67,98 +67,6 @@
#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 @@
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();
+}
+
}
diff --git a/Source/JavaScriptCore/interpreter/CallFrame.h b/Source/JavaScriptCore/interpreter/CallFrame.h
index 9f51f39..3dceb2f 100644
--- a/Source/JavaScriptCore/interpreter/CallFrame.h
+++ b/Source/JavaScriptCore/interpreter/CallFrame.h
@@ -28,6 +28,7 @@
#include "JSStack.h"
#include "MacroAssemblerCodeRef.h"
#include "Register.h"
+#include "StackIteratorPrivate.h"
namespace JSC {
@@ -274,21 +275,13 @@
#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;
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index 79fa7cf..bbe90d3 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -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 @@
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 @@
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 @@
#endif
}
-NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
+NEVER_INLINE bool Interpreter::unwindCallFrame(StackIterator& iter, JSValue exceptionValue)
{
+ CallFrame* callFrame = iter->callFrame();
+ CodeBlock* codeBlock = iter->codeBlock();
CodeBlock* oldCodeBlock = codeBlock;
JSScope* scope = callFrame->scope();
@@ -407,10 +410,7 @@
CallFrame* callerFrame = callFrame->callerFrame();
callFrame->vm().topCallFrame = callerFrame;
- if (callerFrame->hasHostCallFrameFlag())
- return false;
- callFrame = getCallerInfo(&callFrame->vm(), callFrame, bytecodeOffset, codeBlock);
- return true;
+ return !callerFrame->hasHostCallFrameFlag();
}
static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
@@ -467,61 +467,24 @@
exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message));
}
-static unsigned getBytecodeOffsetForCallFrame(CallFrame* callFrame)
-{
- callFrame = callFrame->removeHostCallFrameFlag();
- CodeBlock* codeBlock = callFrame->codeBlock();
- if (!codeBlock)
- return 0;
-#if ENABLE(DFG_JIT)
- if (JITCode::isOptimizingJIT(codeBlock->jitType()))
- return codeBlock->codeOrigin(callFrame->locationAsCodeOriginIndex()).bytecodeIndex;
-#endif
- return callFrame->locationAsBytecodeOffset();
-}
-
-static CallFrame* getCallerInfo(VM* vm, CallFrame* callFrame, unsigned& bytecodeOffset, CodeBlock*& caller)
-{
- ASSERT_UNUSED(vm, vm);
- bytecodeOffset = 0;
- ASSERT(!callFrame->hasHostCallFrameFlag());
- CallFrame* trueCallerFrame = callFrame->trueCallerFrame();
- ASSERT(!trueCallerFrame->hasHostCallFrameFlag());
-
- if (trueCallerFrame == CallFrame::noCaller() || !trueCallerFrame || !trueCallerFrame->codeBlock()) {
- caller = 0;
- return trueCallerFrame;
- }
-
- CodeBlock* callerCodeBlock = trueCallerFrame->codeBlock();
-#if ENABLE(DFG_JIT)
- if (trueCallerFrame->hasLocationAsCodeOriginIndex())
- bytecodeOffset = trueCallerFrame->bytecodeOffsetFromCodeOriginIndex();
- else
-#endif // ENABLE(DFG_JIT)
- bytecodeOffset = trueCallerFrame->locationAsBytecodeOffset();
-
- caller = callerCodeBlock;
- return trueCallerFrame;
-}
-
static ALWAYS_INLINE const String getSourceURLFromCallFrame(CallFrame* callFrame)
{
ASSERT(!callFrame->hasHostCallFrameFlag());
return callFrame->codeBlock()->ownerExecutable()->sourceURL();
}
-static StackFrameCodeType getStackFrameCodeType(CallFrame* callFrame)
+static StackFrameCodeType getStackFrameCodeType(StackIterator iter)
{
- ASSERT(!callFrame->hasHostCallFrameFlag());
-
- switch (callFrame->codeBlock()->codeType()) {
- case EvalCode:
+ switch (iter->codeType()) {
+ case StackIterator::Frame::Eval:
return StackFrameEvalCode;
- case FunctionCode:
+ case StackIterator::Frame::Function:
return StackFrameFunctionCode;
- case GlobalCode:
+ case StackIterator::Frame::Global:
return StackFrameGlobalCode;
+ case StackIterator::Frame::Native:
+ ASSERT_NOT_REACHED();
+ return StackFrameNativeCode;
}
RELEASE_ASSERT_NOT_REACHED();
return StackFrameGlobalCode;
@@ -576,40 +539,33 @@
return traceBuild.toString().impl();
}
-void Interpreter::getStackTrace(VM* vm, Vector<StackFrame>& results, size_t maxStackSize)
+void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t maxStackSize)
{
- CallFrame* callFrame = vm->topCallFrame->removeHostCallFrameFlag();
- if (!callFrame || callFrame == CallFrame::noCaller())
- return;
- unsigned bytecodeOffset = getBytecodeOffsetForCallFrame(callFrame);
- callFrame = callFrame->trueCallFrame();
+ VM& vm = m_vm;
+ CallFrame* callFrame = vm.topCallFrame->removeHostCallFrameFlag();
if (!callFrame)
return;
- CodeBlock* callerCodeBlock = callFrame->codeBlock();
-
- while (callFrame && callFrame != CallFrame::noCaller() && maxStackSize--) {
- String sourceURL;
- if (callerCodeBlock) {
- sourceURL = getSourceURLFromCallFrame(callFrame);
+ StackIterator iter = callFrame->begin();
+ for (; iter != callFrame->end() && maxStackSize--; ++iter) {
+ if (iter->isJSFrame()) {
+ CodeBlock* codeBlock = iter->codeBlock();
StackFrame s = {
- Strong<JSObject>(*vm, callFrame->callee()),
- getStackFrameCodeType(callFrame),
- Strong<ExecutableBase>(*vm, callerCodeBlock->ownerExecutable()),
- Strong<UnlinkedCodeBlock>(*vm, callerCodeBlock->unlinkedCodeBlock()),
- callerCodeBlock->source(),
- callerCodeBlock->ownerExecutable()->lineNo(),
- callerCodeBlock->firstLineColumnOffset(),
- callerCodeBlock->sourceOffset(),
- bytecodeOffset,
- sourceURL
+ Strong<JSObject>(vm, iter->callee()),
+ getStackFrameCodeType(iter),
+ Strong<ExecutableBase>(vm, codeBlock->ownerExecutable()),
+ Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()),
+ codeBlock->source(),
+ codeBlock->ownerExecutable()->lineNo(),
+ codeBlock->firstLineColumnOffset(),
+ codeBlock->sourceOffset(),
+ iter->bytecodeOffset(),
+ iter->sourceURL()
};
-
results.append(s);
} else {
- StackFrame s = { Strong<JSObject>(*vm, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()};
+ StackFrame s = { Strong<JSObject>(vm, iter->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()};
results.append(s);
}
- callFrame = getCallerInfo(vm, callFrame, bytecodeOffset, callerCodeBlock);
}
}
@@ -624,7 +580,7 @@
}
Vector<StackFrame> stackTrace;
- getStackTrace(&callFrame->vm(), stackTrace);
+ vm->interpreter->getStackTrace(stackTrace);
vm->exceptionStack() = RefCountedArray<StackFrame>(stackTrace);
if (stackTrace.isEmpty() || !error.isObject())
return;
@@ -676,7 +632,7 @@
} else {
if (!callFrame->vm().exceptionStack().size()) {
Vector<StackFrame> stack;
- Interpreter::getStackTrace(&callFrame->vm(), stack);
+ callFrame->vm().interpreter->getStackTrace(stack);
callFrame->vm().exceptionStack() = RefCountedArray<StackFrame>(stack);
}
}
@@ -689,12 +645,21 @@
// Calculate an exception handler vPC, unwinding call frames as necessary.
HandlerInfo* handler = 0;
- while (isTermination || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
- if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
- if (LegacyProfiler* profiler = callFrame->vm().enabledProfiler())
- profiler->exceptionUnwind(callFrame);
- return 0;
- }
+ VM& vm = callFrame->vm();
+ ASSERT(callFrame == vm.topCallFrame);
+ for (StackIterator iter = callFrame->begin(); iter != callFrame->end(); ++iter) {
+ callFrame = iter->callFrame();
+ codeBlock = iter->codeBlock();
+ bytecodeOffset = iter->bytecodeOffset();
+
+ if (isTermination || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
+ if (!unwindCallFrame(iter, exceptionValue)) {
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->exceptionUnwind(callFrame);
+ return 0;
+ }
+ } else
+ break;
}
if (LegacyProfiler* profiler = callFrame->vm().enabledProfiler())
@@ -1287,57 +1252,7 @@
debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine, column);
return;
}
-}
-
-JSValue Interpreter::retrieveArgumentsFromVMCode(CallFrame* callFrame, JSFunction* function) const
-{
- CallFrame* functionCallFrame = findFunctionCallFrameFromVMCode(callFrame, function);
- if (!functionCallFrame)
- return jsNull();
-
- Arguments* arguments = Arguments::create(functionCallFrame->vm(), functionCallFrame);
- arguments->tearOff(functionCallFrame);
- return JSValue(arguments);
-}
-
-JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction* function) const
-{
- CallFrame* functionCallFrame = findFunctionCallFrameFromVMCode(callFrame, function);
-
- if (!functionCallFrame)
- return jsNull();
-
- unsigned bytecodeOffset;
- CodeBlock* unusedCallerCodeBlock = 0;
- CallFrame* callerFrame = getCallerInfo(&callFrame->vm(), functionCallFrame, bytecodeOffset, unusedCallerCodeBlock);
- if (!callerFrame)
- return jsNull();
- JSValue caller = callerFrame->callee();
- if (!caller)
- return jsNull();
-
- // Skip over function bindings.
- ASSERT(caller.isObject());
- while (asObject(caller)->inherits(&JSBoundFunction::s_info)) {
- callerFrame = getCallerInfo(&callFrame->vm(), callerFrame, bytecodeOffset, unusedCallerCodeBlock);
- if (!callerFrame)
- return jsNull();
- caller = callerFrame->callee();
- if (!caller)
- return jsNull();
- }
-
- return caller;
-}
-
-CallFrame* Interpreter::findFunctionCallFrameFromVMCode(CallFrame* callFrame, JSFunction* function)
-{
- for (CallFrame* candidate = callFrame->trueCallFrame(); candidate; candidate = candidate->trueCallerFrame()) {
- if (candidate->callee() == function)
- return candidate;
- }
- return 0;
-}
+}
void Interpreter::enableSampler()
{
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.h b/Source/JavaScriptCore/interpreter/Interpreter.h
index 3ac1472..9b39018 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.h
+++ b/Source/JavaScriptCore/interpreter/Interpreter.h
@@ -55,6 +55,7 @@
class Register;
class JSScope;
class SamplingTool;
+ class StackIterator;
struct CallFrameClosure;
struct HandlerInfo;
struct Instruction;
@@ -210,9 +211,6 @@
JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&);
JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, JSScope*);
- JSValue retrieveArgumentsFromVMCode(CallFrame*, JSFunction*) const;
- JSValue retrieveCallerFromVMCode(CallFrame*, JSFunction*) const;
-
void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
SamplingTool* sampler() { return m_sampler.get(); }
@@ -221,8 +219,6 @@
NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine, int column);
- static const String getTraceLine(CallFrame*, StackFrameCodeType, const String&, int);
- JS_EXPORT_PRIVATE static void getStackTrace(VM*, Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
static void addStackTraceIfNecessary(CallFrame*, JSValue error);
void dumpSampleData(ExecState* exec);
@@ -238,9 +234,8 @@
void endRepeatCall(CallFrameClosure&);
JSValue execute(CallFrameClosure&);
- NEVER_INLINE bool unwindCallFrame(CallFrame*&, JSValue, unsigned& bytecodeOffset, CodeBlock*&);
-
- static CallFrame* findFunctionCallFrameFromVMCode(CallFrame*, JSFunction*);
+ void getStackTrace(Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
+ NEVER_INLINE bool unwindCallFrame(StackIterator&, JSValue);
void dumpRegisters(CallFrame*);
diff --git a/Source/JavaScriptCore/interpreter/StackIterator.cpp b/Source/JavaScriptCore/interpreter/StackIterator.cpp
new file mode 100644
index 0000000..e550070
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/StackIterator.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StackIterator.h"
+
+#include "Arguments.h"
+#include "CallFrameInlines.h"
+#include "Executable.h"
+#include "Operations.h"
+#include <wtf/DataLog.h>
+
+namespace JSC {
+
+StackIterator::StackIterator(CallFrame* frame, StackIterator::FrameFilter filter)
+ : m_filter(filter)
+{
+ ASSERT(frame);
+ m_frame = Frame::create(frame);
+ m_frame = m_frame->logicalFrame();
+}
+
+void StackIterator::gotoNextFrame()
+{
+ Frame* frame = m_frame;
+ while (frame) {
+ frame = frame->logicalCallerFrame();
+ if (!frame || !m_filter || !m_filter(frame))
+ break;
+ }
+ m_frame = frame;
+}
+
+void StackIterator::find(JSFunction* functionObj)
+{
+ ASSERT(functionObj);
+ JSObject* targetCallee = jsDynamicCast<JSObject*>(functionObj);
+ while (m_frame) {
+ if (m_frame->callee() == targetCallee)
+ break;
+ gotoNextFrame();
+ }
+}
+
+StackIterator::Frame::CodeType StackIterator::Frame::codeType() const
+{
+ if (!isJSFrame())
+ return CodeType::Native;
+
+ switch (codeBlock()->codeType()) {
+ case EvalCode:
+ return CodeType::Eval;
+ case FunctionCode:
+ return CodeType::Function;
+ case GlobalCode:
+ return CodeType::Global;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return CodeType::Global;
+}
+
+String StackIterator::Frame::functionName()
+{
+ String traceLine;
+ JSObject* callee = this->callee();
+
+ switch (codeType()) {
+ case CodeType::Eval:
+ traceLine = "eval code";
+ break;
+ case CodeType::Native:
+ if (callee)
+ traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
+ break;
+ case CodeType::Function:
+ traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
+ break;
+ case CodeType::Global:
+ traceLine = "global code";
+ break;
+ }
+ return traceLine.isNull() ? emptyString() : traceLine;
+}
+
+String StackIterator::Frame::sourceURL()
+{
+ String traceLine;
+
+ switch (codeType()) {
+ case CodeType::Eval:
+ case CodeType::Function:
+ case CodeType::Global: {
+ String sourceURL = codeBlock()->ownerExecutable()->sourceURL();
+ if (!sourceURL.isEmpty())
+ traceLine = sourceURL.impl();
+ break;
+ }
+ case CodeType::Native:
+ traceLine = "[native code]";
+ break;
+ }
+ return traceLine.isNull() ? emptyString() : traceLine;
+}
+
+String StackIterator::Frame::toString()
+{
+ StringBuilder traceBuild;
+ String functionName = this->functionName();
+ String sourceURL = this->sourceURL();
+ traceBuild.append(functionName);
+ if (!sourceURL.isEmpty()) {
+ if (!functionName.isEmpty())
+ traceBuild.append('@');
+ traceBuild.append(sourceURL);
+ if (isJSFrame()) {
+ unsigned line = 0;
+ unsigned column = 0;
+ computeLineAndColumn(line, column);
+ traceBuild.append(':');
+ traceBuild.appendNumber(line);
+ traceBuild.append(':');
+ traceBuild.appendNumber(column);
+ }
+ }
+ return traceBuild.toString().impl();
+}
+
+unsigned StackIterator::Frame::bytecodeOffset()
+{
+ if (!isJSFrame())
+ return 0;
+ if (hasLocationAsCodeOriginIndex())
+ return bytecodeOffsetFromCodeOriginIndex();
+ return locationAsBytecodeOffset();
+}
+
+Arguments* StackIterator::Frame::arguments()
+{
+ CallFrame* callFrame = this->callFrame();
+ Arguments* arguments = Arguments::create(vm(), callFrame);
+ arguments->tearOff(callFrame);
+ return arguments;
+}
+
+void StackIterator::Frame::computeLineAndColumn(unsigned& line, unsigned& column)
+{
+ CodeBlock* codeBlock = this->codeBlock();
+ if (!codeBlock) {
+ line = 0;
+ column = 0;
+ return;
+ }
+
+ int divot = 0;
+ int unusedStartOffset = 0;
+ int unusedEndOffset = 0;
+ unsigned divotLine = 0;
+ unsigned divotColumn = 0;
+ retrieveExpressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn);
+
+ line = divotLine + codeBlock->ownerExecutable()->lineNo();
+ column = divotColumn + (divotLine ? 1 : codeBlock->firstLineColumnOffset());
+}
+
+void StackIterator::Frame::retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
+{
+ CodeBlock* codeBlock = this->codeBlock();
+ codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeOffset(bytecodeOffset(), divot, startOffset, endOffset, line, column);
+ divot += codeBlock->sourceOffset();
+}
+
+
+StackIterator::Frame* StackIterator::Frame::logicalFrame()
+{
+#if !ENABLE(DFG_JIT)
+ return this;
+
+#else // !ENABLE(DFG_JIT)
+ 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* codeBlock = this->codeBlock();
+ if (!codeBlock)
+ return this;
+
+ // If the code block does not have any code origins, then there was no inlining, so
+ // I'm done.
+ if (!codeBlock->hasCodeOrigins())
+ return this;
+
+ CodeBlock* outerMostCodeBlock = codeBlock;
+ unsigned index = locationAsCodeOriginIndex();
+ ASSERT(outerMostCodeBlock->canGetCodeOrigin(index));
+ if (!outerMostCodeBlock->canGetCodeOrigin(index)) {
+ // See above. In release builds, we try to protect ourselves from crashing even
+ // though stack walking will be goofed up.
+ return nullptr;
+ }
+
+ CodeOrigin codeOrigin = outerMostCodeBlock->codeOrigin(index);
+ if (!codeOrigin.inlineCallFrame)
+ return this; // Not currently in inlined code.
+
+ // We've got inlined frames. So, reify them so that the iterator can walk through them.
+ CallFrame* currFrame = this->callFrame();
+ CallFrame* innerMostLogicalFrame = currFrame + codeOrigin.inlineCallFrame->stackOffset;
+
+ CallFrame* logicalFrame = innerMostLogicalFrame;
+ while (logicalFrame != currFrame) {
+ InlineCallFrame* inlinedFrameInfo = codeOrigin.inlineCallFrame;
+
+ // Fill in the logical (i.e. inlined) frame
+ logicalFrame->setCodeBlock(inlinedFrameInfo->baselineCodeBlock());
+ logicalFrame->setInlineCallFrame(inlinedFrameInfo);
+ logicalFrame->setArgumentCountIncludingThis(inlinedFrameInfo->arguments.size());
+ logicalFrame->setLocationAsBytecodeOffset(codeOrigin.bytecodeIndex);
+ logicalFrame->setIsInlinedFrame();
+
+ JSFunction* callee = inlinedFrameInfo->callee.get();
+ if (callee) {
+ logicalFrame->setScope(callee->scope());
+ logicalFrame->setCallee(callee);
+ }
+
+ CodeOrigin* callerCodeOrigin = &inlinedFrameInfo->caller;
+ InlineCallFrame* callerInlinedFrameInfo = callerCodeOrigin->inlineCallFrame;
+ unsigned callerFrameOffset = callerInlinedFrameInfo ? callerInlinedFrameInfo->stackOffset : 0;
+ CallFrame* callerFrame = currFrame + callerFrameOffset;
+ logicalFrame->setCallerFrame(callerFrame);
+
+ codeOrigin = *callerCodeOrigin;
+ logicalFrame = callerFrame;
+ }
+
+ ASSERT(!innerMostLogicalFrame->hasHostCallFrameFlag());
+ return Frame::create(innerMostLogicalFrame);
+#endif // !ENABLE(DFG_JIT)
+}
+
+StackIterator::Frame* StackIterator::Frame::logicalCallerFrame()
+{
+ Frame* callerFrame = create(this->callerFrame()->removeHostCallFrameFlag());
+#if !ENABLE(DFG_JIT)
+ return callerFrame;
+
+#else // !ENABLE(DFG_JIT)
+ if (!isJSFrame() || !callerFrame)
+ return callerFrame;
+
+ // If I am known to be an inlined frame, then I've been reified already and
+ // have my caller.
+ if (isInlinedFrame())
+ return callerFrame;
+
+ // I am not an inlined frame. So the question is: is my caller a CallFrame
+ // that has inlines or a CallFrame that doesn't?
+
+ // If my caller is not a JS frame, it cannot have inlines, and we're done.
+ if (!callerFrame->isJSFrame())
+ return callerFrame;
+
+ ASSERT(!callerFrame->isInlinedFrame());
+ return callerFrame->logicalFrame();
+
+#endif // !ENABLE(DFG_JIT)
+}
+
+#ifndef NDEBUG
+
+static const char* jitTypeName(JITCode::JITType jitType)
+{
+ switch (jitType) {
+ case JITCode::None: return "None";
+ case JITCode::HostCallThunk: return "HostCallThunk";
+ case JITCode::InterpreterThunk: return "InterpreterThunk";
+ case JITCode::BaselineJIT: return "BaselineJIT";
+ case JITCode::DFGJIT: return "DFGJIT";
+ case JITCode::FTLJIT: return "FTLJIT";
+ }
+ return "<unknown>";
+}
+
+static void printIndents(int levels)
+{
+ while (levels--)
+ dataLogFString(" ");
+}
+
+static void printif(int indentLevels, const char* format, ...)
+{
+ va_list argList;
+ va_start(argList, format);
+
+ if (indentLevels)
+ printIndents(indentLevels);
+
+#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+
+ WTF::dataLogFV(format, argList);
+
+#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
+#pragma GCC diagnostic pop
+#endif
+
+ va_end(argList);
+}
+
+void StackIterator::Frame::print(int indentLevel)
+{
+ int i = indentLevel;
+
+ CodeBlock* codeBlock = this->codeBlock();
+ printif(i, "frame %p {\n", this);
+
+ CallFrame* callerFrame = this->callerFrame();
+ void* returnPC = hasReturnPC()? this->returnPC().value() : nullptr;
+
+ printif(i, " name '%s'\n", functionName().utf8().data());
+ printif(i, " sourceURL '%s'\n", sourceURL().utf8().data());
+ printif(i, " hostFlag %d\n", callerFrame->hasHostCallFrameFlag());
+ printif(i, " isInlinedFrame %d\n", isInlinedFrame());
+
+ if (isInlinedFrame())
+ printif(i, " InlineCallFrame %p\n", this->inlineCallFrame());
+
+ printif(i, " callee %p\n", callee());
+ printif(i, " returnPC %p\n", returnPC);
+ printif(i, " callerFrame %p\n", callerFrame->removeHostCallFrameFlag());
+ printif(i, " logicalCallerFrame %p\n", logicalCallerFrame());
+ printif(i, " rawLocationBits %u 0x%x\n", locationAsRawBits(), locationAsRawBits());
+ printif(i, " codeBlock %p\n", codeBlock);
+ if (codeBlock) {
+ JITCode::JITType jitType = codeBlock->jitType();
+ if (hasLocationAsBytecodeOffset()) {
+ unsigned bytecodeOffset = locationAsBytecodeOffset();
+ printif(i, " bytecodeOffset %u %p / %zu\n", bytecodeOffset, reinterpret_cast<void*>(bytecodeOffset), codeBlock->instructions().size());
+ } else {
+ unsigned codeOriginIndex = locationAsCodeOriginIndex();
+ printif(i, " codeOriginIdex %u %p / %zu\n", codeOriginIndex, reinterpret_cast<void*>(codeOriginIndex), codeBlock->codeOrigins().size());
+ }
+ unsigned line = 0;
+ unsigned column = 0;
+ computeLineAndColumn(line, column);
+ printif(i, " line %d\n", line);
+ printif(i, " column %d\n", column);
+ printif(i, " jitType %d <%s> isOptimizingJIT %d\n", jitType, jitTypeName(jitType), JITCode::isOptimizingJIT(jitType));
+ printif(i, " hasCodeOrigins %d\n", codeBlock->hasCodeOrigins());
+ if (codeBlock->hasCodeOrigins()) {
+ JITCode* jitCode = codeBlock->jitCode().get();
+ printif(i, " jitCode %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
+ }
+ }
+ printif(i, "}\n");
+}
+
+#endif // NDEBUG
+
+} // namespace JSC
+
+#ifndef NDEBUG
+// For use in the debugger
+void debugPrintCallFrame(JSC::CallFrame*);
+
+void debugPrintCallFrame(JSC::CallFrame* callFrame)
+{
+ if (!callFrame)
+ return;
+ JSC::StackIterator::Frame* frame = JSC::StackIterator::Frame::create(callFrame);
+ frame->print(2);
+}
+#endif // !NDEBUG
diff --git a/Source/JavaScriptCore/interpreter/StackIterator.h b/Source/JavaScriptCore/interpreter/StackIterator.h
new file mode 100644
index 0000000..00240680
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/StackIterator.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StackIterator_h
+#define StackIterator_h
+
+#include "CallFrame.h"
+#include "Interpreter.h"
+#include "StackIteratorPrivate.h"
+
+namespace JSC {
+
+class Arguments;
+
+class StackIterator::Frame : public CallFrame {
+public:
+ enum CodeType {
+ Global = StackFrameGlobalCode,
+ Eval = StackFrameEvalCode,
+ Function = StackFrameFunctionCode,
+ Native = StackFrameNativeCode
+ };
+
+ static Frame* create(CallFrame* f) { return reinterpret_cast<Frame*>(f); }
+
+ bool isJSFrame() const { return !!codeBlock(); }
+
+ JS_EXPORT_PRIVATE String functionName();
+ JS_EXPORT_PRIVATE String sourceURL();
+ JS_EXPORT_PRIVATE String toString();
+
+ CodeType codeType() const;
+ unsigned bytecodeOffset();
+ JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column);
+
+ Arguments* arguments();
+ CallFrame* callFrame() { return reinterpret_cast<CallFrame*>(this); }
+
+ Frame* logicalFrame();
+ Frame* logicalCallerFrame();
+
+#ifndef NDEBUG
+ JS_EXPORT_PRIVATE void print(int indentLevel);
+#endif
+
+private:
+ Frame();
+ ~Frame();
+
+ void retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column);
+};
+
+} // namespace JSC
+
+#endif // StackIterator_h
+
diff --git a/Source/JavaScriptCore/interpreter/StackIteratorPrivate.h b/Source/JavaScriptCore/interpreter/StackIteratorPrivate.h
new file mode 100644
index 0000000..c057152
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/StackIteratorPrivate.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StackIteratorPrivate_h
+#define StackIteratorPrivate_h
+
+namespace JSC {
+
+class ExecState;
+class JSFunction;
+class VM;
+
+typedef ExecState CallFrame;
+
+class StackIterator {
+public:
+ class Frame;
+ typedef bool (*FrameFilter)(Frame*);
+
+ Frame& operator*() { return *m_frame; }
+ ALWAYS_INLINE Frame* operator->() { return m_frame; }
+
+ bool operator==(Frame* frame) { return m_frame == frame; }
+ bool operator!=(Frame* frame) { return m_frame != frame; }
+ void operator++() { gotoNextFrame(); }
+ void find(JSFunction*);
+
+private:
+ JS_EXPORT_PRIVATE StackIterator(CallFrame* startFrame, FrameFilter = nullptr);
+
+ static Frame* end() { return nullptr; }
+ JS_EXPORT_PRIVATE void gotoNextFrame();
+
+ Frame* m_frame;
+ FrameFilter m_filter;
+
+ friend class ExecState;
+};
+
+} // namespace JSC
+
+#endif // StackIteratorPrivate_h
+
diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp
index 4404faa..3e6d4ab 100644
--- a/Source/JavaScriptCore/jsc.cpp
+++ b/Source/JavaScriptCore/jsc.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2006 Bjoern Graf (bjoern.graf@gmail.com)
*
* This library is free software; you can redistribute it and/or
@@ -25,6 +25,7 @@
#include "APIShims.h"
#include "ButterflyInlines.h"
#include "BytecodeGenerator.h"
+#include "CallFrameInlines.h"
#include "Completion.h"
#include "CopiedSpaceInlines.h"
#include "ExceptionHelpers.h"
@@ -39,6 +40,7 @@
#include "JSString.h"
#include "Operations.h"
#include "SamplingTool.h"
+#include "StackIterator.h"
#include "StructureRareDataInlines.h"
#include <math.h>
#include <stdio.h>
@@ -340,15 +342,9 @@
StringBuilder trace;
trace.appendLiteral("--> Stack trace:\n");
- Vector<StackFrame> stackTrace;
- Interpreter::getStackTrace(&exec->vm(), stackTrace);
int i = 0;
-
- for (Vector<StackFrame>::iterator iter = stackTrace.begin(); iter < stackTrace.end(); iter++) {
- StackFrame level = *iter;
- trace.append(String::format(" %i %s\n", i, level.toString(exec).utf8().data()));
- i++;
- }
+ for (StackIterator iter = exec->begin(); iter != exec->end(); ++iter, ++i)
+ trace.append(String::format(" %i %s\n", i, iter->toString().utf8().data()));
fprintf(stderr, "%s", trace.toString().utf8().data());
return JSValue::encode(jsUndefined());
}
diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp
index 820868b..6990395 100644
--- a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp
+++ b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp
@@ -27,14 +27,15 @@
#include "ProfileGenerator.h"
#include "CallFrame.h"
+#include "CallFrameInlines.h"
#include "CodeBlock.h"
#include "JSGlobalObject.h"
#include "JSStringRef.h"
#include "JSFunction.h"
-#include "Interpreter.h"
#include "LegacyProfiler.h"
#include "Operations.h"
#include "Profile.h"
+#include "StackIterator.h"
#include "Tracing.h"
namespace JSC {
@@ -58,14 +59,17 @@
void ProfileGenerator::addParentForConsoleStart(ExecState* exec)
{
- Vector<StackFrame> stackTrace;
- Interpreter::getStackTrace(&exec->vm(), stackTrace, 2);
- if (stackTrace.size() < 2)
+ StackIterator iter = exec->begin();
+ ++iter;
+ if (iter == exec->end()) {
+ m_currentNode = ProfileNode::create(exec, LegacyProfiler::createCallIdentifier(exec, JSValue(), String(), 0), m_head.get(), m_head.get());
+ m_head->insertNode(m_currentNode.get());
return;
+ }
unsigned line = 0;
unsigned unusedColumn = 0;
- stackTrace[1].computeLineAndColumn(line, unusedColumn);
- m_currentNode = ProfileNode::create(exec, LegacyProfiler::createCallIdentifier(exec, stackTrace[1].callee.get(), stackTrace[1].sourceURL, line), m_head.get(), m_head.get());
+ iter->computeLineAndColumn(line, unusedColumn);
+ m_currentNode = ProfileNode::create(exec, LegacyProfiler::createCallIdentifier(exec, iter->callee(), iter->sourceURL(), line), m_head.get(), m_head.get());
m_head->insertNode(m_currentNode.get());
}
diff --git a/Source/JavaScriptCore/profiler/ProfileNode.h b/Source/JavaScriptCore/profiler/ProfileNode.h
index f5fef86..9997aa5 100644
--- a/Source/JavaScriptCore/profiler/ProfileNode.h
+++ b/Source/JavaScriptCore/profiler/ProfileNode.h
@@ -40,7 +40,6 @@
class ExecState;
class ProfileNode;
- typedef Vector<RefPtr<ProfileNode> >::const_iterator StackIterator;
typedef HashCountedSet<StringImpl*> FunctionCallHashCount;
class ProfileNode : public RefCounted<ProfileNode> {
@@ -131,6 +130,8 @@
#endif
private:
+ typedef Vector<RefPtr<ProfileNode> >::const_iterator StackIterator;
+
ProfileNode(ExecState* callerCallFrame, const CallIdentifier&, ProfileNode* headNode, ProfileNode* parentNode);
ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy);
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 3b89f6d..0774e04 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -25,13 +25,16 @@
#include "config.h"
#include "JSFunction.h"
+#include "Arguments.h"
#include "CodeBlock.h"
#include "CommonIdentifiers.h"
#include "CallFrame.h"
+#include "CallFrameInlines.h"
#include "ExceptionHelpers.h"
#include "FunctionPrototype.h"
#include "GetterSetter.h"
#include "JSArray.h"
+#include "JSBoundFunction.h"
#include "JSGlobalObject.h"
#include "JSNotAnObject.h"
#include "Interpreter.h"
@@ -40,6 +43,7 @@
#include "Operations.h"
#include "Parser.h"
#include "PropertyNameArray.h"
+#include "StackIterator.h"
using namespace WTF;
using namespace Unicode;
@@ -178,18 +182,40 @@
return CallTypeJS;
}
+static JSValue retrieveArguments(ExecState* exec, JSFunction* functionObj)
+{
+ StackIterator iter = exec->find(functionObj);
+ return iter != exec->end() ? JSValue(iter->arguments()) : jsNull();
+}
+
JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, PropertyName)
{
JSFunction* thisObj = jsCast<JSFunction*>(slotBase);
ASSERT(!thisObj->isHostFunction());
- return exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObj);
+
+ return retrieveArguments(exec, thisObj);
+}
+
+static bool skipOverBoundFunctions(StackIterator::Frame* frame)
+{
+ JSObject* callee = frame->callee();
+ bool shouldSkip = callee ? callee->inherits(&JSBoundFunction::s_info) : false;
+ return shouldSkip;
+}
+
+static JSValue retrieveCallerFunction(ExecState* exec, JSFunction* functionObj)
+{
+ StackIterator iter = exec->find(functionObj, skipOverBoundFunctions);
+ if (iter != exec->end())
+ ++iter;
+ return iter != exec->end() && iter->callee() ? iter->callee() : jsNull();
}
JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, PropertyName)
{
JSFunction* thisObj = jsCast<JSFunction*>(slotBase);
ASSERT(!thisObj->isHostFunction());
- JSValue caller = exec->interpreter()->retrieveCallerFromVMCode(exec, thisObj);
+ JSValue caller = retrieveCallerFunction(exec, thisObj);
// See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller.
if (!caller.isObject() || !asObject(caller)->inherits(&JSFunction::s_info))
@@ -297,7 +323,7 @@
}
return result;
}
- descriptor.setDescriptor(exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject), ReadOnly | DontEnum | DontDelete);
+ descriptor.setDescriptor(retrieveArguments(exec, thisObject), ReadOnly | DontEnum | DontDelete);
return true;
}
@@ -321,7 +347,7 @@
}
return result;
}
- descriptor.setDescriptor(exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject), ReadOnly | DontEnum | DontDelete);
+ descriptor.setDescriptor(retrieveCallerFunction(exec, thisObject), ReadOnly | DontEnum | DontDelete);
return true;
}
@@ -415,14 +441,14 @@
thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
- valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject));
+ valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), retrieveArguments(exec, thisObject));
} else if (propertyName == exec->propertyNames().caller) {
if (thisObject->jsExecutable()->isStrictMode()) {
if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor))
thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
- valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject));
+ valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), retrieveCallerFunction(exec, thisObject));
} else if (propertyName == exec->propertyNames().length)
valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount()));
else if (propertyName == exec->propertyNames().name)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
index dafc5f6..c42d2d4 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
@@ -26,6 +26,7 @@
#include "JSGlobalObjectFunctions.h"
#include "CallFrame.h"
+#include "CallFrameInlines.h"
#include "Interpreter.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
@@ -36,6 +37,7 @@
#include "Nodes.h"
#include "Operations.h"
#include "Parser.h"
+#include "StackIterator.h"
#include <wtf/dtoa.h>
#include <stdio.h>
#include <stdlib.h>
@@ -712,7 +714,9 @@
if (!thisObject)
return JSValue::encode(exec->thisValue().synthesizePrototype(exec));
- if (!thisObject->allowsAccessFrom(exec->trueCallerFrame()))
+ StackIterator iter = exec->begin();
+ ++iter;
+ if ((iter == exec->end()) || !thisObject->allowsAccessFrom(iter->callFrame()))
return JSValue::encode(jsUndefined());
return JSValue::encode(thisObject->prototype());
@@ -728,7 +732,9 @@
if (!thisObject)
return JSValue::encode(jsUndefined());
- if (!thisObject->allowsAccessFrom(exec->trueCallerFrame()))
+ StackIterator iter = exec->begin();
+ ++iter;
+ if ((iter == exec->end()) || !thisObject->allowsAccessFrom(iter->callFrame()))
return JSValue::encode(jsUndefined());
// Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
index d72cbe8..01a3a13 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -22,6 +22,7 @@
#include "ObjectConstructor.h"
#include "ButterflyInlines.h"
+#include "CallFrameInlines.h"
#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "ExceptionHelpers.h"
@@ -33,6 +34,7 @@
#include "Operations.h"
#include "PropertyDescriptor.h"
#include "PropertyNameArray.h"
+#include "StackIterator.h"
namespace JSC {
@@ -139,7 +141,9 @@
if (!exec->argument(0).isObject())
return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested prototype of a value that is not an object.")));
JSObject* object = asObject(exec->argument(0));
- if (!object->allowsAccessFrom(exec->trueCallerFrame()))
+ StackIterator iter = exec->begin();
+ ++iter;
+ if ((iter == exec->end()) || !object->allowsAccessFrom(iter->callFrame()))
return JSValue::encode(jsUndefined());
return JSValue::encode(object->prototype());
}
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 4babe2d..c107a76 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,18 @@
+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.
+
+ No new tests.
+
+ * ForwardingHeaders/interpreter/StackIterator.h: Added.
+ * bindings/js/JSXMLHttpRequestCustom.cpp:
+ (WebCore::JSXMLHttpRequest::send):
+ * bindings/js/ScriptCallStackFactory.cpp:
+ (WebCore::createScriptCallStack):
+
2013-06-09 Filip Pizlo <fpizlo@apple.com>
Unreviewed, fix build. Use at() instead of operator[] because of ambiguity on some compilers.
diff --git a/Source/WebCore/ForwardingHeaders/interpreter/CallFrameInlines.h b/Source/WebCore/ForwardingHeaders/interpreter/CallFrameInlines.h
new file mode 100644
index 0000000..9f68b7c
--- /dev/null
+++ b/Source/WebCore/ForwardingHeaders/interpreter/CallFrameInlines.h
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_CallFrameInlines_h
+#define WebCore_FWD_CallFrameInlines_h
+#include <JavaScriptCore/CallFrameInlines.h>
+#endif
diff --git a/Source/WebCore/ForwardingHeaders/interpreter/StackIterator.h b/Source/WebCore/ForwardingHeaders/interpreter/StackIterator.h
new file mode 100644
index 0000000..977e337
--- /dev/null
+++ b/Source/WebCore/ForwardingHeaders/interpreter/StackIterator.h
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_StackIterator_h
+#define WebCore_FWD_StackIterator_h
+#include <JavaScriptCore/StackIterator.h>
+#endif
diff --git a/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp b/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp
index 230f115..2b799c5 100644
--- a/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp
+++ b/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp
@@ -47,8 +47,7 @@
#include "JSEvent.h"
#include "JSEventListener.h"
#include "XMLHttpRequest.h"
-#include <interpreter/Interpreter.h>
-#include <parser/SourceProvider.h>
+#include <interpreter/StackIterator.h>
#include <runtime/Error.h>
#include <wtf/ArrayBuffer.h>
@@ -134,14 +133,17 @@
impl()->send(val.toString(exec)->value(exec), ec);
}
- Vector<StackFrame> stackTrace(2);
- Interpreter::getStackTrace(&exec->vm(), stackTrace, 2);
- if (stackTrace.size() == 2) {
+ StackIterator iter = exec->begin();
+ ++iter;
+ if (iter != exec->end()) {
unsigned line = 0;
unsigned unusuedColumn = 0;
- stackTrace[1].computeLineAndColumn(line, unusuedColumn);
+ iter->computeLineAndColumn(line, unusuedColumn);
impl()->setLastSendLineNumber(line);
- impl()->setLastSendURL(stackTrace[1].sourceURL);
+ impl()->setLastSendURL(iter->sourceURL());
+ } else {
+ impl()->setLastSendLineNumber(0);
+ impl()->setLastSendURL(String());
}
setDOMException(exec, ec);
return jsUndefined();
diff --git a/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp b/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp
index 6226126..f29befe 100644
--- a/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp
+++ b/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp
@@ -40,7 +40,8 @@
#include "ScriptCallStack.h"
#include "ScriptValue.h"
#include <interpreter/CallFrame.h>
-#include <interpreter/Interpreter.h>
+#include <interpreter/CallFrameInlines.h>
+#include <interpreter/StackIterator.h>
#include <runtime/ArgList.h>
#include <runtime/JSCJSValue.h>
#include <runtime/JSFunction.h>
@@ -57,13 +58,12 @@
{
Vector<ScriptCallFrame> frames;
if (JSC::ExecState* exec = JSMainThreadExecState::currentState()) {
- Vector<StackFrame> stackTrace;
- Interpreter::getStackTrace(&exec->vm(), stackTrace, maxStackSize);
- for (size_t i = 0; i < stackTrace.size(); i++) {
+ CallFrame* frame = exec->vm().topCallFrame;
+ for (StackIterator iter = frame->begin(); iter != frame->end() && maxStackSize--; ++iter) {
unsigned line;
unsigned column;
- stackTrace[i].computeLineAndColumn(line, column);
- frames.append(ScriptCallFrame(stackTrace[i].friendlyFunctionName(exec), stackTrace[i].friendlySourceURL(), line, column));
+ iter->computeLineAndColumn(line, column);
+ frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
}
}
if (frames.isEmpty() && !emptyIsAllowed) {
@@ -78,22 +78,20 @@
PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize)
{
Vector<ScriptCallFrame> frames;
- Vector<StackFrame> stackTrace;
- Interpreter::getStackTrace(&exec->vm(), stackTrace, maxStackSize + 1);
- for (size_t i = stackTrace.size() == 1 ? 0 : 1; i < stackTrace.size(); i++) {
+ ASSERT(exec);
+ CallFrame* frame = exec->vm().topCallFrame;
+ StackIterator iter = frame->begin();
+ for (++iter; iter != frame->end() && maxStackSize--; ++iter) {
// This early exit is necessary to maintain our old behaviour
// but the stack trace we produce now is complete and handles all
// ways in which code may be running
- if (!stackTrace[i].callee && frames.size())
+ if (!iter->callee() && frames.size())
break;
-
- String functionName = stackTrace[i].friendlyFunctionName(exec);
unsigned line;
unsigned column;
- stackTrace[i].computeLineAndColumn(line, column);
- frames.append(ScriptCallFrame(functionName, stackTrace[i].sourceURL, line, column));
+ iter->computeLineAndColumn(line, column);
+ frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
}
-
return ScriptCallStack::create(frames);
}