summaryrefslogtreecommitdiff
path: root/deps/v8/src/inspector/v8-stack-trace-impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/inspector/v8-stack-trace-impl.cc')
-rw-r--r--deps/v8/src/inspector/v8-stack-trace-impl.cc281
1 files changed, 281 insertions, 0 deletions
diff --git a/deps/v8/src/inspector/v8-stack-trace-impl.cc b/deps/v8/src/inspector/v8-stack-trace-impl.cc
new file mode 100644
index 0000000000..1a38c6dd82
--- /dev/null
+++ b/deps/v8/src/inspector/v8-stack-trace-impl.cc
@@ -0,0 +1,281 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/inspector/v8-stack-trace-impl.h"
+
+#include "src/inspector/string-util.h"
+#include "src/inspector/v8-debugger.h"
+#include "src/inspector/v8-inspector-impl.h"
+#include "src/inspector/v8-profiler-agent-impl.h"
+
+#include "include/v8-debug.h"
+#include "include/v8-profiler.h"
+#include "include/v8-version.h"
+
+namespace v8_inspector {
+
+namespace {
+
+static const v8::StackTrace::StackTraceOptions stackTraceOptions =
+ static_cast<v8::StackTrace::StackTraceOptions>(
+ v8::StackTrace::kLineNumber | v8::StackTrace::kColumnOffset |
+ v8::StackTrace::kScriptId | v8::StackTrace::kScriptNameOrSourceURL |
+ v8::StackTrace::kFunctionName);
+
+V8StackTraceImpl::Frame toFrame(v8::Local<v8::StackFrame> frame) {
+ String16 scriptId = String16::fromInteger(frame->GetScriptId());
+ String16 sourceName;
+ v8::Local<v8::String> sourceNameValue(frame->GetScriptNameOrSourceURL());
+ if (!sourceNameValue.IsEmpty())
+ sourceName = toProtocolString(sourceNameValue);
+
+ String16 functionName;
+ v8::Local<v8::String> functionNameValue(frame->GetFunctionName());
+ if (!functionNameValue.IsEmpty())
+ functionName = toProtocolString(functionNameValue);
+
+ int sourceLineNumber = frame->GetLineNumber();
+ int sourceColumn = frame->GetColumn();
+ return V8StackTraceImpl::Frame(functionName, scriptId, sourceName,
+ sourceLineNumber, sourceColumn);
+}
+
+void toFramesVector(v8::Local<v8::StackTrace> stackTrace,
+ std::vector<V8StackTraceImpl::Frame>& frames,
+ size_t maxStackSize, v8::Isolate* isolate) {
+ DCHECK(isolate->InContext());
+ int frameCount = stackTrace->GetFrameCount();
+ if (frameCount > static_cast<int>(maxStackSize))
+ frameCount = static_cast<int>(maxStackSize);
+ for (int i = 0; i < frameCount; i++) {
+ v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(i);
+ frames.push_back(toFrame(stackFrame));
+ }
+}
+
+} // namespace
+
+V8StackTraceImpl::Frame::Frame()
+ : m_functionName("undefined"),
+ m_scriptId(""),
+ m_scriptName("undefined"),
+ m_lineNumber(0),
+ m_columnNumber(0) {}
+
+V8StackTraceImpl::Frame::Frame(const String16& functionName,
+ const String16& scriptId,
+ const String16& scriptName, int lineNumber,
+ int column)
+ : m_functionName(functionName),
+ m_scriptId(scriptId),
+ m_scriptName(scriptName),
+ m_lineNumber(lineNumber),
+ m_columnNumber(column) {
+ DCHECK(m_lineNumber != v8::Message::kNoLineNumberInfo);
+ DCHECK(m_columnNumber != v8::Message::kNoColumnInfo);
+}
+
+V8StackTraceImpl::Frame::~Frame() {}
+
+// buildInspectorObject() and SourceLocation's toTracedValue() should set the
+// same fields.
+// If either of them is modified, the other should be also modified.
+std::unique_ptr<protocol::Runtime::CallFrame>
+V8StackTraceImpl::Frame::buildInspectorObject() const {
+ return protocol::Runtime::CallFrame::create()
+ .setFunctionName(m_functionName)
+ .setScriptId(m_scriptId)
+ .setUrl(m_scriptName)
+ .setLineNumber(m_lineNumber - 1)
+ .setColumnNumber(m_columnNumber - 1)
+ .build();
+}
+
+V8StackTraceImpl::Frame V8StackTraceImpl::Frame::clone() const {
+ return Frame(m_functionName, m_scriptId, m_scriptName, m_lineNumber,
+ m_columnNumber);
+}
+
+// static
+void V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(
+ v8::Isolate* isolate, bool capture) {
+ isolate->SetCaptureStackTraceForUncaughtExceptions(
+ capture, V8StackTraceImpl::maxCallStackSizeToCapture, stackTraceOptions);
+}
+
+// static
+std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create(
+ V8Debugger* debugger, int contextGroupId,
+ v8::Local<v8::StackTrace> stackTrace, size_t maxStackSize,
+ const String16& description) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ std::vector<V8StackTraceImpl::Frame> frames;
+ if (!stackTrace.IsEmpty())
+ toFramesVector(stackTrace, frames, maxStackSize, isolate);
+
+ int maxAsyncCallChainDepth = 1;
+ V8StackTraceImpl* asyncCallChain = nullptr;
+ if (debugger && maxStackSize > 1) {
+ asyncCallChain = debugger->currentAsyncCallChain();
+ maxAsyncCallChainDepth = debugger->maxAsyncCallChainDepth();
+ }
+ // Do not accidentally append async call chain from another group. This should
+ // not
+ // happen if we have proper instrumentation, but let's double-check to be
+ // safe.
+ if (contextGroupId && asyncCallChain && asyncCallChain->m_contextGroupId &&
+ asyncCallChain->m_contextGroupId != contextGroupId) {
+ asyncCallChain = nullptr;
+ maxAsyncCallChainDepth = 1;
+ }
+
+ // Only the top stack in the chain may be empty, so ensure that second stack
+ // is non-empty (it's the top of appended chain).
+ if (asyncCallChain && asyncCallChain->isEmpty())
+ asyncCallChain = asyncCallChain->m_parent.get();
+
+ if (stackTrace.IsEmpty() && !asyncCallChain) return nullptr;
+
+ std::unique_ptr<V8StackTraceImpl> result(new V8StackTraceImpl(
+ contextGroupId, description, frames,
+ asyncCallChain ? asyncCallChain->cloneImpl() : nullptr));
+
+ // Crop to not exceed maxAsyncCallChainDepth.
+ V8StackTraceImpl* deepest = result.get();
+ while (deepest && maxAsyncCallChainDepth) {
+ deepest = deepest->m_parent.get();
+ maxAsyncCallChainDepth--;
+ }
+ if (deepest) deepest->m_parent.reset();
+
+ return result;
+}
+
+// static
+std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture(
+ V8Debugger* debugger, int contextGroupId, size_t maxStackSize,
+ const String16& description) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handleScope(isolate);
+ v8::Local<v8::StackTrace> stackTrace;
+ if (isolate->InContext()) {
+ if (debugger) {
+ V8InspectorImpl* inspector = debugger->inspector();
+ V8ProfilerAgentImpl* profilerAgent =
+ inspector->enabledProfilerAgentForGroup(contextGroupId);
+ if (profilerAgent) profilerAgent->collectSample();
+ }
+ stackTrace = v8::StackTrace::CurrentStackTrace(
+ isolate, static_cast<int>(maxStackSize), stackTraceOptions);
+ }
+ return V8StackTraceImpl::create(debugger, contextGroupId, stackTrace,
+ maxStackSize, description);
+}
+
+std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::cloneImpl() {
+ std::vector<Frame> framesCopy(m_frames);
+ return wrapUnique(
+ new V8StackTraceImpl(m_contextGroupId, m_description, framesCopy,
+ m_parent ? m_parent->cloneImpl() : nullptr));
+}
+
+std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() {
+ std::vector<Frame> frames;
+ for (size_t i = 0; i < m_frames.size(); i++)
+ frames.push_back(m_frames.at(i).clone());
+ return wrapUnique(
+ new V8StackTraceImpl(m_contextGroupId, m_description, frames, nullptr));
+}
+
+V8StackTraceImpl::V8StackTraceImpl(int contextGroupId,
+ const String16& description,
+ std::vector<Frame>& frames,
+ std::unique_ptr<V8StackTraceImpl> parent)
+ : m_contextGroupId(contextGroupId),
+ m_description(description),
+ m_parent(std::move(parent)) {
+ m_frames.swap(frames);
+}
+
+V8StackTraceImpl::~V8StackTraceImpl() {}
+
+StringView V8StackTraceImpl::topSourceURL() const {
+ DCHECK(m_frames.size());
+ return toStringView(m_frames[0].m_scriptName);
+}
+
+int V8StackTraceImpl::topLineNumber() const {
+ DCHECK(m_frames.size());
+ return m_frames[0].m_lineNumber;
+}
+
+int V8StackTraceImpl::topColumnNumber() const {
+ DCHECK(m_frames.size());
+ return m_frames[0].m_columnNumber;
+}
+
+StringView V8StackTraceImpl::topFunctionName() const {
+ DCHECK(m_frames.size());
+ return toStringView(m_frames[0].m_functionName);
+}
+
+StringView V8StackTraceImpl::topScriptId() const {
+ DCHECK(m_frames.size());
+ return toStringView(m_frames[0].m_scriptId);
+}
+
+std::unique_ptr<protocol::Runtime::StackTrace>
+V8StackTraceImpl::buildInspectorObjectImpl() const {
+ std::unique_ptr<protocol::Array<protocol::Runtime::CallFrame>> frames =
+ protocol::Array<protocol::Runtime::CallFrame>::create();
+ for (size_t i = 0; i < m_frames.size(); i++)
+ frames->addItem(m_frames.at(i).buildInspectorObject());
+
+ std::unique_ptr<protocol::Runtime::StackTrace> stackTrace =
+ protocol::Runtime::StackTrace::create()
+ .setCallFrames(std::move(frames))
+ .build();
+ if (!m_description.isEmpty()) stackTrace->setDescription(m_description);
+ if (m_parent) stackTrace->setParent(m_parent->buildInspectorObjectImpl());
+ return stackTrace;
+}
+
+std::unique_ptr<protocol::Runtime::StackTrace>
+V8StackTraceImpl::buildInspectorObjectForTail(V8Debugger* debugger) const {
+ v8::HandleScope handleScope(v8::Isolate::GetCurrent());
+ // Next call collapses possible empty stack and ensures
+ // maxAsyncCallChainDepth.
+ std::unique_ptr<V8StackTraceImpl> fullChain = V8StackTraceImpl::create(
+ debugger, m_contextGroupId, v8::Local<v8::StackTrace>(),
+ V8StackTraceImpl::maxCallStackSizeToCapture);
+ if (!fullChain || !fullChain->m_parent) return nullptr;
+ return fullChain->m_parent->buildInspectorObjectImpl();
+}
+
+std::unique_ptr<protocol::Runtime::API::StackTrace>
+V8StackTraceImpl::buildInspectorObject() const {
+ return buildInspectorObjectImpl();
+}
+
+std::unique_ptr<StringBuffer> V8StackTraceImpl::toString() const {
+ String16Builder stackTrace;
+ for (size_t i = 0; i < m_frames.size(); ++i) {
+ const Frame& frame = m_frames[i];
+ stackTrace.append("\n at " + (frame.functionName().length()
+ ? frame.functionName()
+ : "(anonymous function)"));
+ stackTrace.append(" (");
+ stackTrace.append(frame.sourceURL());
+ stackTrace.append(':');
+ stackTrace.append(String16::fromInteger(frame.lineNumber()));
+ stackTrace.append(':');
+ stackTrace.append(String16::fromInteger(frame.columnNumber()));
+ stackTrace.append(')');
+ }
+ String16 string = stackTrace.toString();
+ return StringBufferImpl::adopt(string);
+}
+
+} // namespace v8_inspector