blob: c83f2317ae592a9234961cc87fda2be852a26906 [file] [log] [blame]
// Copyright 2016 The Chromium 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 "bindings/core/v8/SourceLocation.h"
#include "bindings/core/v8/V8BindingMacros.h"
#include "bindings/core/v8/V8PerIsolateData.h"
#include "core/dom/Document.h"
#include "core/dom/ExecutionContext.h"
#include "core/dom/ScriptableDocumentParser.h"
#include "core/html/HTMLFrameOwnerElement.h"
#include "core/inspector/ThreadDebugger.h"
#include "core/inspector/V8InspectorString.h"
#include "platform/ScriptForbiddenScope.h"
#include "platform/TracedValue.h"
#include "wtf/PtrUtil.h"
#include <memory>
namespace blink {
namespace {
std::unique_ptr<v8_inspector::V8StackTrace> captureStackTrace(bool full) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
V8PerIsolateData* data = V8PerIsolateData::from(isolate);
if (!data->threadDebugger() || !isolate->InContext())
return nullptr;
ScriptForbiddenScope::AllowUserAgentScript allowScripting;
return data->threadDebugger()->v8Inspector()->captureStackTrace(full);
}
}
// static
std::unique_ptr<SourceLocation> SourceLocation::capture(const String& url,
unsigned lineNumber,
unsigned columnNumber) {
std::unique_ptr<v8_inspector::V8StackTrace> stackTrace =
captureStackTrace(false);
if (stackTrace && !stackTrace->isEmpty())
return SourceLocation::createFromNonEmptyV8StackTrace(std::move(stackTrace),
0);
return SourceLocation::create(url, lineNumber, columnNumber,
std::move(stackTrace));
}
// static
std::unique_ptr<SourceLocation> SourceLocation::capture(
ExecutionContext* executionContext) {
std::unique_ptr<v8_inspector::V8StackTrace> stackTrace =
captureStackTrace(false);
if (stackTrace && !stackTrace->isEmpty())
return SourceLocation::createFromNonEmptyV8StackTrace(std::move(stackTrace),
0);
Document* document = executionContext && executionContext->isDocument()
? toDocument(executionContext)
: nullptr;
if (document) {
unsigned lineNumber = 0;
if (document->scriptableDocumentParser() &&
!document->isInDocumentWrite()) {
if (document->scriptableDocumentParser()->isParsingAtLineNumber())
lineNumber =
document->scriptableDocumentParser()->lineNumber().oneBasedInt();
}
return SourceLocation::create(document->url().getString(), lineNumber, 0,
std::move(stackTrace));
}
return SourceLocation::create(
executionContext ? executionContext->url().getString() : String(), 0, 0,
std::move(stackTrace));
}
// static
std::unique_ptr<SourceLocation> SourceLocation::fromMessage(
v8::Isolate* isolate,
v8::Local<v8::Message> message,
ExecutionContext* executionContext) {
v8::Local<v8::StackTrace> stack = message->GetStackTrace();
std::unique_ptr<v8_inspector::V8StackTrace> stackTrace = nullptr;
V8PerIsolateData* data = V8PerIsolateData::from(isolate);
if (data && data->threadDebugger())
stackTrace = data->threadDebugger()->v8Inspector()->createStackTrace(stack);
int scriptId = message->GetScriptOrigin().ScriptID()->Value();
if (!stack.IsEmpty() && stack->GetFrameCount() > 0) {
int topScriptId = stack->GetFrame(0)->GetScriptId();
if (topScriptId == scriptId)
scriptId = 0;
}
int lineNumber = 0;
int columnNumber = 0;
if (v8Call(message->GetLineNumber(isolate->GetCurrentContext()),
lineNumber) &&
v8Call(message->GetStartColumn(isolate->GetCurrentContext()),
columnNumber))
++columnNumber;
if ((!scriptId || !lineNumber) && stackTrace && !stackTrace->isEmpty())
return SourceLocation::createFromNonEmptyV8StackTrace(std::move(stackTrace),
0);
String url = toCoreStringWithUndefinedOrNullCheck(
message->GetScriptOrigin().ResourceName());
if (url.isNull())
url = executionContext->url();
return SourceLocation::create(url, lineNumber, columnNumber,
std::move(stackTrace), scriptId);
}
// static
std::unique_ptr<SourceLocation> SourceLocation::create(
const String& url,
unsigned lineNumber,
unsigned columnNumber,
std::unique_ptr<v8_inspector::V8StackTrace> stackTrace,
int scriptId) {
return wrapUnique(new SourceLocation(url, lineNumber, columnNumber,
std::move(stackTrace), scriptId));
}
// static
std::unique_ptr<SourceLocation> SourceLocation::createFromNonEmptyV8StackTrace(
std::unique_ptr<v8_inspector::V8StackTrace> stackTrace,
int scriptId) {
// Retrieve the data before passing the ownership to SourceLocation.
String url = toCoreString(stackTrace->topSourceURL());
unsigned lineNumber = stackTrace->topLineNumber();
unsigned columnNumber = stackTrace->topColumnNumber();
return wrapUnique(new SourceLocation(url, lineNumber, columnNumber,
std::move(stackTrace), scriptId));
}
// static
std::unique_ptr<SourceLocation> SourceLocation::fromFunction(
v8::Local<v8::Function> function) {
if (!function.IsEmpty())
return SourceLocation::create(
toCoreStringWithUndefinedOrNullCheck(
function->GetScriptOrigin().ResourceName()),
function->GetScriptLineNumber() + 1,
function->GetScriptColumnNumber() + 1, nullptr, function->ScriptId());
return SourceLocation::create(String(), 0, 0, nullptr, 0);
}
// static
std::unique_ptr<SourceLocation> SourceLocation::captureWithFullStackTrace() {
std::unique_ptr<v8_inspector::V8StackTrace> stackTrace =
captureStackTrace(true);
if (stackTrace && !stackTrace->isEmpty())
return SourceLocation::createFromNonEmptyV8StackTrace(std::move(stackTrace),
0);
return SourceLocation::create(String(), 0, 0, nullptr, 0);
}
SourceLocation::SourceLocation(
const String& url,
unsigned lineNumber,
unsigned columnNumber,
std::unique_ptr<v8_inspector::V8StackTrace> stackTrace,
int scriptId)
: m_url(url),
m_lineNumber(lineNumber),
m_columnNumber(columnNumber),
m_stackTrace(std::move(stackTrace)),
m_scriptId(scriptId) {}
SourceLocation::~SourceLocation() {}
void SourceLocation::toTracedValue(TracedValue* value, const char* name) const {
if (!m_stackTrace || m_stackTrace->isEmpty())
return;
value->beginArray(name);
value->beginDictionary();
value->setString("functionName",
toCoreString(m_stackTrace->topFunctionName()));
value->setString("scriptId", toCoreString(m_stackTrace->topScriptId()));
value->setString("url", toCoreString(m_stackTrace->topSourceURL()));
value->setInteger("lineNumber", m_stackTrace->topLineNumber());
value->setInteger("columnNumber", m_stackTrace->topColumnNumber());
value->endDictionary();
value->endArray();
}
std::unique_ptr<SourceLocation> SourceLocation::clone() const {
return wrapUnique(new SourceLocation(
m_url.isolatedCopy(), m_lineNumber, m_columnNumber,
m_stackTrace ? m_stackTrace->clone() : nullptr, m_scriptId));
}
std::unique_ptr<v8_inspector::protocol::Runtime::API::StackTrace>
SourceLocation::buildInspectorObject() const {
return m_stackTrace ? m_stackTrace->buildInspectorObject() : nullptr;
}
String SourceLocation::toString() const {
if (!m_stackTrace)
return String();
return toCoreString(m_stackTrace->toString());
}
} // namespace blink