Commit 12cdb31b authored by clemensh's avatar clemensh Committed by Commit bot

[inspector] Introduce debug::WasmScript

*and* report all "virtual" wasm scripts right when the wasm script is
registered at the inspector.

WasmScript is a subtype of Script, with the cast checking that it is
actually a wasm script.
This layout makes it quite easy to implement functionality that is only
available for wasm scripts, and allows to later directly use the
WasmCompiledModule instead of the i::Script for backing the
debug::WasmScript. We might also add virtual methods to
provide different implementations for GetSourcePosition, Source and
others.

DisassembleWasmFunction now also becomes a method of this class instead
of a static function on the DebugInterface.

The WasmTranslation now uses the new WasmScript type instead of the
Script wrapper, and also registers all virtual wasm scripts immediately
when the wasm script is made public to the inspector (when the wasm
module is created).

R=yangguo@chromium.org,dgozman@chromium.org,titzer@chromium.org
BUG=chromium:613110,chromium:659715

Review-Url: https://codereview.chromium.org/2531163010
Cr-Commit-Position: refs/heads/master@{#41519}
parent a610155c
......@@ -9095,6 +9095,40 @@ MaybeLocal<debug::Script> debug::Script::Wrap(v8::Isolate* v8_isolate,
return ToApiHandle<debug::Script>(handle_scope.CloseAndEscape(script_obj));
}
debug::WasmScript* debug::WasmScript::Cast(debug::Script* script) {
CHECK(script->IsWasm());
return static_cast<WasmScript*>(script);
}
int debug::WasmScript::NumFunctions() const {
i::DisallowHeapAllocation no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
i::WasmCompiledModule* compiled_module =
i::WasmCompiledModule::cast(script->wasm_compiled_module());
DCHECK_GE(i::kMaxInt, compiled_module->module()->functions.size());
return static_cast<int>(compiled_module->module()->functions.size());
}
int debug::WasmScript::NumImportedFunctions() const {
i::DisallowHeapAllocation no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
i::WasmCompiledModule* compiled_module =
i::WasmCompiledModule::cast(script->wasm_compiled_module());
DCHECK_GE(i::kMaxInt, compiled_module->module()->num_imported_functions);
return static_cast<int>(compiled_module->module()->num_imported_functions);
}
debug::WasmDisassembly debug::WasmScript::DisassembleFunction(
int function_index) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
i::WasmCompiledModule* compiled_module =
i::WasmCompiledModule::cast(script->wasm_compiled_module());
return compiled_module->DisassembleFunction(function_index);
}
debug::Location::Location(int line_number, int column_number)
: line_number_(line_number), column_number_(column_number) {
CHECK(line_number >= 0);
......@@ -9139,23 +9173,6 @@ void debug::GetLoadedScripts(v8::Isolate* v8_isolate,
}
}
debug::WasmDisassembly debug::DisassembleWasmFunction(Isolate* v8_isolate,
Local<Object> v8_script,
int function_index) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
if (v8_script.IsEmpty()) return {};
i::Handle<i::Object> script_wrapper = Utils::OpenHandle(*v8_script);
if (!script_wrapper->IsJSValue()) return {};
i::Handle<i::Object> script_obj(
i::Handle<i::JSValue>::cast(script_wrapper)->value(), isolate);
if (!script_obj->IsScript()) return {};
i::Handle<i::Script> script = i::Handle<i::Script>::cast(script_obj);
if (script->type() != i::Script::TYPE_WASM) return {};
i::Handle<i::WasmCompiledModule> compiled_module(
i::WasmCompiledModule::cast(script->wasm_compiled_module()), isolate);
return compiled_module->DisassembleFunction(function_index);
}
MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate,
Local<String> source) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
......
......@@ -176,14 +176,18 @@ class Script {
int GetSourcePosition(const debug::Location& location) const;
};
void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts);
// Specialization for wasm Scripts.
class WasmScript : public Script {
public:
static WasmScript* Cast(Script* script);
/**
* Compute the disassembly of a wasm function.
*/
debug::WasmDisassembly DisassembleWasmFunction(Isolate* isolate,
v8::Local<v8::Object> script,
int function_index);
int NumFunctions() const;
int NumImportedFunctions() const;
debug::WasmDisassembly DisassembleFunction(int function_index) const;
};
void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts);
MaybeLocal<UnboundScript> CompileInspectorScript(Isolate* isolate,
Local<String> source);
......
......@@ -63,8 +63,7 @@ static const char kDebuggerNotPaused[] =
namespace {
void TranslateWasmStackTraceLocations(Array<CallFrame>* stackTrace,
WasmTranslation* wasmTranslation,
int context_group_id) {
WasmTranslation* wasmTranslation) {
for (size_t i = 0, e = stackTrace->length(); i != e; ++i) {
protocol::Debugger::Location* location = stackTrace->get(i)->getLocation();
String16 scriptId = location->getScriptId();
......@@ -72,7 +71,7 @@ void TranslateWasmStackTraceLocations(Array<CallFrame>* stackTrace,
int columnNumber = location->getColumnNumber(-1);
if (!wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
&scriptId, &lineNumber, &columnNumber, context_group_id)) {
&scriptId, &lineNumber, &columnNumber)) {
continue;
}
......@@ -515,6 +514,7 @@ std::unique_ptr<protocol::Debugger::Location>
V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId,
const ScriptBreakpoint& breakpoint,
BreakpointSource source) {
v8::HandleScope handles(m_isolate);
DCHECK(enabled());
// FIXME: remove these checks once crbug.com/520702 is resolved.
CHECK(!breakpointId.isEmpty());
......@@ -526,12 +526,9 @@ V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId,
return nullptr;
ScriptBreakpoint translatedBreakpoint = breakpoint;
if (m_scripts.count(breakpoint.script_id) == 0) {
m_debugger->wasmTranslation()
->TranslateProtocolLocationToWasmScriptLocation(
&translatedBreakpoint.script_id, &translatedBreakpoint.line_number,
&translatedBreakpoint.column_number);
}
m_debugger->wasmTranslation()->TranslateProtocolLocationToWasmScriptLocation(
&translatedBreakpoint.script_id, &translatedBreakpoint.line_number,
&translatedBreakpoint.column_number);
int actualLineNumber;
int actualColumnNumber;
......@@ -1033,8 +1030,8 @@ Response V8DebuggerAgentImpl::currentCallFrames(
protocol::ErrorSupport errorSupport;
*result = Array<CallFrame>::fromValue(protocolValue.get(), &errorSupport);
if (!*result) return Response::Error(errorSupport.errors());
TranslateWasmStackTraceLocations(result->get(), m_debugger->wasmTranslation(),
m_session->contextGroupId());
TranslateWasmStackTraceLocations(result->get(),
m_debugger->wasmTranslation());
return Response::OK();
}
......
......@@ -57,7 +57,7 @@ V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector)
m_ignoreScriptParsedEventsCounter(0),
m_maxAsyncCallStackDepth(0),
m_pauseOnExceptionsState(v8::debug::NoBreakOnException),
m_wasmTranslation(isolate, this) {}
m_wasmTranslation(isolate) {}
V8Debugger::~V8Debugger() {}
......@@ -587,7 +587,7 @@ void V8Debugger::handleV8DebugEvent(
return;
}
if (script->IsWasm()) {
m_wasmTranslation.AddScript(scriptWrapper.As<v8::Object>());
m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent);
} else if (m_ignoreScriptParsedEventsCounter == 0) {
agent->didParseSource(
std::unique_ptr<V8DebuggerScript>(
......
......@@ -42,7 +42,7 @@ V8StackTraceImpl::Frame toFrame(v8::Local<v8::StackFrame> frame,
// sending the stack trace over wire.
if (wasmTranslation)
wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
&scriptId, &sourceLineNumber, &sourceColumn, contextGroupId);
&scriptId, &sourceLineNumber, &sourceColumn);
return V8StackTraceImpl::Frame(functionName, scriptId, sourceName,
sourceLineNumber + 1, sourceColumn + 1);
}
......
This diff is collapsed.
......@@ -9,33 +9,30 @@
#include "include/v8.h"
#include "src/base/macros.h"
#include "src/debug/debug-interface.h"
#include "src/inspector/string-16.h"
namespace v8_inspector {
// Forward declarations.
class V8Debugger;
class V8DebuggerScript;
struct ScriptBreakpoint;
namespace protocol {
namespace Debugger {
class Location;
}
}
class V8DebuggerAgentImpl;
class WasmTranslation {
public:
enum Mode { Raw, Disassemble };
WasmTranslation(v8::Isolate* isolate, V8Debugger* debugger);
explicit WasmTranslation(v8::Isolate* isolate);
~WasmTranslation();
// Set translation mode.
void SetMode(Mode mode) { mode_ = mode; }
// Make a wasm script known to the translation. Only locations referencing a
// registered script will be translated by the Translate functions below.
void AddScript(v8::Local<v8::Object> script_wrapper);
// Make a wasm script known to the translation. This will trigger a number of
// didParseScript calls to the given debugger agent.
// Only locations referencing a registered script will be translated by the
// Translate functions below.
void AddScript(v8::Local<v8::debug::WasmScript> script,
V8DebuggerAgentImpl* agent);
// Clear all registered scripts.
void Clear();
......@@ -45,15 +42,10 @@ class WasmTranslation {
// Does nothing for locations referencing a script which was not registered
// before via AddScript.
// Line and column are 0-based.
// The context group id specifies the context of the script.
// If the script was registered and the respective wasm function was not seen
// before, a new artificial script representing this function will be created
// and made public to the frontend.
// Returns true if the location was translated, false otherwise.
bool TranslateWasmScriptLocationToProtocolLocation(String16* script_id,
int* line_number,
int* column_number,
int context_group_id);
int* column_number);
// Translate back from protocol locations (potentially referencing artificial
// scripts for individual wasm functions) to locations that make sense to V8.
......@@ -68,11 +60,9 @@ class WasmTranslation {
class TranslatorImpl;
friend class TranslatorImpl;
void AddFakeScript(std::unique_ptr<V8DebuggerScript> fake_script,
TranslatorImpl* translator, int context_group_id);
void AddFakeScript(const String16& scriptId, TranslatorImpl* translator);
v8::Isolate* isolate_;
V8Debugger* debugger_;
std::unordered_map<int, std::unique_ptr<TranslatorImpl>> wasm_translators_;
std::unordered_map<String16, TranslatorImpl*> fake_scripts_;
Mode mode_;
......
Check that inspector gets two wasm scripts at module creation time.
Script #0 parsed. URL: v8://test/testFunction
Script #1 parsed. URL: v8://test/runTestRunction
Script #2 parsed. URL: wasm://wasm/wasm-911a065e/wasm-911a065e-0
Script #3 parsed. URL: wasm://wasm/wasm-911a065e/wasm-911a065e-1
Source for wasm://wasm/wasm-911a065e/wasm-911a065e-0:
func $nopFunction
nop
Source for wasm://wasm/wasm-911a065e/wasm-911a065e-1:
func $main
block
i32.const 2
drop
end
// 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.
// Flags: --expose-wasm
load('test/mjsunit/wasm/wasm-constants.js');
load('test/mjsunit/wasm/wasm-module-builder.js');
// Add two empty functions. Both should be registered as individual scripts at
// module creation time.
var builder = new WasmModuleBuilder();
builder.addFunction('nopFunction', kSig_v_v).addBody([kExprNop]);
builder.addFunction('main', kSig_v_v)
.addBody([kExprBlock, kAstStmt, kExprI32Const, 2, kExprDrop, kExprEnd])
.exportAs('main');
var module_bytes = builder.toArray();
function testFunction(bytes) {
var buffer = new ArrayBuffer(bytes.length);
var view = new Uint8Array(buffer);
for (var i = 0; i < bytes.length; i++) {
view[i] = bytes[i] | 0;
}
// Compilation triggers registration of wasm scripts.
new WebAssembly.Module(buffer);
}
InspectorTest.addScriptWithUrl(
testFunction.toString(), 'v8://test/testFunction');
InspectorTest.addScript('var module_bytes = ' + JSON.stringify(module_bytes));
Protocol.Debugger.enable();
Protocol.Debugger.onScriptParsed(handleScriptParsed);
InspectorTest.log(
'Check that inspector gets two wasm scripts at module creation time.');
Protocol.Runtime
.evaluate({
'expression': '//# sourceURL=v8://test/runTestRunction\n' +
'testFunction(module_bytes)'
})
.then(checkFinished);
var num_scripts = 0;
var missing_sources = 0;
function checkFinished() {
if (missing_sources == 0)
InspectorTest.completeTest();
}
function handleScriptParsed(messageObject)
{
var url = messageObject.params.url;
InspectorTest.log("Script #" + num_scripts + " parsed. URL: " + url);
++num_scripts;
if (url.startsWith("wasm://")) {
++missing_sources;
function dumpScriptSource(message) {
InspectorTest.log("Source for " + url + ":");
InspectorTest.log(message.result.scriptSource);
--missing_sources;
}
Protocol.Debugger.getScriptSource({scriptId: messageObject.params.scriptId})
.then(dumpScriptSource.bind(null))
.then(checkFinished);
}
}
......@@ -114,6 +114,7 @@ InspectorTest.completeTestAfterPendingTimeouts = function()
}
InspectorTest.addScript = (string) => compileAndRunWithOrigin(string, "", 0, 0);
InspectorTest.addScriptWithUrl = (string, url) => compileAndRunWithOrigin(string, url, 0, 0);
InspectorTest.startDumpingProtocolMessages = function()
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment