Commit a4e162f7 authored by Eric Leese's avatar Eric Leese Committed by Commit Bot

Remove fake wasm scripts from V8 backend

Inspector will no longer report per-function wasm scripts or
provide wasm disassembly. Locations in wasm are now consistently
reported through the inspector API as lineNumber=0
columnNumber=byte offset in module.

Bug: chromium:1013527, chromium:1003022
Change-Id: Ide85bbaa85ad75f29248ff82a3e7f3e40688d377
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1991481
Commit-Queue: Eric Leese <leese@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarSimon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65660}
parent 36cb5f4b
......@@ -159,8 +159,6 @@ v8_source_set("inspector") {
"v8-value-utils.h",
"value-mirror.cc",
"value-mirror.h",
"wasm-translation.cc",
"wasm-translation.h",
]
}
......
......@@ -64,19 +64,6 @@ static const intptr_t kBreakpointHintMaxSearchOffset = 80 * 10;
namespace {
void TranslateLocation(protocol::Debugger::Location* location,
WasmTranslation* wasmTranslation) {
String16 scriptId = location->getScriptId();
int lineNumber = location->getLineNumber();
int columnNumber = location->getColumnNumber(-1);
if (wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
&scriptId, &lineNumber, &columnNumber)) {
location->setScriptId(std::move(scriptId));
location->setLineNumber(lineNumber);
location->setColumnNumber(columnNumber);
}
}
enum class BreakpointType {
kByUrl = 1,
kByUrlRegex,
......@@ -1348,7 +1335,6 @@ Response V8DebuggerAgentImpl::currentCallFrames(
.setLineNumber(loc.GetLineNumber())
.setColumnNumber(loc.GetColumnNumber())
.build();
TranslateLocation(location.get(), m_debugger->wasmTranslation());
String16 scriptId = String16::fromInteger(script->Id());
ScriptsMap::iterator scriptIterator =
m_scripts.find(location->getScriptId());
......
......@@ -9,7 +9,6 @@
#include "src/inspector/string-util.h"
#include "src/inspector/v8-debugger-agent-impl.h"
#include "src/inspector/v8-inspector-impl.h"
#include "src/inspector/wasm-translation.h"
namespace v8_inspector {
......@@ -86,32 +85,6 @@ String16 calculateHash(v8::Isolate* isolate, v8::Local<v8::String> source) {
return hash.toString();
}
void TranslateProtocolLocationToV8Location(WasmTranslation* wasmTranslation,
v8::debug::Location* loc,
const String16& scriptId,
const String16& expectedV8ScriptId) {
if (loc->IsEmpty()) return;
int lineNumber = loc->GetLineNumber();
int columnNumber = loc->GetColumnNumber();
String16 translatedScriptId = scriptId;
wasmTranslation->TranslateProtocolLocationToWasmScriptLocation(
&translatedScriptId, &lineNumber, &columnNumber);
DCHECK_EQ(expectedV8ScriptId.utf8(), translatedScriptId.utf8());
*loc = v8::debug::Location(lineNumber, columnNumber);
}
void TranslateV8LocationToProtocolLocation(
WasmTranslation* wasmTranslation, v8::debug::Location* loc,
const String16& scriptId, const String16& expectedProtocolScriptId) {
int lineNumber = loc->GetLineNumber();
int columnNumber = loc->GetColumnNumber();
String16 translatedScriptId = scriptId;
wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
&translatedScriptId, &lineNumber, &columnNumber);
DCHECK_EQ(expectedProtocolScriptId.utf8(), translatedScriptId.utf8());
*loc = v8::debug::Location(lineNumber, columnNumber);
}
class ActualScript : public V8DebuggerScript {
friend class V8DebuggerScript;
......@@ -334,137 +307,6 @@ class ActualScript : public V8DebuggerScript {
v8::Global<v8::debug::Script> m_script;
};
class WasmVirtualScript : public V8DebuggerScript {
friend class V8DebuggerScript;
public:
WasmVirtualScript(v8::Isolate* isolate, WasmTranslation* wasmTranslation,
v8::Local<v8::debug::WasmScript> script, String16 id,
String16 url, int functionIndex)
: V8DebuggerScript(isolate, std::move(id), std::move(url)),
m_script(isolate, script),
m_wasmTranslation(wasmTranslation),
m_functionIndex(functionIndex) {
m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
m_executionContextId = script->ContextId().ToChecked();
}
const String16& sourceMappingURL() const override { return emptyString(); }
bool isLiveEdit() const override { return false; }
bool isModule() const override { return false; }
void setSourceMappingURL(const String16&) override {}
void setSource(const String16&, bool, v8::debug::LiveEditResult*) override {
UNREACHABLE();
}
bool isSourceLoadedLazily() const override { return true; }
String16 source(size_t pos, size_t len) const override {
return m_wasmTranslation->GetSource(m_id, m_functionIndex)
.substring(pos, len);
}
v8::Maybe<v8::MemorySpan<const uint8_t>> wasmBytecode() const override {
return v8::Nothing<v8::MemorySpan<const uint8_t>>();
}
int startLine() const override {
return m_wasmTranslation->GetStartLine(m_id, m_functionIndex);
}
int startColumn() const override {
return m_wasmTranslation->GetStartColumn(m_id, m_functionIndex);
}
int endLine() const override {
return m_wasmTranslation->GetEndLine(m_id, m_functionIndex);
}
int endColumn() const override {
return m_wasmTranslation->GetEndColumn(m_id, m_functionIndex);
}
int length() const override {
return static_cast<int>(source(0, UINT_MAX).length());
}
bool getPossibleBreakpoints(
const v8::debug::Location& start, const v8::debug::Location& end,
bool restrictToFunction,
std::vector<v8::debug::BreakLocation>* locations) override {
v8::HandleScope scope(m_isolate);
v8::Local<v8::debug::Script> script = m_script.Get(m_isolate);
String16 v8ScriptId = String16::fromInteger(script->Id());
v8::debug::Location translatedStart = start;
TranslateProtocolLocationToV8Location(m_wasmTranslation, &translatedStart,
scriptId(), v8ScriptId);
v8::debug::Location translatedEnd = end;
if (translatedEnd.IsEmpty()) {
// Stop at the end of the function.
int end_offset = m_wasmTranslation->GetEndOffset(scriptId());
translatedEnd = v8::debug::Location(0, end_offset);
} else {
TranslateProtocolLocationToV8Location(m_wasmTranslation, &translatedEnd,
scriptId(), v8ScriptId);
}
bool success = script->GetPossibleBreakpoints(
translatedStart, translatedEnd, restrictToFunction, locations);
for (v8::debug::BreakLocation& loc : *locations) {
TranslateV8LocationToProtocolLocation(m_wasmTranslation, &loc, v8ScriptId,
scriptId());
}
return success;
}
void resetBlackboxedStateCache() override {}
int offset(int lineNumber, int columnNumber) const override {
return kNoOffset;
}
v8::debug::Location location(int offset) const override {
return v8::debug::Location();
}
bool setBreakpoint(const String16& condition, v8::debug::Location* location,
int* id) const override {
v8::HandleScope scope(m_isolate);
v8::Local<v8::debug::Script> script = m_script.Get(m_isolate);
String16 v8ScriptId = String16::fromInteger(script->Id());
TranslateProtocolLocationToV8Location(m_wasmTranslation, location,
scriptId(), v8ScriptId);
if (location->IsEmpty()) return false;
if (!script->SetBreakpoint(toV8String(m_isolate, condition), location, id))
return false;
TranslateV8LocationToProtocolLocation(m_wasmTranslation, location,
v8ScriptId, scriptId());
return true;
}
bool setBreakpointOnRun(int*) const override { return false; }
const String16& hash() const override {
if (m_hash.isEmpty()) {
m_hash = m_wasmTranslation->GetHash(m_id, m_functionIndex);
}
return m_hash;
}
void MakeWeak() override {}
private:
static const String16& emptyString() {
// On the heap and leaked so that no destructor needs to run at exit time.
static const String16* singleEmptyString = new String16;
return *singleEmptyString;
}
v8::Local<v8::debug::Script> script() const override {
return m_script.Get(m_isolate);
}
v8::Global<v8::debug::WasmScript> m_script;
WasmTranslation* m_wasmTranslation;
int m_functionIndex;
mutable String16 m_hash;
};
} // namespace
std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create(
......@@ -474,15 +316,6 @@ std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create(
client);
}
std::unique_ptr<V8DebuggerScript> V8DebuggerScript::CreateWasm(
v8::Isolate* isolate, WasmTranslation* wasmTranslation,
v8::Local<v8::debug::WasmScript> underlyingScript, String16 id,
String16 url, int functionIndex) {
return std::make_unique<WasmVirtualScript>(isolate, wasmTranslation,
underlyingScript, std::move(id),
std::move(url), functionIndex);
}
V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, String16 id,
String16 url)
: m_id(std::move(id)), m_url(std::move(url)), m_isolate(isolate) {}
......
......@@ -43,17 +43,12 @@ namespace v8_inspector {
class V8DebuggerAgentImpl;
class V8InspectorClient;
class WasmTranslation;
class V8DebuggerScript {
public:
static std::unique_ptr<V8DebuggerScript> Create(
v8::Isolate* isolate, v8::Local<v8::debug::Script> script,
bool isLiveEdit, V8DebuggerAgentImpl* agent, V8InspectorClient* client);
static std::unique_ptr<V8DebuggerScript> CreateWasm(
v8::Isolate* isolate, WasmTranslation* wasmTranslation,
v8::Local<v8::debug::WasmScript> underlyingScript, String16 id,
String16 url, int functionIndex);
virtual ~V8DebuggerScript();
......
......@@ -108,8 +108,7 @@ V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector)
m_continueToLocationBreakpointId(kNoBreakpointId),
m_maxAsyncCallStacks(kMaxAsyncTaskStacks),
m_maxAsyncCallStackDepth(0),
m_pauseOnExceptionsState(v8::debug::NoBreakOnException),
m_wasmTranslation(isolate) {}
m_pauseOnExceptionsState(v8::debug::NoBreakOnException) {}
V8Debugger::~V8Debugger() {
m_isolate->RemoveCallCompletedCallback(
......@@ -147,7 +146,6 @@ void V8Debugger::disable() {
m_taskWithScheduledBreakPauseRequested = false;
m_pauseOnNextCallRequested = false;
m_pauseOnAsyncCall = false;
m_wasmTranslation.Clear();
v8::debug::SetDebugDelegate(m_isolate, nullptr);
m_isolate->RemoveNearHeapLimitCallback(&V8Debugger::nearHeapLimitCallback,
m_originalHeapLimit);
......@@ -514,24 +512,17 @@ void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script,
v8::Isolate* isolate = m_isolate;
V8InspectorClient* client = m_inspector->client();
WasmTranslation& wasmTranslation = m_wasmTranslation;
m_inspector->forEachSession(
m_inspector->contextGroupId(contextId),
[isolate, &script, has_compile_error, is_live_edited, client,
&wasmTranslation](V8InspectorSessionImpl* session) {
[isolate, &script, has_compile_error, is_live_edited,
client](V8InspectorSessionImpl* session) {
auto agent = session->debuggerAgent();
if (!agent->enabled()) return;
agent->didParseSource(
V8DebuggerScript::Create(isolate, script, is_live_edited, agent,
client),
!has_compile_error);
if (script->IsWasm() && script->SourceMappingURL().IsEmpty()) {
// In this case we also create fake scripts corresponding to each
// function.
// TODO(leese): Get rid of this once frontend no longer uses these.
wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent);
}
});
}
......@@ -1084,9 +1075,6 @@ std::shared_ptr<StackFrame> V8Debugger::symbolize(
return std::shared_ptr<StackFrame>(it->second);
}
std::shared_ptr<StackFrame> frame(new StackFrame(isolate(), v8Frame));
// TODO(clemensb): Figure out a way to do this translation only right before
// sending the stack trace over wire.
if (v8Frame->IsWasm()) frame->translate(&m_wasmTranslation);
if (m_maxAsyncCallStackDepth) {
m_framesCache[frameId] = frame;
}
......
......@@ -17,7 +17,6 @@
#include "src/inspector/protocol/Forward.h"
#include "src/inspector/protocol/Runtime.h"
#include "src/inspector/v8-debugger-script.h"
#include "src/inspector/wasm-translation.h"
#include "include/v8-inspector.h"
......@@ -140,8 +139,6 @@ class V8Debugger : public v8::debug::DebugDelegate,
V8InspectorImpl* inspector() { return m_inspector; }
WasmTranslation* wasmTranslation() { return &m_wasmTranslation; }
void setMaxAsyncTaskStacksForTest(int limit);
void dumpAsyncTaskStacksStateForTest();
......@@ -274,8 +271,6 @@ class V8Debugger : public v8::debug::DebugDelegate,
std::unique_ptr<TerminateExecutionCallback> m_terminateExecutionCallback;
WasmTranslation m_wasmTranslation;
DISALLOW_COPY_AND_ASSIGN(V8Debugger);
};
......
......@@ -246,7 +246,6 @@ void V8InspectorImpl::resetContextGroup(int contextGroupId) {
[&contextIdsToClear](InspectedContext* context) {
contextIdsToClear.push_back(context->contextId());
});
m_debugger->wasmTranslation()->Clear(m_isolate, contextIdsToClear);
forEachSession(contextGroupId,
[](V8InspectorSessionImpl* session) { session->reset(); });
m_contexts.erase(contextGroupId);
......
......@@ -8,7 +8,6 @@
#include "src/inspector/v8-debugger.h"
#include "src/inspector/v8-inspector-impl.h"
#include "src/inspector/wasm-translation.h"
namespace v8_inspector {
......@@ -167,11 +166,6 @@ StackFrame::StackFrame(v8::Isolate* isolate, v8::Local<v8::StackFrame> v8Frame)
DCHECK_NE(v8::Message::kNoColumnInfo, m_columnNumber + 1);
}
void StackFrame::translate(WasmTranslation* wasmTranslation) {
wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
&m_scriptId, &m_lineNumber, &m_columnNumber);
}
const String16& StackFrame::functionName() const { return m_functionName; }
const String16& StackFrame::scriptId() const { return m_scriptId; }
......
......@@ -18,7 +18,6 @@ namespace v8_inspector {
class AsyncStackTrace;
class V8Debugger;
class WasmTranslation;
struct V8StackTraceId;
class StackFrame {
......@@ -26,8 +25,6 @@ class StackFrame {
explicit StackFrame(v8::Isolate* isolate, v8::Local<v8::StackFrame> frame);
~StackFrame() = default;
void translate(WasmTranslation* wasmTranslation);
const String16& functionName() const;
const String16& scriptId() const;
const String16& sourceURL() const;
......
// 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/wasm-translation.h"
#include <algorithm>
#include <utility>
#include "src/debug/debug-interface.h"
#include "src/inspector/string-util.h"
#include "src/inspector/v8-debugger-agent-impl.h"
#include "src/inspector/v8-debugger-script.h"
#include "src/inspector/v8-debugger.h"
#include "src/inspector/v8-inspector-impl.h"
namespace v8_inspector {
using OffsetTable = v8::debug::WasmDisassembly::OffsetTable;
struct WasmSourceInformation {
String16 source;
int end_line = 0;
int end_column = 0;
OffsetTable offset_table;
OffsetTable reverse_offset_table;
WasmSourceInformation(String16 source, OffsetTable offset_table)
: source(std::move(source)), offset_table(std::move(offset_table)) {
int num_lines = 0;
int last_newline = -1;
size_t next_newline = this->source.find('\n', last_newline + 1);
while (next_newline != String16::kNotFound) {
last_newline = static_cast<int>(next_newline);
next_newline = this->source.find('\n', last_newline + 1);
++num_lines;
}
end_line = num_lines;
end_column = static_cast<int>(this->source.length()) - last_newline - 1;
reverse_offset_table = this->offset_table;
// Order by line, column, then byte offset.
auto cmp = [](OffsetTable::value_type el1, OffsetTable::value_type el2) {
if (el1.line != el2.line) return el1.line < el2.line;
if (el1.column != el2.column) return el1.column < el2.column;
return el1.byte_offset < el2.byte_offset;
};
std::sort(reverse_offset_table.begin(), reverse_offset_table.end(), cmp);
}
WasmSourceInformation() = default;
};
class WasmTranslation::TranslatorImpl {
public:
struct TransLocation {
WasmTranslation* translation;
String16 script_id;
int line;
int column;
TransLocation(WasmTranslation* translation, String16 script_id, int line,
int column)
: translation(translation),
script_id(std::move(script_id)),
line(line),
column(column) {}
};
TranslatorImpl(v8::Isolate* isolate, WasmTranslation* translation,
v8::Local<v8::debug::WasmScript> script)
: script_(isolate, script) {
script_.AnnotateStrongRetainer(kGlobalScriptHandleLabel);
ForEachFunction(script, [this, translation](String16& script_id,
int func_idx) {
translation->AddFakeScript(GetFakeScriptId(script_id, func_idx), this);
});
}
template <typename Callback>
void ForEachFunction(v8::Local<v8::debug::WasmScript> script,
Callback callback) {
int num_functions = script->NumFunctions();
int num_imported_functions = script->NumImportedFunctions();
DCHECK_LE(0, num_imported_functions);
DCHECK_LE(0, num_functions);
DCHECK_GE(num_functions, num_imported_functions);
String16 script_id = String16::fromInteger(script->Id());
for (int func_idx = num_imported_functions; func_idx < num_functions;
++func_idx) {
callback(script_id, func_idx);
}
}
void ReportFakeScripts(v8::Isolate* isolate, WasmTranslation* translation,
V8DebuggerAgentImpl* agent) {
ForEachFunction(
script_.Get(isolate), [=](String16& script_id, int func_idx) {
ReportFakeScript(isolate, script_id, func_idx, translation, agent);
});
}
void Translate(TransLocation* loc) {
v8::Isolate* isolate = loc->translation->isolate_;
int func_index = GetFunctionIndexFromLocation(loc);
DCHECK_GE(func_index, 0);
const OffsetTable& offset_table = GetOffsetTable(isolate, func_index);
DCHECK(!offset_table.empty());
std::pair<int, int> func_range =
script_.Get(isolate)->GetFunctionRange(func_index);
DCHECK_LE(func_range.first, loc->column);
DCHECK_LT(loc->column, func_range.second);
uint32_t byte_offset =
static_cast<uint32_t>(loc->column - func_range.first);
// Binary search for the given offset.
unsigned left = 0; // inclusive
unsigned right = static_cast<unsigned>(offset_table.size()); // exclusive
while (right - left > 1) {
unsigned mid = (left + right) / 2;
if (offset_table[mid].byte_offset <= byte_offset) {
left = mid;
} else {
right = mid;
}
}
loc->script_id = GetFakeScriptId(loc);
if (offset_table[left].byte_offset == byte_offset) {
loc->line = offset_table[left].line;
loc->column = offset_table[left].column;
} else {
loc->line = 0;
loc->column = 0;
}
}
static bool LessThan(const v8::debug::WasmDisassemblyOffsetTableEntry& entry,
const TransLocation& loc) {
return entry.line < loc.line ||
(entry.line == loc.line && entry.column < loc.column);
}
void TranslateBack(TransLocation* loc) {
v8::Isolate* isolate = loc->translation->isolate_;
int func_index = GetFunctionIndexFromFakeScriptId(loc->script_id);
const OffsetTable& reverse_table = GetReverseTable(isolate, func_index);
if (reverse_table.empty()) return;
// Binary search for the given line and column.
auto element = std::lower_bound(reverse_table.begin(), reverse_table.end(),
*loc, LessThan);
std::pair<int, int> func_range =
script_.Get(isolate)->GetFunctionRange(func_index);
DCHECK_LE(func_range.first, func_range.second);
int found_byte_offset = func_range.first;
// We want an entry on the same line if possible.
if (element == reverse_table.end()) {
// We did not find an element, so this points after the function.
found_byte_offset = func_range.second;
} else if (element->line == loc->line || element == reverse_table.begin()) {
found_byte_offset = element->byte_offset + func_range.first;
} else {
auto prev = element - 1;
DCHECK(prev->line == loc->line);
found_byte_offset = prev->byte_offset + func_range.first;
}
loc->script_id = String16::fromInteger(script_.Get(isolate)->Id());
loc->line = 0;
loc->column = found_byte_offset;
}
const WasmSourceInformation& GetSourceInformation(v8::Isolate* isolate,
int index) {
auto it = source_informations_.find(index);
if (it != source_informations_.end()) return it->second;
v8::HandleScope scope(isolate);
v8::Local<v8::debug::WasmScript> script = script_.Get(isolate);
v8::debug::WasmDisassembly disassembly = script->DisassembleFunction(index);
auto inserted = source_informations_.insert(std::make_pair(
index, WasmSourceInformation({disassembly.disassembly.data(),
disassembly.disassembly.length()},
std::move(disassembly.offset_table))));
DCHECK(inserted.second);
return inserted.first->second;
}
const String16 GetHash(v8::Isolate* isolate, int index) {
v8::HandleScope scope(isolate);
v8::Local<v8::debug::WasmScript> script = script_.Get(isolate);
uint32_t hash = script->GetFunctionHash(index);
String16Builder builder;
builder.appendUnsignedAsHex(hash);
return builder.toString();
}
int GetContextId(v8::Isolate* isolate) {
v8::HandleScope scope(isolate);
v8::Local<v8::debug::WasmScript> script = script_.Get(isolate);
return script->ContextId().FromMaybe(0);
}
private:
friend class WasmTranslation;
String16 GetFakeScriptUrl(v8::Isolate* isolate, int func_index) {
v8::Local<v8::debug::WasmScript> script = script_.Get(isolate);
String16 script_name =
toProtocolString(isolate, script->Name().ToLocalChecked());
int numFunctions = script->NumFunctions();
int numImported = script->NumImportedFunctions();
String16Builder builder;
builder.appendAll("wasm://wasm/", script_name, '/');
if (numFunctions - numImported > 300) {
size_t digits = String16::fromInteger(numFunctions - 1).length();
String16 thisCategory = String16::fromInteger((func_index / 100) * 100);
DCHECK_LE(thisCategory.length(), digits);
for (size_t i = thisCategory.length(); i < digits; ++i)
builder.append('0');
builder.appendAll(thisCategory, '/');
}
builder.appendAll(script_name, '-');
builder.appendNumber(func_index);
return builder.toString();
}
String16 GetFakeScriptId(const String16& script_id, int func_index) {
return String16::concat(script_id, '-', String16::fromInteger(func_index));
}
String16 GetFakeScriptId(const TransLocation* loc) {
return GetFakeScriptId(loc->script_id, GetFunctionIndexFromLocation(loc));
}
void ReportFakeScript(v8::Isolate* isolate,
const String16& underlyingScriptId, int func_idx,
WasmTranslation* translation,
V8DebuggerAgentImpl* agent) {
String16 fake_script_id = GetFakeScriptId(underlyingScriptId, func_idx);
String16 fake_script_url = GetFakeScriptUrl(isolate, func_idx);
std::unique_ptr<V8DebuggerScript> fake_script =
V8DebuggerScript::CreateWasm(isolate, translation, script_.Get(isolate),
fake_script_id, std::move(fake_script_url),
func_idx);
agent->didParseSource(std::move(fake_script), true);
}
int GetFunctionIndexFromFakeScriptId(const String16& fake_script_id) {
size_t last_dash_pos = fake_script_id.reverseFind('-');
DCHECK_GT(fake_script_id.length(), last_dash_pos);
bool ok = true;
int func_index = fake_script_id.substring(last_dash_pos + 1).toInteger(&ok);
DCHECK(ok);
return func_index;
}
int GetFunctionIndexFromLocation(const TransLocation* loc) {
DCHECK_EQ(0, loc->line);
v8::Isolate* isolate = loc->translation->isolate_;
v8::Local<v8::debug::WasmScript> script = script_.Get(isolate);
return script->GetContainingFunction(loc->column);
}
const OffsetTable& GetOffsetTable(v8::Isolate* isolate, int func_index) {
return GetSourceInformation(isolate, func_index).offset_table;
}
const OffsetTable& GetReverseTable(v8::Isolate* isolate, int func_index) {
return GetSourceInformation(isolate, func_index).reverse_offset_table;
}
static constexpr char kGlobalScriptHandleLabel[] =
"WasmTranslation::TranslatorImpl::script_";
v8::Global<v8::debug::WasmScript> script_;
// We assume to only disassemble a subset of the functions, so store them in a
// map instead of an array.
std::unordered_map<int, WasmSourceInformation> source_informations_;
// Disallow copies, because our pointer is registered in translation.
DISALLOW_COPY_AND_ASSIGN(TranslatorImpl);
};
constexpr char WasmTranslation::TranslatorImpl::kGlobalScriptHandleLabel[];
WasmTranslation::WasmTranslation(v8::Isolate* isolate) : isolate_(isolate) {}
WasmTranslation::~WasmTranslation() { Clear(); }
void WasmTranslation::AddScript(v8::Local<v8::debug::WasmScript> script,
V8DebuggerAgentImpl* agent) {
auto& impl = wasm_translators_[script->Id()];
if (impl == nullptr) {
impl = std::make_unique<TranslatorImpl>(isolate_, this, script);
}
impl->ReportFakeScripts(isolate_, this, agent);
}
void WasmTranslation::Clear() {
wasm_translators_.clear();
fake_scripts_.clear();
}
void WasmTranslation::Clear(v8::Isolate* isolate,
const std::vector<int>& contextIdsToClear) {
for (auto iter = fake_scripts_.begin(); iter != fake_scripts_.end();) {
auto contextId = iter->second->GetContextId(isolate);
auto it = std::find(std::begin(contextIdsToClear),
std::end(contextIdsToClear), contextId);
if (it != std::end(contextIdsToClear)) {
iter = fake_scripts_.erase(iter);
} else {
++iter;
}
}
for (auto iter = wasm_translators_.begin();
iter != wasm_translators_.end();) {
auto contextId = iter->second->GetContextId(isolate);
auto it = std::find(std::begin(contextIdsToClear),
std::end(contextIdsToClear), contextId);
if (it != std::end(contextIdsToClear)) {
iter = wasm_translators_.erase(iter);
} else {
++iter;
}
}
}
const String16& WasmTranslation::GetSource(const String16& script_id,
int func_index) {
auto it = fake_scripts_.find(script_id);
DCHECK_NE(it, fake_scripts_.end());
return it->second->GetSourceInformation(isolate_, func_index).source;
}
int WasmTranslation::GetEndLine(const String16& script_id, int func_index) {
auto it = fake_scripts_.find(script_id);
DCHECK_NE(it, fake_scripts_.end());
return it->second->GetSourceInformation(isolate_, func_index).end_line;
}
int WasmTranslation::GetEndColumn(const String16& script_id, int func_index) {
auto it = fake_scripts_.find(script_id);
DCHECK_NE(it, fake_scripts_.end());
return it->second->GetSourceInformation(isolate_, func_index).end_column;
}
String16 WasmTranslation::GetHash(const String16& script_id, int func_index) {
auto it = fake_scripts_.find(script_id);
DCHECK_NE(it, fake_scripts_.end());
return it->second->GetHash(isolate_, func_index);
}
// Translation "forward" (to artificial scripts).
bool WasmTranslation::TranslateWasmScriptLocationToProtocolLocation(
String16* script_id, int* line_number, int* column_number) {
DCHECK(script_id && line_number && column_number);
bool ok = true;
int script_id_int = script_id->toInteger(&ok);
if (!ok) return false;
auto it = wasm_translators_.find(script_id_int);
if (it == wasm_translators_.end()) return false;
TranslatorImpl* translator = it->second.get();
TranslatorImpl::TransLocation trans_loc(this, std::move(*script_id),
*line_number, *column_number);
translator->Translate(&trans_loc);
*script_id = std::move(trans_loc.script_id);
*line_number = trans_loc.line;
*column_number = trans_loc.column;
return true;
}
// Translation "backward" (from artificial to real scripts).
bool WasmTranslation::TranslateProtocolLocationToWasmScriptLocation(
String16* script_id, int* line_number, int* column_number) {
auto it = fake_scripts_.find(*script_id);
if (it == fake_scripts_.end()) return false;
TranslatorImpl* translator = it->second;
TranslatorImpl::TransLocation trans_loc(this, std::move(*script_id),
*line_number, *column_number);
translator->TranslateBack(&trans_loc);
*script_id = std::move(trans_loc.script_id);
*line_number = trans_loc.line;
*column_number = trans_loc.column;
return true;
}
// Find the end byte offset for a fake script.
int WasmTranslation::GetEndOffset(const String16& script_id) {
auto it = fake_scripts_.find(script_id);
DCHECK_NE(fake_scripts_.end(), it);
TranslatorImpl* translator = it->second;
int func_index = translator->GetFunctionIndexFromFakeScriptId(script_id);
std::pair<int, int> func_range =
translator->script_.Get(isolate_)->GetFunctionRange(func_index);
return func_range.second;
}
void WasmTranslation::AddFakeScript(const String16& scriptId,
TranslatorImpl* translator) {
DCHECK_EQ(0, fake_scripts_.count(scriptId));
fake_scripts_.insert(std::make_pair(scriptId, translator));
}
} // namespace v8_inspector
// 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.
#ifndef V8_INSPECTOR_WASM_TRANSLATION_H_
#define V8_INSPECTOR_WASM_TRANSLATION_H_
#include <memory>
#include <unordered_map>
#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 V8DebuggerAgentImpl;
class WasmTranslation {
public:
explicit WasmTranslation(v8::Isolate* isolate);
~WasmTranslation();
// 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();
// Clear all registered scripts for context group.
void Clear(v8::Isolate* isolate, const std::vector<int>& contextIdsToClear);
// Translate a location as generated by V8 to a location that should be sent
// over protocol.
// Does nothing for locations referencing a script which was not registered
// before via AddScript.
// Line and column are 0-based.
// Returns true if the location was translated, false otherwise.
bool TranslateWasmScriptLocationToProtocolLocation(String16* script_id,
int* line_number,
int* column_number);
// Translate back from protocol locations (potentially referencing artificial
// scripts for individual wasm functions) to locations that make sense to V8.
// Does nothing if the location was not generated by the translate method
// above.
// Returns true if the location was translated, false otherwise.
bool TranslateProtocolLocationToWasmScriptLocation(String16* script_id,
int* line_number,
int* column_number);
// Find the end byte offset for a fake script.
int GetEndOffset(const String16& script_id);
const String16& GetSource(const String16& script_id, int func_index);
int GetStartLine(const String16& script_id, int func_index) { return 0; }
int GetStartColumn(const String16& script_id, int func_index) { return 0; }
int GetEndLine(const String16& script_id, int func_index);
int GetEndColumn(const String16& script_id, int func_index);
String16 GetHash(const String16& script_id, int func_index);
private:
class TranslatorImpl;
friend class TranslatorImpl;
void AddFakeScript(const String16& scriptId, TranslatorImpl* translator);
v8::Isolate* isolate_;
std::unordered_map<int, std::unique_ptr<TranslatorImpl>> wasm_translators_;
std::unordered_map<String16, TranslatorImpl*> fake_scripts_;
DISALLOW_COPY_AND_ASSIGN(WasmTranslation);
};
} // namespace v8_inspector
#endif // V8_INSPECTOR_WASM_TRANSLATION_H_
......@@ -14,8 +14,8 @@ var break_count = 0;
const expected_frames = [
// func-name; wasm?; pos; line; col
['call_debugger', false], // --
['wasm_2', true, 56, 2, 2], // --
['wasm_1', true, 52, 3, 2], // --
['wasm_2', true, 56, 1, 60], // --
['wasm_1', true, 52, 1, 55], // --
['testFrameInspection', false], // --
['', false]
];
......
......@@ -13,7 +13,7 @@ let {session, contextGroup, Protocol} =
let builder = new WasmModuleBuilder();
builder.addImportedGlobal('m', 'global', kWasmAnyRef, false);
builder.addFunction('func', kSig_v_v)
let func = builder.addFunction('func', kSig_v_v)
.addBody([
kExprGlobalGet, 0, //
kExprDrop, //
......@@ -39,8 +39,7 @@ let {session, contextGroup, Protocol} =
let scriptId;
while (true) {
let msg = await Protocol.Debugger.onceScriptParsed();
if (msg.params.url.startsWith('wasm://') &&
msg.params.url.split('/').length == 5) {
if (msg.params.url.startsWith('wasm://')) {
scriptId = msg.params.scriptId;
break;
}
......@@ -48,7 +47,7 @@ let {session, contextGroup, Protocol} =
InspectorTest.log('Setting breakpoint in wasm.');
await Protocol.Debugger.setBreakpoint(
{location: {scriptId, lineNumber: 2}});
{location: {scriptId, lineNumber: 0, columnNumber: func.body_offset}});
InspectorTest.log('Running main.');
Protocol.Runtime.evaluate({expression: 'instance.exports.main()'});
......
Tests that cloning a module notifies the debugger
Got URL: wasm://wasm/95d1e44e
Got URL: wasm://wasm/95d1e44e/95d1e44e-0
Got URL: wasm://wasm/95d1e44e
Got URL: wasm://wasm/95d1e44e/95d1e44e-0
Got URL: wasm://wasm/95d1e44e
Got URL: wasm://wasm/95d1e44e/95d1e44e-0
Done!
......@@ -29,7 +29,7 @@ Protocol.Debugger.onScriptParsed(msg => {
let url = msg.params.url;
if (url.startsWith('wasm://')) {
InspectorTest.log(`Got URL: ${url}`);
if (++scriptsSeen == 6) {
if (++scriptsSeen == 3) {
InspectorTest.log('Done!');
InspectorTest.completeTest();
}
......
......@@ -4,8 +4,6 @@ Script nr 0 parsed. URL: v8://test/setup
Script nr 1 parsed. URL: v8://test/runTestFunction
Script nr 2 parsed. URL: wasm://wasm/6a95b41e
This is a wasm script (nr 0).
Script nr 3 parsed. URL: wasm://wasm/6a95b41e/6a95b41e-0
Script nr 4 parsed. URL: wasm://wasm/6a95b41e/6a95b41e-1
Querying breakable locations for all wasm scripts now...
Requesting all breakable locations in wasm script 0
Bytecode matches!
......@@ -59,27 +57,27 @@ Setting at wasm://wasm/6a95b41e:0:58
Success!
Running wasm code...
Missing breakpoints: 11
Script nr 5 parsed. URL: v8://test/runWasm
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:1:2
Script nr 3 parsed. URL: v8://test/runWasm
Stopped at wasm://wasm/6a95b41e:0:48
Missing breakpoints: 10
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:2:2
Stopped at wasm://wasm/6a95b41e:0:50
Missing breakpoints: 9
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:3:4
Stopped at wasm://wasm/6a95b41e:0:52
Missing breakpoints: 8
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:4:6
Stopped at wasm://wasm/6a95b41e:0:54
Missing breakpoints: 7
Stopped at wasm://wasm/6a95b41e/6a95b41e-0:2:2
Stopped at wasm://wasm/6a95b41e:0:40
Missing breakpoints: 6
Stopped at wasm://wasm/6a95b41e/6a95b41e-0:3:2
Stopped at wasm://wasm/6a95b41e:0:41
Missing breakpoints: 5
Stopped at wasm://wasm/6a95b41e/6a95b41e-0:4:2
Stopped at wasm://wasm/6a95b41e:0:43
Missing breakpoints: 4
Stopped at wasm://wasm/6a95b41e/6a95b41e-0:5:0
Stopped at wasm://wasm/6a95b41e:0:45
Missing breakpoints: 3
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:5:4
Stopped at wasm://wasm/6a95b41e:0:56
Missing breakpoints: 2
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:6:2
Stopped at wasm://wasm/6a95b41e:0:57
Missing breakpoints: 1
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:7:0
Stopped at wasm://wasm/6a95b41e:0:58
Missing breakpoints: 0
Finished!
......@@ -221,6 +221,12 @@ async function setAllBreakableLocations() {
function recordPausedLocation(msg) {
var topLocation = msg.params.callFrames[0].location;
InspectorTest.log('Stopped at ' + locationStr(topLocation));
for (var i = 0; i < allBreakableLocations.length; ++i) {
if (locationMatches(topLocation, allBreakableLocations[i])) {
allBreakableLocations.splice(i, 1);
break;
}
}
}
async function waitForAllPauses() {
......@@ -232,4 +238,8 @@ async function waitForAllPauses() {
remaining--;
InspectorTest.log('Missing breakpoints: ' + remaining);
}
if (allBreakableLocations.length != 0) {
InspectorTest.log('Did not hit all breakable locations: '
+ JSON.stringify(allBreakableLocations));
}
}
Tests breakable locations in wasm
Running testFunction...
Script nr 0 parsed. URL: v8://test/setup
Script nr 1 parsed. URL: v8://test/runTestFunction
Script nr 2 parsed. URL: wasm://wasm/6a95b41e
Script nr 3 parsed. URL: wasm://wasm/6a95b41e/6a95b41e-0
This is a wasm script (nr 0).
Script nr 4 parsed. URL: wasm://wasm/6a95b41e/6a95b41e-1
This is a wasm script (nr 1).
Querying breakable locations for all wasm scripts now...
Requesting all breakable locations in wasm script 0
4 breakable location(s):
[0] 2:2 || >nop
[1] 3:2 || >i32.const 12
[2] 4:2 || >local.set 0
[3] 5:0 || >end
Requesting breakable locations in lines [0,3)
1 breakable location(s):
[0] 2:2 || >nop
Requesting breakable locations in lines [4,6)
2 breakable location(s):
[0] 4:2 || >local.set 0
[1] 5:0 || >end
Requesting all breakable locations in wasm script 1
7 breakable location(s):
[0] 1:2 || >local.get 0
[1] 2:2 || >if
[2] 3:4 || >block
[3] 4:6 || >call 0
[4] 5:4 || >end
[5] 6:2 || >end
[6] 7:0 || >end
Requesting breakable locations in lines [0,3)
2 breakable location(s):
[0] 1:2 || >local.get 0
[1] 2:2 || >if
Requesting breakable locations in lines [4,6)
2 breakable location(s):
[0] 4:6 || >call 0
[1] 5:4 || >end
Setting a breakpoint on each breakable location...
Setting at wasm://wasm/6a95b41e/6a95b41e-0:2:2
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-0:3:2
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-0:4:2
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-0:5:0
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-1:1:2
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-1:2:2
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-1:3:4
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-1:4:6
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-1:5:4
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-1:6:2
Success!
Setting at wasm://wasm/6a95b41e/6a95b41e-1:7:0
Success!
Running wasm code...
Missing breakpoints: 11
Script nr 5 parsed. URL: v8://test/runWasm
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:1:2
Missing breakpoints: 10
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:2:2
Missing breakpoints: 9
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:3:4
Missing breakpoints: 8
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:4:6
Missing breakpoints: 7
Stopped at wasm://wasm/6a95b41e/6a95b41e-0:2:2
Missing breakpoints: 6
Stopped at wasm://wasm/6a95b41e/6a95b41e-0:3:2
Missing breakpoints: 5
Stopped at wasm://wasm/6a95b41e/6a95b41e-0:4:2
Missing breakpoints: 4
Stopped at wasm://wasm/6a95b41e/6a95b41e-0:5:0
Missing breakpoints: 3
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:5:4
Missing breakpoints: 2
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:6:2
Missing breakpoints: 1
Stopped at wasm://wasm/6a95b41e/6a95b41e-1:7:0
Missing breakpoints: 0
Finished!
// 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
let {session, contextGroup, Protocol} = InspectorTest.start('Tests breakable locations in wasm');
utils.load('test/mjsunit/wasm/wasm-module-builder.js');
var builder = new WasmModuleBuilder();
// clang-format off
var func_idx = builder.addFunction('helper', kSig_v_v)
.addLocals({i32_count: 1})
.addBody([
kExprNop,
kExprI32Const, 12,
kExprLocalSet, 0,
]).index;
builder.addFunction('main', kSig_v_i)
.addBody([
kExprLocalGet, 0,
kExprIf, kWasmStmt,
kExprBlock, kWasmStmt,
kExprCallFunction, func_idx,
kExprEnd,
kExprEnd
]).exportAs('main');
// clang-format on
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;
}
var module = new WebAssembly.Module(buffer);
// Set global variable.
instance = new WebAssembly.Instance(module);
}
var evalWithUrl = (code, url) => Protocol.Runtime.evaluate(
{'expression': code + '\n//# sourceURL=v8://test/' + url});
var setupCode = testFunction.toString() + ';\nvar module_bytes = ' +
JSON.stringify(module_bytes) + ';\nvar instance;';
Protocol.Debugger.enable();
Protocol.Debugger.onScriptParsed(handleScriptParsed);
InspectorTest.log('Running testFunction...');
evalWithUrl(setupCode, 'setup')
.then(() => evalWithUrl('testFunction(module_bytes)', 'runTestFunction'))
.then(getBreakableLocationsForAllWasmScripts)
.then(setAllBreakableLocations)
.then(() => InspectorTest.log('Running wasm code...'))
.then(() => (evalWithUrl('instance.exports.main(1)', 'runWasm'), 0))
.then(waitForAllPauses)
.then(() => InspectorTest.log('Finished!'))
.then(InspectorTest.completeTest);
var allBreakableLocations = [];
var urls = {};
var numScripts = 0;
var wasmScripts = [];
function handleScriptParsed(messageObject) {
var scriptId = messageObject.params.scriptId;
var url = messageObject.params.url;
urls[scriptId] = url;
InspectorTest.log('Script nr ' + numScripts + ' parsed. URL: ' + url);
++numScripts;
if (url.startsWith('wasm://')) {
// Only want the fake (function specific) scripts, not the one for the full
// module.
if (url.split('/').length == 5) {
InspectorTest.log('This is a wasm script (nr ' + wasmScripts.length + ').');
wasmScripts.push(scriptId);
}
}
}
function printFailure(message) {
if (!message.result) {
InspectorTest.logMessage(message);
}
return message;
}
function printBreakableLocations(message, expectedScriptId, source) {
var lines = source.split('\n');
var locations = message.result.locations;
InspectorTest.log(locations.length + ' breakable location(s):');
for (var i = 0; i < locations.length; ++i) {
if (locations[i].scriptId != expectedScriptId) {
InspectorTest.log(
'SCRIPT ID MISMATCH!! ' + locations[i].scriptId + ' != ' +
expectedScriptId);
}
var line = '<illegal line number>';
if (locations[i].lineNumber < lines.length) {
line = lines[locations[i].lineNumber];
if (locations[i].columnNumber < line.length) {
line = line.substr(0, locations[i].columnNumber) + '>' +
line.substr(locations[i].columnNumber);
}
}
InspectorTest.log(
'[' + i + '] ' + locations[i].lineNumber + ':' +
locations[i].columnNumber + ' || ' + line);
}
}
function checkGetBreakableLocations(wasmScriptNr) {
InspectorTest.log(
'Requesting all breakable locations in wasm script ' + wasmScriptNr);
var scriptId = wasmScripts[wasmScriptNr];
var source;
return Protocol.Debugger.getScriptSource({scriptId: scriptId})
.then(msg => source = msg.result.scriptSource)
.then(
() => Protocol.Debugger.getPossibleBreakpoints(
{start: {lineNumber: 0, columnNumber: 0, scriptId: scriptId}}))
.then(printFailure)
.then(msg => (allBreakableLocations.push(...msg.result.locations), msg))
.then(msg => printBreakableLocations(msg, scriptId, source))
.then(
() => InspectorTest.log(
'Requesting breakable locations in lines [0,3)'))
.then(() => Protocol.Debugger.getPossibleBreakpoints({
start: {lineNumber: 0, columnNumber: 0, scriptId: scriptId},
end: {lineNumber: 3, columnNumber: 0, scriptId: scriptId}
}))
.then(printFailure)
.then(msg => printBreakableLocations(msg, scriptId, source))
.then(
() => InspectorTest.log(
'Requesting breakable locations in lines [4,6)'))
.then(() => Protocol.Debugger.getPossibleBreakpoints({
start: {lineNumber: 4, columnNumber: 0, scriptId: scriptId},
end: {lineNumber: 6, columnNumber: 0, scriptId: scriptId}
}))
.then(printFailure)
.then(msg => printBreakableLocations(msg, scriptId, source));
}
function getBreakableLocationsForAllWasmScripts() {
InspectorTest.log('Querying breakable locations for all wasm scripts now...');
var promise = Promise.resolve();
for (var wasmScriptNr = 0; wasmScriptNr < wasmScripts.length;
++wasmScriptNr) {
promise = promise.then(checkGetBreakableLocations.bind(null, wasmScriptNr));
}
return promise;
}
function locationMatches(loc1, loc2) {
return loc1.scriptId == loc2.scriptId && loc1.lineNumber == loc2.lineNumber &&
loc1.columnNumber == loc2.columnNumber;
}
function locationStr(loc) {
return urls[loc.scriptId] + ':' + loc.lineNumber + ':' + loc.columnNumber;
}
function setBreakpoint(loc) {
InspectorTest.log('Setting at ' + locationStr(loc));
function check(msg) {
if (locationMatches(loc, msg.result.actualLocation)) {
InspectorTest.log("Success!");
} else {
InspectorTest.log("Mismatch!");
InspectorTest.logMessage(msg);
}
}
return Protocol.Debugger.setBreakpoint({'location': loc})
.then(printFailure)
.then(check);
}
function setAllBreakableLocations() {
InspectorTest.log('Setting a breakpoint on each breakable location...');
var promise = Promise.resolve();
for (var loc of allBreakableLocations) {
promise = promise.then(setBreakpoint.bind(null, loc));
}
return promise;
}
function removePausedLocation(msg) {
var topLocation = msg.params.callFrames[0].location;
InspectorTest.log('Stopped at ' + locationStr(topLocation));
for (var i = 0; i < allBreakableLocations.length; ++i) {
if (locationMatches(topLocation, allBreakableLocations[i])) {
allBreakableLocations.splice(i, 1);
--i;
}
}
}
function waitForAllPauses() {
InspectorTest.log('Missing breakpoints: ' + allBreakableLocations.length);
if (allBreakableLocations.length == 0) return;
return Protocol.Debugger.oncePaused()
.then(removePausedLocation)
.then(Protocol.Debugger.resume())
.then(waitForAllPauses);
}
......@@ -4,17 +4,11 @@ Calling instantiate function for module A.
Waiting for wasm script to be parsed.
Got wasm script!
Setting breakpoint in line 1:
func $func
#nop
end
Script wasm://wasm/1871020e byte offset 33: Wasm opcode 0x1
Calling instantiate function for module B.
Calling main function on module B.
Paused at 1:2.
func $func
#nop
end
Paused at 0:33.
Script wasm://wasm/1871020e byte offset 33: Wasm opcode 0x1
Getting current stack trace via "new Error().stack".
Error
at v8://test/getStack:1:1
......
......@@ -12,10 +12,9 @@ utils.load('test/mjsunit/wasm/wasm-module-builder.js');
// This failed before (http://crbug.com/v8/5971).
var builder_a = new WasmModuleBuilder();
var func_idx = builder_a.addFunction('func', kSig_v_v)
var func = builder_a.addFunction('func', kSig_v_v)
.addBody([kExprNop])
.exportFunc()
.index;
.exportFunc();
var module_a_bytes = builder_a.toArray();
var builder_b = new WasmModuleBuilder();
......@@ -60,7 +59,8 @@ Protocol.Debugger.enable()
.then(url => (InspectorTest.log('Setting breakpoint in line 1:'), url))
.then(
url =>
Protocol.Debugger.setBreakpointByUrl({lineNumber: 1, url: url}))
Protocol.Debugger.setBreakpointByUrl(
{lineNumber: 0, columnNumber: func.body_offset, url: url}))
.then(printFailure)
.then(msg => session.logSourceLocations(msg.result.locations))
.then(() => InspectorTest.log('Calling instantiate function for module B.'))
......@@ -101,8 +101,7 @@ function printFailure(message) {
}
function waitForWasmScript(msg) {
if (!msg || !msg.params.url.startsWith('wasm://') ||
msg.params.url.split('/').length != 5) {
if (!msg || !msg.params.url.startsWith('wasm://')) {
return Protocol.Debugger.onceScriptParsed().then(waitForWasmScript);
}
InspectorTest.log('Got wasm script!');
......
......@@ -3,21 +3,17 @@ Installing code and global variable.
Calling instantiate function.
Waiting for wasm scripts to be parsed.
Ignoring script with url v8://test/callInstantiate
Ignoring script with url wasm://wasm/fa045c1e
Got wasm script: wasm://wasm/fa045c1e/fa045c1e-0
Got wasm script: wasm://wasm/fa045c1e
Setting breakpoint on line 3 of wasm function
{
columnNumber : 2
lineNumber : 3
columnNumber : 39
lineNumber : 0
scriptId : <scriptId>
}
BreakpointId: 4:3:0:6-0
BreakpointId: 4:0:39:6
paused No 1
i32.const 1
#i32.sub
end
Remove breakpoint with breakpointId: 4:3:0:6-0
Script wasm://wasm/fa045c1e byte offset 39: Wasm opcode 0x6b
Remove breakpoint with breakpointId: 4:0:39:6
Debugger.resume
exports.main returned!
Finished!
......@@ -10,7 +10,7 @@ utils.load('test/mjsunit/wasm/wasm-module-builder.js');
let builder = new WasmModuleBuilder();
// wasm_A
builder.addFunction('wasm_A', kSig_i_i)
let func = builder.addFunction('wasm_A', kSig_i_i)
.addBody([
// clang-format off
kExprLocalGet, 0, // Line 1: get input
......@@ -72,7 +72,7 @@ function test() {
InspectorTest.log(
'Setting breakpoint on line 3 of wasm function');
let msg = await Protocol.Debugger.setBreakpoint(
{'location': {'scriptId': scriptId, 'lineNumber': 3}});
{'location': {'scriptId': scriptId, 'lineNumber': 0, 'columnNumber': func.body_offset + 4}});
printFailure(msg);
InspectorTest.logMessage(msg.result.actualLocation);
InspectorTest.logMessage('BreakpointId: '+ msg.result.breakpointId);
......@@ -96,7 +96,7 @@ async function waitForWasmScript() {
while (true) {
let msg = await Protocol.Debugger.onceScriptParsed();
let url = msg.params.url;
if (!url.startsWith('wasm://') || url.split('/').length != 5) {
if (!url.startsWith('wasm://')) {
InspectorTest.log('Ignoring script with url ' + url);
continue;
}
......
Test retrieving scope information when pausing in wasm functions
Installing code and global variable.
Calling instantiate function.
Waiting for two wasm scripts to be parsed.
Waiting for wasm script to be parsed.
Got wasm script!
Got wasm script!
Setting breakpoint on line 2 (first instruction) of second function
Setting breakpoint on first instruction of second function
{
columnNumber : 2
lineNumber : 2
columnNumber : 69
lineNumber : 0
scriptId : <scriptId>
}
Paused:
(local i32 i64 f64)
#i32.const 11
local.set 0
Script wasm://wasm/0aafe946 byte offset 69: Wasm opcode 0x41
Scope:
at func (2:2):
at func (0:69):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 4 (number), "local#1": 0 (number), "i64_local": 0 (number), "unicode☼f64": 0 (number)
stack:
at call_func (5:2):
stack:
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -31,18 +27,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
i32.const 11
#local.set 0
i32.const 47
Script wasm://wasm/0aafe946 byte offset 71: Wasm opcode 0x21
Scope:
at func (3:2):
at func (0:71):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 4 (number), "local#1": 0 (number), "i64_local": 0 (number), "unicode☼f64": 0 (number)
stack: "0": 11 (number)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -51,18 +44,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
local.set 0
#i32.const 47
local.set 1
Script wasm://wasm/0aafe946 byte offset 73: Wasm opcode 0x41
Scope:
at func (4:2):
at func (0:73):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 0 (number), "i64_local": 0 (number), "unicode☼f64": 0 (number)
stack:
at call_func (5:2):
stack:
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -71,18 +61,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
i32.const 47
#local.set 1
i64.const 9223372036854775807
Script wasm://wasm/0aafe946 byte offset 75: Wasm opcode 0x21
Scope:
at func (5:2):
at func (0:75):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 0 (number), "i64_local": 0 (number), "unicode☼f64": 0 (number)
stack: "0": 47 (number)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -91,18 +78,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
local.set 1
#i64.const 9223372036854775807
local.set 2
Script wasm://wasm/0aafe946 byte offset 77: Wasm opcode 0x42
Scope:
at func (6:2):
at func (0:77):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": 0 (number), "unicode☼f64": 0 (number)
stack:
at call_func (5:2):
stack:
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -111,18 +95,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
i64.const 9223372036854775807
#local.set 2
i64.const -9223372036854775808
Script wasm://wasm/0aafe946 byte offset 88: Wasm opcode 0x21
Scope:
at func (7:2):
at func (0:88):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": 0 (number), "unicode☼f64": 0 (number)
stack: "0": 9223372036854775807 (string)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -131,18 +112,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
local.set 2
#i64.const -9223372036854775808
local.set 2
Script wasm://wasm/0aafe946 byte offset 90: Wasm opcode 0x42
Scope:
at func (8:2):
at func (0:90):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": 9223372036854775807 (string), "unicode☼f64": 0 (number)
stack:
at call_func (5:2):
stack:
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -151,18 +129,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
i64.const -9223372036854775808
#local.set 2
i32.const 1
Script wasm://wasm/0aafe946 byte offset 101: Wasm opcode 0x21
Scope:
at func (9:2):
at func (0:101):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": 9223372036854775807 (string), "unicode☼f64": 0 (number)
stack: "0": -9223372036854775808 (string)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -171,18 +146,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
local.set 2
#i32.const 1
f64.convert_i32_u
Script wasm://wasm/0aafe946 byte offset 103: Wasm opcode 0x41
Scope:
at func (10:2):
at func (0:103):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": -9223372036854775808 (string), "unicode☼f64": 0 (number)
stack:
at call_func (5:2):
stack:
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -191,18 +163,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
i32.const 1
#f64.convert_i32_u
i32.const 7
Script wasm://wasm/0aafe946 byte offset 105: Wasm opcode 0xb8
Scope:
at func (11:2):
at func (0:105):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": -9223372036854775808 (string), "unicode☼f64": 0 (number)
stack: "0": 1 (number)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -211,18 +180,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
f64.convert_i32_u
#i32.const 7
f64.convert_i32_u
Script wasm://wasm/0aafe946 byte offset 106: Wasm opcode 0x41
Scope:
at func (12:2):
at func (0:106):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": -9223372036854775808 (string), "unicode☼f64": 0 (number)
stack: "0": 1 (number)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -231,18 +197,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
i32.const 7
#f64.convert_i32_u
f64.div
Script wasm://wasm/0aafe946 byte offset 108: Wasm opcode 0xb8
Scope:
at func (13:2):
at func (0:108):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": -9223372036854775808 (string), "unicode☼f64": 0 (number)
stack: "0": 1 (number), "1": 7 (number)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -251,18 +214,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
f64.convert_i32_u
#f64.div
local.set 3
Script wasm://wasm/0aafe946 byte offset 109: Wasm opcode 0xa3
Scope:
at func (14:2):
at func (0:109):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": -9223372036854775808 (string), "unicode☼f64": 0 (number)
stack: "0": 1 (number), "1": 7 (number)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -271,18 +231,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
f64.div
#local.set 3
i32.const 15
Script wasm://wasm/0aafe946 byte offset 110: Wasm opcode 0x21
Scope:
at func (15:2):
at func (0:110):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": -9223372036854775808 (string), "unicode☼f64": 0 (number)
stack: "0": 0.14285714285714285 (number)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -291,18 +248,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
local.set 3
#i32.const 15
global.set 0
Script wasm://wasm/0aafe946 byte offset 112: Wasm opcode 0x41
Scope:
at func (16:2):
at func (0:112):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": -9223372036854775808 (string), "unicode☼f64": 0.14285714285714285 (number)
stack:
at call_func (5:2):
stack:
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -311,18 +265,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
i32.const 15
#global.set 0
end
Script wasm://wasm/0aafe946 byte offset 114: Wasm opcode 0x24
Scope:
at func (17:2):
at func (0:114):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": -9223372036854775808 (string), "unicode☼f64": 0.14285714285714285 (number)
stack: "0": 15 (number)
at call_func (5:2):
at call_func (0:58):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -331,18 +282,15 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
global.set 0
#end
Script wasm://wasm/0aafe946 byte offset 116: Wasm opcode 0xb
Scope:
at func (18:0):
at func (0:116):
- scope (global):
globals: "global#0": 15 (number)
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "i64_local": -9223372036854775808 (string), "unicode☼f64": 0.14285714285714285 (number)
stack:
at call_func (5:2):
stack:
at call_func (0:58):
- scope (global):
globals: "global#0": 15 (number)
- scope (local):
......
Test retrieving scope information from compiled Liftoff frames
Installing instantiate code.
Waiting for three wasm scripts to be parsed.
Waiting for wasm script to be parsed.
Calling instantiate function.
Got wasm script!
Got wasm script!
Got wasm script!
Setting breakpoint on line 2 (first instruction) of third function
{
columnNumber : 2
lineNumber : 2
columnNumber : 85
lineNumber : 0
scriptId : <scriptId>
}
Paused:
(local i32)
#local.get 0
global.set 0
Script wasm://wasm/71172dd6 byte offset 85: Wasm opcode 0x20
Scope:
at C (interpreted) (2:2):
at C (interpreted) (0:85):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32_arg": 42 (number), "i32_local": 0 (number)
stack:
at B (liftoff) (7:2):
stack:
at B (liftoff) (0:76):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
at A (liftoff) (2:2):
at A (liftoff) (0:54):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -36,22 +31,19 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
local.get 0
#global.set 0
i32.const 47
Script wasm://wasm/71172dd6 byte offset 87: Wasm opcode 0x24
Scope:
at C (interpreted) (3:2):
at C (interpreted) (0:87):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
locals: "i32_arg": 42 (number), "i32_local": 0 (number)
stack: "0": 42 (number)
at B (liftoff) (7:2):
at B (liftoff) (0:76):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
at A (liftoff) (2:2):
at A (liftoff) (0:54):
- scope (global):
globals: "global#0": 0 (number)
- scope (local):
......@@ -60,22 +52,19 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
global.set 0
#i32.const 47
local.set 1
Script wasm://wasm/71172dd6 byte offset 89: Wasm opcode 0x41
Scope:
at C (interpreted) (4:2):
at C (interpreted) (0:89):
- scope (global):
globals: "global#0": 42 (number)
- scope (local):
locals: "i32_arg": 42 (number), "i32_local": 0 (number)
stack:
at B (liftoff) (7:2):
stack:
at B (liftoff) (0:76):
- scope (global):
globals: "global#0": 42 (number)
- scope (local):
at A (liftoff) (2:2):
at A (liftoff) (0:54):
- scope (global):
globals: "global#0": 42 (number)
- scope (local):
......@@ -84,22 +73,19 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
i32.const 47
#local.set 1
end
Script wasm://wasm/71172dd6 byte offset 91: Wasm opcode 0x21
Scope:
at C (interpreted) (5:2):
at C (interpreted) (0:91):
- scope (global):
globals: "global#0": 42 (number)
- scope (local):
locals: "i32_arg": 42 (number), "i32_local": 0 (number)
stack: "0": 47 (number)
at B (liftoff) (7:2):
at B (liftoff) (0:76):
- scope (global):
globals: "global#0": 42 (number)
- scope (local):
at A (liftoff) (2:2):
at A (liftoff) (0:54):
- scope (global):
globals: "global#0": 42 (number)
- scope (local):
......@@ -108,22 +94,19 @@ at (anonymous) (0:17):
-- skipped globals
Paused:
local.set 1
#end
Script wasm://wasm/71172dd6 byte offset 93: Wasm opcode 0xb
Scope:
at C (interpreted) (6:0):
at C (interpreted) (0:93):
- scope (global):
globals: "global#0": 42 (number)
- scope (local):
locals: "i32_arg": 42 (number), "i32_local": 47 (number)
stack:
at B (liftoff) (7:2):
stack:
at B (liftoff) (0:76):
- scope (global):
globals: "global#0": 42 (number)
- scope (local):
at A (liftoff) (2:2):
at A (liftoff) (0:54):
- scope (global):
globals: "global#0": 42 (number)
- scope (local):
......
......@@ -14,6 +14,8 @@ Protocol.Debugger.onPaused(printPauseLocationsAndContinue);
let evaluate = code => Protocol.Runtime.evaluate({expression: code});
let breakpointLocation = -1;
(async function test() {
// Instantiate wasm and wait for three wasm scripts for the three functions.
instantiateWasm();
......@@ -23,7 +25,7 @@ let evaluate = code => Protocol.Runtime.evaluate({expression: code});
InspectorTest.log(
'Setting breakpoint on line 2 (first instruction) of third function');
let breakpoint = await Protocol.Debugger.setBreakpoint(
{'location': {'scriptId': scriptIds[2], 'lineNumber': 2}});
{'location': {'scriptId': scriptIds[0], 'lineNumber': 0, 'columnNumber': breakpointLocation}});
printIfFailure(breakpoint);
InspectorTest.logMessage(breakpoint.result.actualLocation);
......@@ -95,7 +97,7 @@ async function instantiateWasm() {
]);
// A third function which will be stepped through.
builder.addFunction('C (interpreted)', kSig_v_i)
let func = builder.addFunction('C (interpreted)', kSig_v_i)
.addLocals({i32_count: 1}, ['i32_arg', 'i32_local'])
.addBody([
// Set global 0 to param 0.
......@@ -105,6 +107,7 @@ async function instantiateWasm() {
]);
var module_bytes = builder.toArray();
breakpointLocation = func.body_offset;
function instantiate(bytes) {
var buffer = new ArrayBuffer(bytes.length);
......@@ -131,12 +134,12 @@ function printIfFailure(message) {
}
async function waitForWasmScripts() {
InspectorTest.log('Waiting for three wasm scripts to be parsed.');
InspectorTest.log('Waiting for wasm script to be parsed.');
let wasm_script_ids = [];
while (wasm_script_ids.length < 3) {
while (wasm_script_ids.length < 1) {
let script_msg = await Protocol.Debugger.onceScriptParsed();
let url = script_msg.params.url;
if (url.startsWith('wasm://') && url.split('/').length == 5) {
if (url.startsWith('wasm://')) {
InspectorTest.log('Got wasm script!');
wasm_script_ids.push(script_msg.params.scriptId);
}
......
......@@ -9,6 +9,8 @@ Protocol.Debugger.enable();
let evaluate = code => Protocol.Runtime.evaluate({expression: code});
let breakpointLocation = -1;
(async function test() {
let scriptIds = await instantiateWasm();
await setBreakpoint(scriptIds);
......@@ -45,7 +47,7 @@ async function instantiateWasm() {
]).exportAs('main');
// A second function which will be stepped through.
builder.addFunction('func', kSig_v_i)
let func = builder.addFunction('func', kSig_v_i)
.addLocals(
{i32_count: 1, i64_count: 1, f64_count: 1},
['i32Arg', undefined, 'i64_local', 'unicode☼f64'])
......@@ -69,6 +71,7 @@ async function instantiateWasm() {
]);
var module_bytes = builder.toArray();
breakpointLocation = func.body_offset;
function instantiate(bytes) {
var buffer = new ArrayBuffer(bytes.length);
......@@ -91,9 +94,9 @@ async function instantiateWasm() {
async function setBreakpoint(scriptIds) {
InspectorTest.log(
'Setting breakpoint on line 2 (first instruction) of second function');
'Setting breakpoint on first instruction of second function');
let breakpoint = await Protocol.Debugger.setBreakpoint(
{'location': {'scriptId': scriptIds[1], 'lineNumber': 2}});
{'location': {'scriptId': scriptIds[0], 'lineNumber': 0, 'columnNumber': breakpointLocation}});
printFailure(breakpoint);
InspectorTest.logMessage(breakpoint.result.actualLocation);
}
......@@ -106,12 +109,12 @@ function printFailure(message) {
}
async function waitForWasmScripts() {
InspectorTest.log('Waiting for two wasm scripts to be parsed.');
InspectorTest.log('Waiting for wasm script to be parsed.');
let wasm_script_ids = [];
while (wasm_script_ids.length < 2) {
while (wasm_script_ids.length < 1) {
let script_msg = await Protocol.Debugger.onceScriptParsed();
let url = script_msg.params.url;
if (url.startsWith('wasm://') && url.split('/').length == 5) {
if (url.startsWith('wasm://')) {
InspectorTest.log('Got wasm script!');
wasm_script_ids.push(script_msg.params.scriptId);
}
......
Tests how wasm scripts are reported
Check that each inspector gets two wasm scripts at module creation time.
Check that each inspector gets a wasm script at module creation time.
Session #1: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL:
Session #1: Script #1 parsed. URL: wasm://wasm/f608ae1e/f608ae1e-0. Source map URL:
Session #1: Script #2 parsed. URL: wasm://wasm/f608ae1e/f608ae1e-1. Source map URL:
Session #2: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL:
Session #2: Script #1 parsed. URL: wasm://wasm/f608ae1e/f608ae1e-0. Source map URL:
Session #2: Script #2 parsed. URL: wasm://wasm/f608ae1e/f608ae1e-1. Source map URL:
Session #1: Script #3 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf
Session #2: Script #3 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf
Session #1: Script #4 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc
Session #2: Script #4 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc
Session #1: Script #5 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc
Session #2: Script #5 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc
Session #1: Script #6 parsed. URL: wasm://wasm/f568e726. Source map URL: abc
Session #2: Script #6 parsed. URL: wasm://wasm/f568e726. Source map URL: abc
Session #1: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf
Session #2: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf
Session #1: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc
Session #2: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc
Session #1: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc
Session #2: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc
Session #1: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc
Session #2: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc
Session #1: Source for wasm://wasm/f608ae1e:
Session #1: Source for wasm://wasm/f608ae1e/f608ae1e-0:
func $nopFunction
nop
end
Session #1: Source for wasm://wasm/f608ae1e/f608ae1e-1:
func $main
block
i32.const 2
drop
end
end
Raw: 00 61 73 6d 01 00 00 00 01 07 02 60 00 00 60 00 00 03 03 02 00 01 07 08 01 04 6d 61 69 6e 00 01 0a 0e 02 03 00 01 0b 08 00 02 40 41 02 1a 0b 0b 00 1b 04 6e 61 6d 65 01 14 02 00 0b 6e 6f 70 46 75 6e 63 74 69 6f 6e 01 04 6d 61 69 6e
Imports: []
Exports: [main: function]
Session #2: Source for wasm://wasm/f608ae1e:
Session #2: Source for wasm://wasm/f608ae1e/f608ae1e-0:
func $nopFunction
nop
end
Session #2: Source for wasm://wasm/f608ae1e/f608ae1e-1:
func $main
block
i32.const 2
drop
end
end
Raw: 00 61 73 6d 01 00 00 00 01 07 02 60 00 00 60 00 00 03 03 02 00 01 07 08 01 04 6d 61 69 6e 00 01 0a 0e 02 03 00 01 0b 08 00 02 40 41 02 1a 0b 0b 00 1b 04 6e 61 6d 65 01 14 02 00 0b 6e 6f 70 46 75 6e 63 74 69 6f 6e 01 04 6d 61 69 6e
Imports: []
Exports: [main: function]
Session #1: Source for wasm://wasm/74f86b7e:
Raw: 00 61 73 6d 01 00 00 00 01 07 02 60 00 00 60 00 00 03 03 02 00 01 07 08 01 04 6d 61 69 6e 00 01 0a 0e 02 03 00 01 0b 08 00 02 40 41 02 1a 0b 0b 00 11 0b 2e 64 65 62 75 67 5f 69 6e 66 6f 01 02 03 04 05 00 1b 04 6e 61 6d 65 01 14 02 00 0b 6e 6f 70 46 75 6e 63 74 69 6f 6e 01 04 6d 61 69 6e
Imports: []
......
Tests how wasm scripts are reported with name
Check that the inspector gets four wasm scripts at module creation time.
Session #1: Script #0 parsed. URL: wasm://wasm/49a8663e.
Session #1: Script #1 parsed. URL: wasm://wasm/49a8663e/49a8663e-0.
Session #1: Script #2 parsed. URL: wasm://wasm/moduleName-aea4a206.
Session #1: Script #3 parsed. URL: wasm://wasm/moduleName-aea4a206/moduleName-aea4a206-0.
Session #1: Script #1 parsed. URL: wasm://wasm/moduleName-aea4a206.
Session #1: Source for wasm://wasm/49a8663e:
Session #1: Source for wasm://wasm/49a8663e/49a8663e-0:
func $nopFunction
nop
end
Session #1: Source for wasm://wasm/moduleName-aea4a206:
Session #1: Source for wasm://wasm/moduleName-aea4a206/moduleName-aea4a206-0:
func $nopFunction
nop
end
......@@ -38,7 +38,7 @@ function testFunction(bytes) {
contextGroup.addScript(testFunction.toString(), 0, 0, 'v8://test/testFunction');
InspectorTest.log(
'Check that each inspector gets two wasm scripts at module creation time.');
'Check that each inspector gets a wasm script at module creation time.');
// Sample .debug_info section.
// Content doesn't matter, as we don't try to parse it in V8,
......@@ -78,30 +78,6 @@ sessions[0].Protocol.Runtime
})
.then(() => InspectorTest.completeTest());
function decodeBase64(base64) {
const LOOKUP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const paddingLength = base64.match(/=*$/)[0].length;
const bytesLength = base64.length * 0.75 - paddingLength;
let bytes = new Uint8Array(bytesLength);
for (let i = 0, p = 0; i < base64.length; i += 4, p += 3) {
let bits = 0;
for (let j = 0; j < 4; j++) {
bits <<= 6;
const c = base64[i + j];
if (c !== '=') bits |= LOOKUP.indexOf(c);
}
for (let j = p + 2; j >= p; j--) {
if (j < bytesLength) bytes[j] = bits;
bits >>= 8;
}
}
return bytes;
}
function trackScripts(debuggerParams) {
let {id: sessionId, Protocol} = contextGroup.connect();
let scripts = [];
......@@ -111,11 +87,14 @@ function trackScripts(debuggerParams) {
async function loadScript({url, scriptId, sourceMapURL}) {
InspectorTest.log(`Session #${sessionId}: Script #${scripts.length} parsed. URL: ${url}. Source map URL: ${sourceMapURL}`);
let scriptSource;
if (sourceMapURL) {
let {result: {bytecode}} = await Protocol.Debugger.getWasmBytecode({scriptId});
let {result: {scriptSource, bytecode}} = await Protocol.Debugger.getScriptSource({scriptId});
if (bytecode) {
if (scriptSource) {
InspectorTest.log('Unexpected scriptSource with bytecode: ');
InspectorTest.log(scriptSource);
}
// Binary value is represented as base64 in JSON, decode it.
bytecode = decodeBase64(bytecode);
bytecode = InspectorTest.decodeBase64(bytecode);
// Check that it can be parsed back to a WebAssembly module.
let module = new WebAssembly.Module(bytecode);
scriptSource = `
......@@ -123,15 +102,13 @@ Raw: ${Array.from(bytecode, b => ('0' + b.toString(16)).slice(-2)).join(' ')}
Imports: [${WebAssembly.Module.imports(module).map(i => `${i.name}: ${i.kind} from "${i.module}"`).join(', ')}]
Exports: [${WebAssembly.Module.exports(module).map(e => `${e.name}: ${e.kind}`).join(', ')}]
`.trim();
} else {
({result: {scriptSource}} = await Protocol.Debugger.getScriptSource({scriptId}));
}
InspectorTest.log(`Session #${sessionId}: Source for ${url}:`);
InspectorTest.log(scriptSource);
}
function handleScriptParsed({params}) {
if (params.url.startsWith("wasm://")) {
if (params.url.startsWith('wasm://')) {
scripts.push(loadScript(params));
}
}
......
Tests stepping through wasm scripts.
Instantiating.
Waiting for two wasm scripts (ignoring first non-wasm script).
Source of script wasm://wasm/18214bfe/18214bfe-0:
1: func $wasm_A
2: nop
3: nop
4: end
Source of script wasm://wasm/18214bfe/18214bfe-1:
1: func $wasm_B (param i32)
2: loop
3: local.get 0
4: if
5: local.get 0
6: i32.const 1
7: i32.sub
8: local.set 0
9: call 0
10: br 1
11: end
12: end
13: end
Setting breakpoint on line 8 on script wasm://wasm/18214bfe/18214bfe-1
Setting breakpoint on line 7 on script wasm://wasm/18214bfe/18214bfe-1
Setting breakpoint on line 6 on script wasm://wasm/18214bfe/18214bfe-1
Setting breakpoint on line 5 on script wasm://wasm/18214bfe/18214bfe-1
Setting breakpoint on line 3 on script wasm://wasm/18214bfe/18214bfe-1
Setting breakpoint on line 4 on script wasm://wasm/18214bfe/18214bfe-1
Waiting for wasm script (ignoring first non-wasm script).
Setting breakpoint at offset 54 on script wasm://wasm/18214bfe
Setting breakpoint at offset 53 on script wasm://wasm/18214bfe
Setting breakpoint at offset 51 on script wasm://wasm/18214bfe
Setting breakpoint at offset 49 on script wasm://wasm/18214bfe
Setting breakpoint at offset 45 on script wasm://wasm/18214bfe
Setting breakpoint at offset 47 on script wasm://wasm/18214bfe
Calling main(4)
Breaking on line 3
Breaking on line 4
Breaking on line 5
Breaking on line 6
Breaking on line 7
Breaking on line 8
Breaking on line 3
Breaking on line 4
Breaking on line 5
Breaking on line 6
Breaking on line 7
Breaking on line 8
Breaking on line 3
Breaking on line 4
Breaking on line 5
Breaking on line 6
Breaking on line 7
Breaking on line 8
Breaking on line 3
Breaking on line 4
Breaking on line 5
Breaking on line 6
Breaking on line 7
Breaking on line 8
Breaking on line 3
Breaking on byte offset 45
Breaking on byte offset 47
Breaking on byte offset 49
Breaking on byte offset 51
Breaking on byte offset 53
Breaking on byte offset 54
Breaking on byte offset 45
Breaking on byte offset 47
Breaking on byte offset 49
Breaking on byte offset 51
Breaking on byte offset 53
Breaking on byte offset 54
Breaking on byte offset 45
Breaking on byte offset 47
Breaking on byte offset 49
Breaking on byte offset 51
Breaking on byte offset 53
Breaking on byte offset 54
Breaking on byte offset 45
Breaking on byte offset 47
Breaking on byte offset 49
Breaking on byte offset 51
Breaking on byte offset 53
Breaking on byte offset 54
Breaking on byte offset 45
Breaking on byte offset 47
exports.main returned!
Finished!
......@@ -13,7 +13,7 @@ const func_a_idx =
builder.addFunction('wasm_A', kSig_v_v).addBody([kExprNop, kExprNop]).index;
// wasm_B calls wasm_A <param0> times.
builder.addFunction('wasm_B', kSig_v_i)
const func_b = builder.addFunction('wasm_B', kSig_v_i)
.addBody([
// clang-format off
kExprLoop, kWasmStmt, // while
......@@ -51,18 +51,21 @@ const evalWithUrl = (code, url) =>
.evaluate({'expression': code + '\n//# sourceURL=v8://test/' + url})
.then(getResult);
function setBreakpoint(line, script) {
function setBreakpoint(offset, script) {
InspectorTest.log(
'Setting breakpoint on line ' + line + ' on script ' + script.url);
'Setting breakpoint at offset ' + offset + ' on script ' + script.url);
return Protocol.Debugger
.setBreakpoint(
{'location': {'scriptId': script.scriptId, 'lineNumber': line}})
{'location': {'scriptId': script.scriptId, 'lineNumber': 0, 'columnNumber': offset}})
.then(getResult);
}
Protocol.Debugger.onPaused(pause_msg => {
let loc = pause_msg.params.callFrames[0].location;
InspectorTest.log('Breaking on line ' + loc.lineNumber);
if (loc.lineNumber != 0) {
InspectorTest.log('Unexpected line number: ' + loc.lineNumber);
}
InspectorTest.log('Breaking on byte offset ' + loc.columnNumber);
Protocol.Debugger.resume();
});
......@@ -74,20 +77,11 @@ Protocol.Debugger.onPaused(pause_msg => {
JSON.stringify(module_bytes) + ');';
evalWithUrl(instantiate_code, 'instantiate');
InspectorTest.log(
'Waiting for two wasm scripts (ignoring first non-wasm script).');
'Waiting for wasm script (ignoring first non-wasm script).');
// Ignore javascript and full module wasm script, get scripts for functions.
const [, , {params: wasm_script_a}, {params: wasm_script_b}] =
await Protocol.Debugger.onceScriptParsed(4);
for (script of [wasm_script_a, wasm_script_b]) {
InspectorTest.log('Source of script ' + script.url + ':');
let src_msg =
await Protocol.Debugger.getScriptSource({scriptId: script.scriptId});
let lines = getResult(src_msg).scriptSource.replace(/\s+$/, '').split('\n');
InspectorTest.log(
lines.map((line, nr) => (nr + 1) + ': ' + line).join('\n') + '\n');
}
for (line of [8, 7, 6, 5, 3, 4]) {
await setBreakpoint(line, wasm_script_b);
const [, {params: wasm_script}] = await Protocol.Debugger.onceScriptParsed(2);
for (offset of [11, 10, 8, 6, 2, 4]) {
await setBreakpoint(func_b.body_offset + offset, wasm_script);
}
InspectorTest.log('Calling main(4)');
await evalWithUrl('instance.exports.main(4)', 'runWasm');
......
Tests how wasm scrips report the source
Check that inspector gets disassembled wasm code
Check that inspector gets wasm bytecode
Paused on debugger!
Number of frames: 5
[0] debugger;
[1] call 0
[2] call_indirect 2
[1] Wasm offset 72: 0x10
[2] Wasm offset 81: 0x11
[3] instance.exports.main();
[4] testFunction(module_bytes)
Finished.
......@@ -51,30 +51,37 @@ contextGroup.addScript('var module_bytes = ' + JSON.stringify(module_bytes));
Protocol.Debugger.enable();
Protocol.Debugger.onPaused(handleDebuggerPaused);
InspectorTest.log('Check that inspector gets disassembled wasm code');
InspectorTest.log('Check that inspector gets wasm bytecode');
Protocol.Runtime.evaluate({'expression': 'testFunction(module_bytes)'});
function handleDebuggerPaused(message) {
async function handleDebuggerPaused(message) {
InspectorTest.log('Paused on debugger!');
var frames = message.params.callFrames;
InspectorTest.log('Number of frames: ' + frames.length);
function dumpSourceLine(frameId, sourceMessage) {
async function dumpSourceLine(frameId, sourceMessage) {
if (sourceMessage.error) InspectorTest.logObject(sourceMessage);
var text = sourceMessage.result.scriptSource;
var lineNr = frames[frameId].location.lineNumber;
var line = text.split('\n')[lineNr];
InspectorTest.log('[' + frameId + '] ' + line);
if (text) {
var line = text.split('\n')[lineNr];
InspectorTest.log('[' + frameId + '] ' + line);
} else {
if (lineNr != 0) {
InspectorTest.log('Unexpected line number in wasm: ' + lineNr);
}
let byteOffset = frames[frameId].location.columnNumber;
let data = InspectorTest.decodeBase64(sourceMessage.result.bytecode);
// Print a byte, which can be compared to the expected wasm opcode.
InspectorTest.log('[' + frameId + '] Wasm offset ' + byteOffset
+ ': 0x' + data[byteOffset].toString(16));
}
}
function next(frameId) {
if (frameId == frames.length) return Promise.resolve();
return Protocol.Debugger
.getScriptSource({scriptId: frames[frameId].location.scriptId})
.then(dumpSourceLine.bind(null, frameId))
.then(() => next(frameId + 1));
}
function finished() {
InspectorTest.log('Finished.');
InspectorTest.completeTest();
for (let frameId = 0; frameId < frames.length; frameId++) {
result = await Protocol.Debugger
.getScriptSource({scriptId: frames[frameId].location.scriptId});
await dumpSourceLine(frameId, result);
}
next(0).then(finished);
InspectorTest.log('Finished.');
InspectorTest.completeTest();
}
......@@ -3,8 +3,8 @@ Running testFunction with generated wasm bytes...
Paused on 'debugger;'
Number of frames: 5
- [0] {"functionName":"call_debugger","function_lineNumber":1,"function_columnNumber":24,"lineNumber":2,"columnNumber":4}
- [1] {"functionName":"call_func","lineNumber":1,"columnNumber":2}
- [2] {"functionName":"main","lineNumber":2,"columnNumber":4}
- [1] {"functionName":"call_func","lineNumber":0,"columnNumber":55}
- [2] {"functionName":"main","lineNumber":0,"columnNumber":62}
- [3] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":14,"columnNumber":19}
- [4] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
Getting v8-generated stack trace...
......
Tests stepping through wasm scripts by byte offsets
Setting up global instance variable.
Got wasm script: wasm://wasm/7dfc8356
Requesting source for wasm://wasm/7dfc8356...
Source retrieved without error: true
Setting breakpoint on offset 59 (should be propagated to 60, the offset of the call), url wasm://wasm/7dfc8356
{
columnNumber : 60
lineNumber : 0
scriptId : <scriptId>
}
Paused at wasm://wasm/7dfc8356/7dfc8356-1:9:6
at wasm_B (9:6):
Paused at wasm://wasm/7dfc8356:0:60
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -20,14 +18,14 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-0:1:2
at wasm_A (1:2):
Paused at wasm://wasm/7dfc8356:0:39
at wasm_A (0:39):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1024}
stack: {}
at wasm_B (9:6):
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -37,14 +35,14 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOver called
Paused at wasm://wasm/7dfc8356/7dfc8356-0:2:2
at wasm_A (2:2):
Paused at wasm://wasm/7dfc8356:0:40
at wasm_A (0:40):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1024}
stack: {}
at wasm_B (9:6):
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -54,8 +52,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOut called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:10:6
at wasm_B (10:6):
Paused at wasm://wasm/7dfc8356:0:62
at wasm_B (0:62):
- scope (global):
-- skipped
- scope (local):
......@@ -65,8 +63,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOut called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:9:6
at wasm_B (9:6):
Paused at wasm://wasm/7dfc8356:0:60
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -76,8 +74,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOver called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:10:6
at wasm_B (10:6):
Paused at wasm://wasm/7dfc8356:0:62
at wasm_B (0:62):
- scope (global):
-- skipped
- scope (local):
......@@ -87,8 +85,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:1:2
at wasm_B (1:2):
Paused at wasm://wasm/7dfc8356:0:44
at wasm_B (0:44):
- scope (global):
-- skipped
- scope (local):
......@@ -98,8 +96,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.resume called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:9:6
at wasm_B (9:6):
Paused at wasm://wasm/7dfc8356:0:60
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -109,14 +107,14 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-0:1:2
at wasm_A (1:2):
Paused at wasm://wasm/7dfc8356:0:39
at wasm_A (0:39):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1024}
stack: {}
at wasm_B (9:6):
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -126,8 +124,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOut called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:10:6
at wasm_B (10:6):
Paused at wasm://wasm/7dfc8356:0:62
at wasm_B (0:62):
- scope (global):
-- skipped
- scope (local):
......@@ -137,8 +135,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:1:2
at wasm_B (1:2):
Paused at wasm://wasm/7dfc8356:0:44
at wasm_B (0:44):
- scope (global):
-- skipped
- scope (local):
......@@ -148,8 +146,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:2:4
at wasm_B (2:4):
Paused at wasm://wasm/7dfc8356:0:46
at wasm_B (0:46):
- scope (global):
-- skipped
- scope (local):
......@@ -159,8 +157,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:3:4
at wasm_B (3:4):
Paused at wasm://wasm/7dfc8356:0:48
at wasm_B (0:48):
- scope (global):
-- skipped
- scope (local):
......@@ -170,8 +168,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:4:6
at wasm_B (4:6):
Paused at wasm://wasm/7dfc8356:0:50
at wasm_B (0:50):
- scope (global):
-- skipped
- scope (local):
......@@ -181,8 +179,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:5:6
at wasm_B (5:6):
Paused at wasm://wasm/7dfc8356:0:52
at wasm_B (0:52):
- scope (global):
-- skipped
- scope (local):
......@@ -192,8 +190,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:6:6
at wasm_B (6:6):
Paused at wasm://wasm/7dfc8356:0:54
at wasm_B (0:54):
- scope (global):
-- skipped
- scope (local):
......@@ -203,8 +201,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:7:6
at wasm_B (7:6):
Paused at wasm://wasm/7dfc8356:0:55
at wasm_B (0:55):
- scope (global):
-- skipped
- scope (local):
......@@ -214,8 +212,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:8:6
at wasm_B (8:6):
Paused at wasm://wasm/7dfc8356:0:57
at wasm_B (0:57):
- scope (global):
-- skipped
- scope (local):
......@@ -225,8 +223,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:9:6
at wasm_B (9:6):
Paused at wasm://wasm/7dfc8356:0:60
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -236,14 +234,14 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-0:1:2
at wasm_A (1:2):
Paused at wasm://wasm/7dfc8356:0:39
at wasm_A (0:39):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1024}
stack: {}
at wasm_B (9:6):
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -253,14 +251,14 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-0:2:2
at wasm_A (2:2):
Paused at wasm://wasm/7dfc8356:0:40
at wasm_A (0:40):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1024}
stack: {}
at wasm_B (9:6):
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -270,14 +268,14 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-0:3:0
at wasm_A (3:0):
Paused at wasm://wasm/7dfc8356:0:41
at wasm_A (0:41):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1024}
stack: {}
at wasm_B (9:6):
at wasm_B (0:60):
- scope (global):
-- skipped
- scope (local):
......@@ -287,8 +285,8 @@ at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/7dfc8356/7dfc8356-1:10:6
at wasm_B (10:6):
Paused at wasm://wasm/7dfc8356:0:62
at wasm_B (0:62):
- scope (global):
-- skipped
- scope (local):
......
......@@ -57,14 +57,9 @@ function instantiate(bytes) {
expression: `var instance;` +
`(${instantiate.toString()})(${JSON.stringify(module_bytes)})`
});
const [, {params: wasmScript}, ,] = await Protocol.Debugger.onceScriptParsed(4);
const [, {params: wasmScript}] = await Protocol.Debugger.onceScriptParsed(2);
InspectorTest.log('Got wasm script: ' + wasmScript.url);
InspectorTest.log('Requesting source for ' + wasmScript.url + '...');
const msg =
await Protocol.Debugger.getScriptSource({scriptId: wasmScript.scriptId});
InspectorTest.log(`Source retrieved without error: ${!msg.error}`);
// TODO(leese): Add check that source text is empty but bytecode is present.
// Set the breakpoint on a non-breakable position. This should resolve to the
// next instruction.
......
Tests stepping through wasm scripts
Installing code an global variable.
Calling instantiate function.
Waiting for two wasm scripts to be parsed.
Ignoring script with url v8://test/callInstantiate
Ignoring script with url wasm://wasm/18214bfe
Got wasm script: wasm://wasm/18214bfe/18214bfe-0
Requesting source for wasm://wasm/18214bfe/18214bfe-0...
Got wasm script: wasm://wasm/18214bfe/18214bfe-1
Requesting source for wasm://wasm/18214bfe/18214bfe-1...
func $wasm_A
nop
nop
end
func $wasm_B (param i32)
loop
local.get 0
if
local.get 0
i32.const 1
i32.sub
local.set 0
call 0
br 1
end
end
end
Setting breakpoint on line 7 (on the setlocal before the call), url wasm://wasm/18214bfe/18214bfe-1
{
columnNumber : 6
lineNumber : 7
scriptId : <scriptId>
}
Paused at wasm://wasm/18214bfe/18214bfe-1:7:6: >local.set 0
at wasm_B (7:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":4} (Object)
stack: {"0":3} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:8:6: >call 0
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":3} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-0:1:2: >nop
at wasm_A (1:2):
- scope (global):
-- skipped
- scope (local):
stack: {} (Object)
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":3} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOver called
Paused at wasm://wasm/18214bfe/18214bfe-0:2:2: >nop
at wasm_A (2:2):
- scope (global):
-- skipped
- scope (local):
stack: {} (Object)
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":3} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOut called
Paused at wasm://wasm/18214bfe/18214bfe-1:9:6: >br 1
at wasm_B (9:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":3} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOut called
Paused at wasm://wasm/18214bfe/18214bfe-1:7:6: >local.set 0
at wasm_B (7:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":3} (Object)
stack: {"0":2} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOver called
Paused at wasm://wasm/18214bfe/18214bfe-1:8:6: >call 0
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":2} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOver called
Paused at wasm://wasm/18214bfe/18214bfe-1:9:6: >br 1
at wasm_B (9:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":2} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.resume called
Paused at wasm://wasm/18214bfe/18214bfe-1:7:6: >local.set 0
at wasm_B (7:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":2} (Object)
stack: {"0":1} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:8:6: >call 0
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-0:1:2: >nop
at wasm_A (1:2):
- scope (global):
-- skipped
- scope (local):
stack: {} (Object)
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepOut called
Paused at wasm://wasm/18214bfe/18214bfe-1:9:6: >br 1
at wasm_B (9:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:1:2: >loop
at wasm_B (1:2):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:2:4: >local.get 0
at wasm_B (2:4):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:3:4: >if
at wasm_B (3:4):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {"0":1} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:4:6: >local.get 0
at wasm_B (4:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:5:6: >i32.const 1
at wasm_B (5:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {"0":1} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:6:6: >i32.sub
at wasm_B (6:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {"0":1,"1":1} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:7:6: >local.set 0
at wasm_B (7:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":1} (Object)
stack: {"0":0} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:8:6: >call 0
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":0} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-0:1:2: >nop
at wasm_A (1:2):
- scope (global):
-- skipped
- scope (local):
stack: {} (Object)
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":0} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-0:2:2: >nop
at wasm_A (2:2):
- scope (global):
-- skipped
- scope (local):
stack: {} (Object)
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":0} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-0:3:0: >end
at wasm_A (3:0):
- scope (global):
-- skipped
- scope (local):
stack: {} (Object)
at wasm_B (8:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":0} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.stepInto called
Paused at wasm://wasm/18214bfe/18214bfe-1:9:6: >br 1
at wasm_B (9:6):
- scope (global):
-- skipped
- scope (local):
locals: {"arg#0":0} (Object)
stack: {} (Object)
at (anonymous) (0:17):
- scope (global):
-- skipped
Debugger.resume called
exports.main returned!
Finished!
......@@ -3,12 +3,11 @@ Installing code and global variable.
Calling instantiate function.
Waiting for wasm scripts to be parsed.
Ignoring script with url v8://test/callInstantiate
Ignoring script with url wasm://wasm/fa045c1e
Got wasm script: wasm://wasm/fa045c1e/fa045c1e-0
Got wasm script: wasm://wasm/fa045c1e
Setting breakpoint on line 3 of wasm function
{
columnNumber : 2
lineNumber : 3
columnNumber : 37
lineNumber : 0
scriptId : <scriptId>
}
paused
......@@ -24,16 +23,10 @@ paused
Debugger.stepInto
paused
func $wasm_A (param i32) (result i32)
#local.get 0
i32.const 1
Script wasm://wasm/fa045c1e byte offset 35: Wasm opcode 0x20
Debugger.resume
paused
i32.const 1
#i32.sub
end
Script wasm://wasm/fa045c1e byte offset 37: Wasm opcode 0x41
Debugger.resume
exports.main returned!
Finished!
......@@ -10,7 +10,7 @@ utils.load('test/mjsunit/wasm/wasm-module-builder.js');
let builder = new WasmModuleBuilder();
// wasm_A
builder.addFunction('wasm_A', kSig_i_i)
let func = builder.addFunction('wasm_A', kSig_i_i)
.addBody([
// clang-format off
kExprLocalGet, 0, // Line 1: get input
......@@ -72,7 +72,7 @@ function test() {
InspectorTest.log(
'Setting breakpoint on line 3 of wasm function');
let msg = await Protocol.Debugger.setBreakpoint(
{'location': {'scriptId': scriptId, 'lineNumber': 3}});
{'location': {'scriptId': scriptId, 'lineNumber': 0, 'columnNumber': 2 + func.body_offset}});
printFailure(msg);
InspectorTest.logMessage(msg.result.actualLocation);
await Protocol.Runtime.evaluate({ expression: 'test()' });
......@@ -93,7 +93,7 @@ async function waitForWasmScript() {
while (true) {
let msg = await Protocol.Debugger.onceScriptParsed();
let url = msg.params.url;
if (!url.startsWith('wasm://') || url.split('/').length != 5) {
if (!url.startsWith('wasm://')) {
InspectorTest.log('Ignoring script with url ' + url);
continue;
}
......
......@@ -3,12 +3,11 @@ Installing code and global variable.
Calling instantiate function.
Waiting for wasm scripts to be parsed.
Ignoring script with url v8://test/callInstantiate
Ignoring script with url wasm://wasm/485e942e
Got wasm script: wasm://wasm/485e942e/485e942e-0
Setting breakpoint on line 2 of wasm function
Got wasm script: wasm://wasm/485e942e
Setting breakpoint at start of wasm function
{
columnNumber : 0
lineNumber : 2
columnNumber : 33
lineNumber : 0
scriptId : <scriptId>
}
Start run 1
......@@ -19,10 +18,7 @@ function test() {
Debugger.resume
paused
nop
#end
Script wasm://wasm/485e942e byte offset 33: Wasm opcode 0x1
Debugger.stepOut
paused
instance.exports.main();
......@@ -41,16 +37,10 @@ function test() {
Debugger.resume
paused
nop
#end
Script wasm://wasm/485e942e byte offset 33: Wasm opcode 0x1
Debugger.stepOver
paused
instance.exports.main();
var x = #1;
x++;
Script wasm://wasm/485e942e byte offset 34: Wasm opcode 0xb
Debugger.resume
exports.main returned!
Finished run 2!
......@@ -63,16 +53,10 @@ function test() {
Debugger.resume
paused
nop
#end
Script wasm://wasm/485e942e byte offset 33: Wasm opcode 0x1
Debugger.stepInto
paused
instance.exports.main();
var x = #1;
x++;
Script wasm://wasm/485e942e byte offset 34: Wasm opcode 0xb
Debugger.resume
exports.main returned!
Finished run 3!
......@@ -10,7 +10,7 @@ utils.load('test/mjsunit/wasm/wasm-module-builder.js');
let builder = new WasmModuleBuilder();
// wasm_A
builder.addFunction('wasm_A', kSig_v_v)
let func = builder.addFunction('wasm_A', kSig_v_v)
.addBody([
// clang-format off
kExprNop, // Line 1
......@@ -85,9 +85,9 @@ function test() {
'instantiate(' + JSON.stringify(module_bytes) + ')', 'callInstantiate');
const scriptId = await waitForWasmScript();
InspectorTest.log(
'Setting breakpoint on line 2 of wasm function');
'Setting breakpoint at start of wasm function');
let msg = await Protocol.Debugger.setBreakpoint(
{'location': {'scriptId': scriptId, 'lineNumber': 2}});
{'location': {'scriptId': scriptId, 'lineNumber': 0, 'columnNumber': func.body_offset}});
printFailure(msg);
InspectorTest.logMessage(msg.result.actualLocation);
......@@ -112,7 +112,7 @@ async function waitForWasmScript() {
while (true) {
let msg = await Protocol.Debugger.onceScriptParsed();
let url = msg.params.url;
if (!url.startsWith('wasm://') || url.split('/').length != 5) {
if (!url.startsWith('wasm://')) {
InspectorTest.log('Ignoring script with url ' + url);
continue;
}
......
// Copyright 2017 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.
let {session, contextGroup, Protocol} = InspectorTest.start('Tests stepping through wasm scripts');
utils.load('test/mjsunit/wasm/wasm-module-builder.js');
let builder = new WasmModuleBuilder();
let func_a_idx =
builder.addFunction('wasm_A', kSig_v_v).addBody([kExprNop, kExprNop]).index;
// wasm_B calls wasm_A <param0> times.
builder.addFunction('wasm_B', kSig_v_i)
.addBody([
// clang-format off
kExprLoop, kWasmStmt, // while
kExprLocalGet, 0, // -
kExprIf, kWasmStmt, // if <param0> != 0
kExprLocalGet, 0, // -
kExprI32Const, 1, // -
kExprI32Sub, // -
kExprLocalSet, 0, // decrease <param0>
kExprCallFunction, func_a_idx, // -
kExprBr, 1, // continue
kExprEnd, // -
kExprEnd, // break
// clang-format on
])
.exportAs('main');
let module_bytes = builder.toArray();
function instantiate(bytes) {
let buffer = new ArrayBuffer(bytes.length);
let view = new Uint8Array(buffer);
for (let i = 0; i < bytes.length; ++i) {
view[i] = bytes[i] | 0;
}
let module = new WebAssembly.Module(buffer);
// Set global variable.
instance = new WebAssembly.Instance(module);
}
let evalWithUrl = (code, url) => Protocol.Runtime.evaluate(
{'expression': code + '\n//# sourceURL=v8://test/' + url});
Protocol.Debugger.onPaused(handlePaused);
let wasm_B_scriptId;
let step_actions = [
'stepInto', // == stepOver, to call instruction
'stepInto', // into call to wasm_A
'stepOver', // over first nop
'stepOut', // out of wasm_A
'stepOut', // out of wasm_B, stop on breakpoint again
'stepOver', // to call
'stepOver', // over call
'resume', // to next breakpoint (third iteration)
'stepInto', // to call
'stepInto', // into wasm_A
'stepOut', // out to wasm_B
// now step 9 times, until we are in wasm_A again.
'stepInto', 'stepInto', 'stepInto', 'stepInto', 'stepInto', 'stepInto',
'stepInto', 'stepInto', 'stepInto',
// 3 more times, back to wasm_B.
'stepInto', 'stepInto', 'stepInto',
// then just resume.
'resume'
];
for (let action of step_actions) {
InspectorTest.logProtocolCommandCalls('Debugger.' + action)
}
let sources = {};
let urls = {};
let afterTwoSourcesCallback;
(async function Test() {
await Protocol.Debugger.enable();
InspectorTest.log('Installing code an global variable.');
await evalWithUrl('var instance;\n' + instantiate.toString(), 'setup');
InspectorTest.log('Calling instantiate function.');
evalWithUrl(
'instantiate(' + JSON.stringify(module_bytes) + ')', 'callInstantiate');
await waitForTwoWasmScripts();
InspectorTest.log(
'Setting breakpoint on line 7 (on the setlocal before the call), url ' +
urls[wasm_B_scriptId]);
let msg = await Protocol.Debugger.setBreakpoint(
{'location': {'scriptId': wasm_B_scriptId, 'lineNumber': 7}});
printFailure(msg);
InspectorTest.logMessage(msg.result.actualLocation);
await evalWithUrl('instance.exports.main(4)', 'runWasm');
InspectorTest.log('exports.main returned!');
InspectorTest.log('Finished!');
InspectorTest.completeTest();
})();
function printFailure(message) {
if (!message.result) {
InspectorTest.logMessage(message);
}
return message;
}
async function waitForTwoWasmScripts() {
let num = 0;
InspectorTest.log('Waiting for two wasm scripts to be parsed.');
let source_promises = [];
async function getWasmSource(scriptId) {
let msg = await Protocol.Debugger.getScriptSource({scriptId: scriptId});
printFailure(msg);
InspectorTest.log(msg.result.scriptSource);
sources[scriptId] = msg.result.scriptSource;
}
while (num < 2) {
let msg = await Protocol.Debugger.onceScriptParsed();
let url = msg.params.url;
if (!url.startsWith('wasm://') || url.split('/').length != 5) {
InspectorTest.log('Ignoring script with url ' + url);
continue;
}
num += 1;
let scriptId = msg.params.scriptId;
urls[scriptId] = url;
InspectorTest.log('Got wasm script: ' + url);
if (url.substr(-2) == '-1') wasm_B_scriptId = scriptId;
InspectorTest.log('Requesting source for ' + url + '...');
source_promises.push(getWasmSource(scriptId));
}
await Promise.all(source_promises);
}
function printPauseLocation(scriptId, lineNr, columnNr) {
let lines = sources[scriptId].split('\n');
let line = '<illegal line number>';
if (lineNr < lines.length) {
line = lines[lineNr];
if (columnNr < line.length) {
line = line.substr(0, columnNr) + '>' + line.substr(columnNr);
}
}
InspectorTest.log(
'Paused at ' + urls[scriptId] + ':' + lineNr + ':' + columnNr + ': ' +
line);
}
async function getValueString(value) {
if (value.type == 'object') {
let msg = await Protocol.Runtime.callFunctionOn({
objectId: value.objectId,
functionDeclaration: 'function () { return JSON.stringify(this); }'
});
printFailure(msg);
return msg.result.result.value + ' (' + value.description + ')';
}
return value.value + ' (' + value.type + ')';
}
async function dumpProperties(message) {
printFailure(message);
for (let value of message.result.result) {
let value_str = await getValueString(value.value);
InspectorTest.log(' ' + value.name + ': ' + value_str);
}
}
async function dumpScopeChainsOnPause(message) {
for (let frame of message.params.callFrames) {
let functionName = frame.functionName || '(anonymous)';
let lineNumber = frame.location ? frame.location.lineNumber : frame.lineNumber;
let columnNumber = frame.location ? frame.location.columnNumber : frame.columnNumber;
InspectorTest.log(`at ${functionName} (${lineNumber}:${columnNumber}):`);
for (let scope of frame.scopeChain) {
InspectorTest.logObject(' - scope (' + scope.type + '):');
if (scope.type == 'global') {
InspectorTest.logObject(' -- skipped');
} else {
let properties = await Protocol.Runtime.getProperties(
{'objectId': scope.object.objectId});
await dumpProperties(properties);
}
}
}
}
async function handlePaused(msg) {
let loc = msg.params.callFrames[0].location;
printPauseLocation(loc.scriptId, loc.lineNumber, loc.columnNumber);
await dumpScopeChainsOnPause(msg);
let action = step_actions.shift() || 'resume';
await Protocol.Debugger[action]();
}
......@@ -105,6 +105,30 @@ InspectorTest.logObject = function(object, title) {
InspectorTest.log(lines.join("\n"));
}
InspectorTest.decodeBase64 = function(base64) {
const LOOKUP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const paddingLength = base64.match(/=*$/)[0].length;
const bytesLength = base64.length * 0.75 - paddingLength;
let bytes = new Uint8Array(bytesLength);
for (let i = 0, p = 0; i < base64.length; i += 4, p += 3) {
let bits = 0;
for (let j = 0; j < 4; j++) {
bits <<= 6;
const c = base64[i + j];
if (c !== '=') bits |= LOOKUP.indexOf(c);
}
for (let j = p + 2; j >= p; j--) {
if (j < bytesLength) bytes[j] = bits;
bits >>= 8;
}
}
return bytes;
}
InspectorTest.ContextGroup = class {
constructor() {
this.id = utils.createContextGroup();
......@@ -239,21 +263,32 @@ InspectorTest.Session = class {
}
}
logSourceLocation(location, forceSourceRequest) {
async getScriptWithSource(scriptId, forceSourceRequest) {
var script = this._scriptMap.get(scriptId);
if (forceSourceRequest || !(script.scriptSource || script.bytecode)) {
var message = await this.Protocol.Debugger.getScriptSource({ scriptId });
script.scriptSource = message.result.scriptSource;
if (message.result.bytecode) {
script.bytecode = InspectorTest.decodeBase64(message.result.bytecode);
}
}
return script;
}
async logSourceLocation(location, forceSourceRequest) {
var scriptId = location.scriptId;
if (!this._scriptMap || !this._scriptMap.has(scriptId)) {
InspectorTest.log("setupScriptMap should be called before Protocol.Debugger.enable.");
InspectorTest.completeTest();
}
var script = this._scriptMap.get(scriptId);
if (!script.scriptSource || forceSourceRequest) {
return this.Protocol.Debugger.getScriptSource({ scriptId })
.then(message => script.scriptSource = message.result.scriptSource)
.then(dumpSourceWithLocation);
}
return Promise.resolve().then(dumpSourceWithLocation);
var script = await this.getScriptWithSource(scriptId, forceSourceRequest);
function dumpSourceWithLocation() {
if (script.bytecode) {
if (location.lineNumber != 0) {
InspectorTest.log('Unexpected wasm line number: ' + location.lineNumber);
}
InspectorTest.log(`Script ${script.url} byte offset ${location.columnNumber}: Wasm opcode 0x${script.bytecode[location.columnNumber].toString(16)}`);
} else {
var lines = script.scriptSource.split('\n');
var line = lines[location.lineNumber];
line = line.slice(0, location.columnNumber) + '#' + (line.slice(location.columnNumber) || '');
......@@ -272,11 +307,7 @@ InspectorTest.Session = class {
async logBreakLocations(inputLocations) {
let locations = inputLocations.slice();
let scriptId = locations[0].scriptId;
let script = this._scriptMap.get(scriptId);
if (!script.scriptSource) {
let message = await this.Protocol.Debugger.getScriptSource({scriptId});
script.scriptSource = message.result.scriptSource;
}
let script = await this.getScriptWithSource(scriptId);
let lines = script.scriptSource.split('\n');
locations = locations.sort((loc1, loc2) => {
if (loc2.lineNumber !== loc1.lineNumber) return loc2.lineNumber - loc1.lineNumber;
......
......@@ -631,6 +631,7 @@ class WasmFunctionBuilder {
this.body = [];
this.locals = [];
this.local_names = [];
this.body_offset = undefined; // Not valid until module is serialized.
}
numLocalNames() {
......@@ -1243,6 +1244,7 @@ class WasmModuleBuilder {
if (wasm.functions.length > 0) {
// emit function bodies
if (debug) print("emitting code @ " + binary.length);
let section_length = 0;
binary.emit_section(kCodeSectionCode, section => {
section.emit_u32v(wasm.functions.length);
let header = new Binary;
......@@ -1285,9 +1287,15 @@ class WasmModuleBuilder {
section.emit_u32v(header.length + func.body.length);
section.emit_bytes(header.trunc_buffer());
// Set to section offset for now, will update.
func.body_offset = section.length;
section.emit_bytes(func.body);
}
section_length = section.length;
});
for (let func of wasm.functions) {
func.body_offset += binary.length - section_length;
}
}
// Add data segments.
......
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