Commit cee2946f authored by Stephan Herhut's avatar Stephan Herhut Committed by Commit Bot

Lazily generate disassembly for WASM functions

Instead of computing the disassmebly and offset tables eagerly on
registering a WASM function with a debugger agent, only generate
it when the source or offset tables are actually required. This is
implemented using a lazy, memoizing supplier that is shared
between the debugger agent and wasm translator.

Bug: chromium:794941
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I1a2f7dd71ab65c80f91ddee4f7babbdf33d2e74b
Reviewed-on: https://chromium-review.googlesource.com/918641
Commit-Queue: Stephan Herhut <herhut@chromium.org>
Reviewed-by: 's avatarDmitry Gozman <dgozman@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51762}
parent db5affec
......@@ -69,6 +69,7 @@
#include "src/snapshot/natives.h"
#include "src/snapshot/snapshot.h"
#include "src/startup-data-util.h"
#include "src/string-hasher.h"
#include "src/tracing/trace-event.h"
#include "src/trap-handler/trap-handler.h"
#include "src/unicode-cache-inl.h"
......@@ -9467,6 +9468,25 @@ std::pair<int, int> debug::WasmScript::GetFunctionRange(
static_cast<int>(func.code.end_offset()));
}
uint32_t debug::WasmScript::GetFunctionHash(int function_index) {
i::DisallowHeapAllocation no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
i::WasmCompiledModule* compiled_module =
i::WasmCompiledModule::cast(script->wasm_compiled_module());
i::wasm::WasmModule* module = compiled_module->shared()->module();
DCHECK_LE(0, function_index);
DCHECK_GT(module->functions.size(), function_index);
i::wasm::WasmFunction& func = module->functions[function_index];
i::SeqOneByteString* module_bytes = compiled_module->shared()->module_bytes();
i::wasm::ModuleWireBytes wire_bytes(
module_bytes->GetFlatContent().ToOneByteVector());
i::Vector<const i::byte> function_bytes = wire_bytes.GetFunctionBytes(&func);
// TODO(herhut): Maybe also take module, name and signature into account.
return i::StringHasher::HashSequentialString(function_bytes.start(),
function_bytes.length(), 0);
}
debug::WasmDisassembly debug::WasmScript::DisassembleFunction(
int function_index) const {
i::DisallowHeapAllocation no_gc;
......
......@@ -166,6 +166,7 @@ class WasmScript : public Script {
std::pair<int, int> GetFunctionRange(int function_index) const;
debug::WasmDisassembly DisassembleFunction(int function_index) const;
uint32_t GetFunctionHash(int function_index);
};
void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts);
......
......@@ -493,22 +493,39 @@ void String16Builder::append(const char* characters, size_t length) {
}
void String16Builder::appendNumber(int number) {
const int kBufferSize = 11;
constexpr int kBufferSize = 11;
char buffer[kBufferSize];
int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%d", number);
DCHECK_GT(kBufferSize, chars);
DCHECK_LE(0, chars);
m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
}
void String16Builder::appendNumber(size_t number) {
const int kBufferSize = 20;
constexpr int kBufferSize = 20;
char buffer[kBufferSize];
#if !defined(_WIN32) && !defined(_WIN64)
int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%zu", number);
#else
int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%Iu", number);
#endif
DCHECK_GT(kBufferSize, chars);
DCHECK_LE(0, chars);
m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
}
void String16Builder::appendUnsignedAsHex(uint64_t number) {
constexpr int kBufferSize = 17;
char buffer[kBufferSize];
int chars =
v8::base::OS::SNPrintF(buffer, kBufferSize, "%016" PRIx64, number);
DCHECK_LE(0, chars);
m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
}
void String16Builder::appendUnsignedAsHex(uint32_t number) {
constexpr int kBufferSize = 9;
char buffer[kBufferSize];
int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%08" PRIx32, number);
DCHECK_LE(0, chars);
m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
}
......
......@@ -112,6 +112,8 @@ class String16Builder {
void append(const char*, size_t);
void appendNumber(int);
void appendNumber(size_t);
void appendUnsignedAsHex(uint64_t);
void appendUnsignedAsHex(uint32_t);
String16 toString();
void reserveCapacity(size_t);
......
......@@ -156,9 +156,8 @@ String16 breakpointHint(const V8DebuggerScript& script, int lineNumber,
return hint;
}
void adjustBreakpointLocation(const V8DebuggerScript& script,
const String16& hint, int* lineNumber,
int* columnNumber) {
void adjustBreakpointLocation(V8DebuggerScript& script, const String16& hint,
int* lineNumber, int* columnNumber) {
if (*lineNumber < script.startLine() || *lineNumber > script.endLine())
return;
if (hint.isEmpty()) return;
......@@ -467,7 +466,7 @@ Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) {
return Response::OK();
}
static bool matches(V8InspectorImpl* inspector, const V8DebuggerScript& script,
static bool matches(V8InspectorImpl* inspector, V8DebuggerScript& script,
BreakpointType type, const String16& selector) {
switch (type) {
case BreakpointType::kByUrl:
......@@ -1357,10 +1356,12 @@ bool V8DebuggerAgentImpl::isPaused() const {
void V8DebuggerAgentImpl::didParseSource(
std::unique_ptr<V8DebuggerScript> script, bool success) {
v8::HandleScope handles(m_isolate);
String16 scriptSource = script->source();
if (!success) script->setSourceURL(findSourceURL(scriptSource, false));
if (!success)
if (!success) {
DCHECK(!script->isSourceLoadedLazily());
String16 scriptSource = script->source();
script->setSourceURL(findSourceURL(scriptSource, false));
script->setSourceMappingURL(findSourceMapURL(scriptSource, false));
}
int contextId = script->executionContextId();
int contextGroupId = m_inspector->contextGroupId(contextId);
......@@ -1402,13 +1403,23 @@ void V8DebuggerAgentImpl::didParseSource(
stack && !stack->isEmpty() ? stack->buildInspectorObjectImpl(m_debugger)
: nullptr;
if (success) {
m_frontend.scriptParsed(
scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
scriptRef->endLine(), scriptRef->endColumn(), contextId,
scriptRef->hash(), std::move(executionContextAuxDataParam),
isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
isModuleParam, static_cast<int>(scriptRef->source().length()),
std::move(stackTrace));
// TODO(herhut, dgozman): Report correct length for WASM if needed for
// coverage. Or do not send the length at all and change coverage instead.
if (scriptRef->isSourceLoadedLazily()) {
m_frontend.scriptParsed(
scriptId, scriptURL, 0, 0, 0, 0, contextId, scriptRef->hash(),
std::move(executionContextAuxDataParam), isLiveEditParam,
std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam, 0,
std::move(stackTrace));
} else {
m_frontend.scriptParsed(
scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
scriptRef->endLine(), scriptRef->endColumn(), contextId,
scriptRef->hash(), std::move(executionContextAuxDataParam),
isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
isModuleParam, static_cast<int>(scriptRef->source().length()),
std::move(stackTrace));
}
} else {
m_frontend.scriptFailedToParse(
scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
......
......@@ -16,10 +16,10 @@ namespace {
const char hexDigits[17] = "0123456789ABCDEF";
const char kGlobalDebuggerScriptHandleLabel[] = "DevTools debugger";
void appendUnsignedAsHex(uint64_t number, String16Builder* destination) {
void appendUnsignedAsHex(uint64_t number, String16Builder& destination) {
for (size_t i = 0; i < 8; ++i) {
UChar c = hexDigits[number & 0xF];
destination->append(c);
destination.append(c);
number >>= 4;
}
}
......@@ -82,7 +82,8 @@ String16 calculateHash(const String16& str) {
hashes[i] = (hashes[i] + zi[i] * (prime[i] - 1)) % prime[i];
String16Builder hash;
for (size_t i = 0; i < hashesSize; ++i) appendUnsignedAsHex(hashes[i], &hash);
// TODO(herhut): Use String16Builder.appendUnsignedAsHex.
for (size_t i = 0; i < hashesSize; ++i) appendUnsignedAsHex(hashes[i], hash);
return hash.toString();
}
......@@ -157,6 +158,13 @@ class ActualScript : public V8DebuggerScript {
bool isLiveEdit() const override { return m_isLiveEdit; }
bool isModule() const override { return m_isModule; }
const String16& source() const override { return m_source; }
int startLine() const override { return m_startLine; }
int startColumn() const override { return m_startColumn; }
int endLine() const override { return m_endLine; }
int endColumn() const override { return m_endColumn; }
bool isSourceLoadedLazily() const override { return false; }
const String16& sourceMappingURL() const override {
return m_sourceMappingURL;
}
......@@ -241,6 +249,12 @@ class ActualScript : public V8DebuggerScript {
id);
}
const String16& hash() override {
if (m_hash.isEmpty()) m_hash = calculateHash(source());
DCHECK(!m_hash.isEmpty());
return m_hash;
}
private:
String16 GetNameOrSourceUrl(v8::Local<v8::debug::Script> script) {
v8::Local<v8::String> name;
......@@ -256,6 +270,12 @@ class ActualScript : public V8DebuggerScript {
String16 m_sourceMappingURL;
bool m_isLiveEdit = false;
bool m_isModule = false;
String16 m_source;
mutable String16 m_hash;
int m_startLine = 0;
int m_startColumn = 0;
int m_endLine = 0;
int m_endColumn = 0;
v8::Global<v8::debug::Script> m_script;
};
......@@ -265,22 +285,12 @@ class WasmVirtualScript : public V8DebuggerScript {
public:
WasmVirtualScript(v8::Isolate* isolate, WasmTranslation* wasmTranslation,
v8::Local<v8::debug::WasmScript> script, String16 id,
String16 url, String16 source)
String16 url, int functionIndex)
: V8DebuggerScript(isolate, std::move(id), std::move(url)),
m_script(isolate, script),
m_wasmTranslation(wasmTranslation) {
m_wasmTranslation(wasmTranslation),
m_functionIndex(functionIndex) {
m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
int num_lines = 0;
int last_newline = -1;
size_t next_newline = source.find('\n', last_newline + 1);
while (next_newline != String16::kNotFound) {
last_newline = static_cast<int>(next_newline);
next_newline = source.find('\n', last_newline + 1);
++num_lines;
}
m_endLine = num_lines;
m_endColumn = static_cast<int>(source.length()) - last_newline - 1;
m_source = std::move(source);
m_executionContextId = script->ContextId().ToChecked();
}
......@@ -289,6 +299,22 @@ class WasmVirtualScript : public V8DebuggerScript {
bool isModule() const override { return false; }
void setSourceMappingURL(const String16&) override {}
void setSource(const String16&, bool, bool*) override { UNREACHABLE(); }
bool isSourceLoadedLazily() const override { return true; }
const String16& source() const override {
return m_wasmTranslation->GetSource(m_id, m_functionIndex);
}
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);
}
bool getPossibleBreakpoints(
const v8::debug::Location& start, const v8::debug::Location& end,
......@@ -347,6 +373,13 @@ class WasmVirtualScript : public V8DebuggerScript {
return true;
}
const String16& hash() override {
if (m_hash.isEmpty()) {
m_hash = m_wasmTranslation->GetHash(m_id, m_functionIndex);
}
return m_hash;
}
private:
static const String16& emptyString() {
static const String16 singleEmptyString;
......@@ -359,6 +392,8 @@ class WasmVirtualScript : public V8DebuggerScript {
v8::Global<v8::debug::WasmScript> m_script;
WasmTranslation* m_wasmTranslation;
int m_functionIndex;
mutable String16 m_hash;
};
} // namespace
......@@ -373,10 +408,10 @@ std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create(
std::unique_ptr<V8DebuggerScript> V8DebuggerScript::CreateWasm(
v8::Isolate* isolate, WasmTranslation* wasmTranslation,
v8::Local<v8::debug::WasmScript> underlyingScript, String16 id,
String16 url, String16 source) {
String16 url, int functionIndex) {
return std::unique_ptr<WasmVirtualScript>(
new WasmVirtualScript(isolate, wasmTranslation, underlyingScript,
std::move(id), std::move(url), std::move(source)));
std::move(id), std::move(url), functionIndex));
}
V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, String16 id,
......@@ -389,12 +424,6 @@ const String16& V8DebuggerScript::sourceURL() const {
return m_sourceURL.isEmpty() ? m_url : m_sourceURL;
}
const String16& V8DebuggerScript::hash() const {
if (m_hash.isEmpty()) m_hash = calculateHash(source());
DCHECK(!m_hash.isEmpty());
return m_hash;
}
void V8DebuggerScript::setSourceURL(const String16& sourceURL) {
m_sourceURL = sourceURL;
}
......
......@@ -50,7 +50,7 @@ class V8DebuggerScript {
static std::unique_ptr<V8DebuggerScript> CreateWasm(
v8::Isolate* isolate, WasmTranslation* wasmTranslation,
v8::Local<v8::debug::WasmScript> underlyingScript, String16 id,
String16 url, String16 source);
String16 url, int functionIndex);
virtual ~V8DebuggerScript();
......@@ -59,15 +59,16 @@ class V8DebuggerScript {
bool hasSourceURL() const { return !m_sourceURL.isEmpty(); }
const String16& sourceURL() const;
virtual const String16& sourceMappingURL() const = 0;
const String16& source() const { return m_source; }
const String16& hash() const;
int startLine() const { return m_startLine; }
int startColumn() const { return m_startColumn; }
int endLine() const { return m_endLine; }
int endColumn() const { return m_endColumn; }
virtual const String16& source() const = 0;
virtual const String16& hash() = 0;
virtual int startLine() const = 0;
virtual int startColumn() const = 0;
virtual int endLine() const = 0;
virtual int endColumn() const = 0;
int executionContextId() const { return m_executionContextId; }
virtual bool isLiveEdit() const = 0;
virtual bool isModule() const = 0;
virtual bool isSourceLoadedLazily() const = 0;
void setSourceURL(const String16&);
virtual void setSourceMappingURL(const String16&) = 0;
......@@ -95,12 +96,6 @@ class V8DebuggerScript {
String16 m_id;
String16 m_url;
String16 m_sourceURL;
String16 m_source;
mutable String16 m_hash;
int m_startLine = 0;
int m_startColumn = 0;
int m_endLine = 0;
int m_endColumn = 0;
int m_executionContextId = 0;
v8::Isolate* m_isolate;
......
......@@ -5,6 +5,7 @@
#include "src/inspector/wasm-translation.h"
#include <algorithm>
#include <utility>
#include "src/debug/debug-interface.h"
#include "src/inspector/string-util.h"
......@@ -15,6 +16,42 @@
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 {
......@@ -33,6 +70,10 @@ class WasmTranslation::TranslatorImpl {
virtual void Init(v8::Isolate*, WasmTranslation*, V8DebuggerAgentImpl*) = 0;
virtual void Translate(TransLocation*) = 0;
virtual void TranslateBack(TransLocation*) = 0;
virtual const WasmSourceInformation& GetSourceInformation(v8::Isolate*,
int index) = 0;
virtual const String16 GetHash(v8::Isolate*, int index) = 0;
virtual ~TranslatorImpl() {}
class RawTranslator;
......@@ -42,14 +83,22 @@ class WasmTranslation::TranslatorImpl {
class WasmTranslation::TranslatorImpl::RawTranslator
: public WasmTranslation::TranslatorImpl {
public:
void Init(v8::Isolate*, WasmTranslation*, V8DebuggerAgentImpl*) {}
void Translate(TransLocation*) {}
void TranslateBack(TransLocation*) {}
void Init(v8::Isolate*, WasmTranslation*, V8DebuggerAgentImpl*) override {}
void Translate(TransLocation*) override {}
void TranslateBack(TransLocation*) override {}
const WasmSourceInformation& GetSourceInformation(v8::Isolate*,
int index) override {
static const WasmSourceInformation singleEmptySourceInformation;
return singleEmptySourceInformation;
}
const String16 GetHash(v8::Isolate*, int index) override {
// TODO(herhut): Find useful hash default value.
return String16();
}
};
class WasmTranslation::TranslatorImpl::DisassemblingTranslator
: public WasmTranslation::TranslatorImpl {
using OffsetTable = v8::debug::WasmDisassembly::OffsetTable;
public:
DisassemblingTranslator(v8::Isolate* isolate,
......@@ -99,48 +148,36 @@ class WasmTranslation::TranslatorImpl::DisassemblingTranslator
}
}
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) override {
int func_index = GetFunctionIndexFromFakeScriptId(loc->script_id);
const OffsetTable* reverse_table = GetReverseTable(func_index);
if (!reverse_table) return;
DCHECK(!reverse_table->empty());
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.
unsigned left = 0; // inclusive
unsigned right = static_cast<unsigned>(reverse_table->size()); // exclusive
while (right - left > 1) {
unsigned mid = (left + right) / 2;
auto& entry = (*reverse_table)[mid];
if (entry.line < loc->line ||
(entry.line == loc->line && entry.column <= loc->column)) {
left = mid;
} else {
right = mid;
}
}
auto element = std::lower_bound(reverse_table.begin(), reverse_table.end(),
*loc, LessThan);
int found_byte_offset = 0;
// [left] is <= <line,column>, or left==0 and [0] > <line,column>.
// We are searching for the smallest entry >= <line,column> which is still
// on the same line. This must be either [left] or [left + 1].
// If we don't find such an entry, we might have hit the special case of
// pointing after the last line, which is translated to the end of the
// function (one byte after the last function byte).
if ((*reverse_table)[left].line == loc->line &&
(*reverse_table)[left].column >= loc->column) {
found_byte_offset = (*reverse_table)[left].byte_offset;
} else if (left + 1 < reverse_table->size() &&
(*reverse_table)[left + 1].line == loc->line &&
(*reverse_table)[left + 1].column >= loc->column) {
found_byte_offset = (*reverse_table)[left + 1].byte_offset;
} else if (left == reverse_table->size() - 1 &&
(*reverse_table)[left].line == loc->line - 1 &&
loc->column == 0) {
// 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.
std::pair<int, int> func_range =
script_.Get(isolate)->GetFunctionRange(func_index);
DCHECK_LE(func_range.first, func_range.second);
found_byte_offset = func_range.second - func_range.first;
} else if (element->line == loc->line || element == reverse_table.begin()) {
found_byte_offset = element->byte_offset;
} else {
auto prev = element - 1;
DCHECK(prev->line == loc->line);
found_byte_offset = prev->byte_offset;
}
loc->script_id = String16::fromInteger(script_.Get(isolate)->Id());
......@@ -148,6 +185,31 @@ class WasmTranslation::TranslatorImpl::DisassemblingTranslator
loc->column = found_byte_offset;
}
const WasmSourceInformation& GetSourceInformation(v8::Isolate* isolate,
int index) override {
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) override {
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();
}
private:
String16 GetFakeScriptUrl(v8::Isolate* isolate, int func_index) {
v8::Local<v8::debug::WasmScript> script = script_.Get(isolate);
......@@ -182,20 +244,10 @@ class WasmTranslation::TranslatorImpl::DisassemblingTranslator
String16 fake_script_id = GetFakeScriptId(underlyingScriptId, func_idx);
String16 fake_script_url = GetFakeScriptUrl(isolate, func_idx);
v8::Local<v8::debug::WasmScript> script = script_.Get(isolate);
// TODO(clemensh): Generate disassembly lazily when queried by the frontend.
v8::debug::WasmDisassembly disassembly =
script->DisassembleFunction(func_idx);
DCHECK_EQ(0, offset_tables_.count(func_idx));
offset_tables_.insert(
std::make_pair(func_idx, std::move(disassembly.offset_table)));
String16 source(disassembly.disassembly.data(),
disassembly.disassembly.length());
std::unique_ptr<V8DebuggerScript> fake_script =
V8DebuggerScript::CreateWasm(isolate, translation, script,
V8DebuggerScript::CreateWasm(isolate, translation, script_.Get(isolate),
fake_script_id, std::move(fake_script_url),
source);
func_idx);
translation->AddFakeScript(fake_script->scriptId(), this);
agent->didParseSource(std::move(fake_script), true);
......@@ -212,42 +264,19 @@ class WasmTranslation::TranslatorImpl::DisassemblingTranslator
const OffsetTable& GetOffsetTable(const TransLocation* loc) {
int func_index = loc->line;
auto it = offset_tables_.find(func_index);
// TODO(clemensh): Once we load disassembly lazily, the offset table
// might not be there yet. Load it lazily then.
DCHECK(it != offset_tables_.end());
return it->second;
return GetSourceInformation(loc->translation->isolate_, func_index)
.offset_table;
}
const OffsetTable* GetReverseTable(int func_index) {
auto it = reverse_tables_.find(func_index);
if (it != reverse_tables_.end()) return &it->second;
// Find offset table, copy and sort it to get reverse table.
it = offset_tables_.find(func_index);
if (it == offset_tables_.end()) return nullptr;
OffsetTable reverse_table = it->second;
// 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_table.begin(), reverse_table.end(), cmp);
auto inserted = reverse_tables_.insert(
std::make_pair(func_index, std::move(reverse_table)));
DCHECK(inserted.second);
return &inserted.first->second;
const OffsetTable& GetReverseTable(v8::Isolate* isolate, int func_index) {
return GetSourceInformation(isolate, func_index).reverse_offset_table;
}
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, const OffsetTable> offset_tables_;
std::unordered_map<int, const OffsetTable> reverse_tables_;
std::unordered_map<int, WasmSourceInformation> source_informations_;
};
WasmTranslation::WasmTranslation(v8::Isolate* isolate)
......@@ -280,6 +309,31 @@ void WasmTranslation::Clear() {
fake_scripts_.clear();
}
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) {
......@@ -326,5 +380,4 @@ void WasmTranslation::AddFakeScript(const String16& scriptId,
DCHECK_EQ(0, fake_scripts_.count(scriptId));
fake_scripts_.insert(std::make_pair(scriptId, translator));
}
} // namespace v8_inspector
......@@ -56,6 +56,13 @@ class WasmTranslation {
int* line_number,
int* column_number);
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;
......
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