summaryrefslogtreecommitdiff
path: root/deps/v8/src/inspector/wasm-translation.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/inspector/wasm-translation.cc')
-rw-r--r--deps/v8/src/inspector/wasm-translation.cc309
1 files changed, 309 insertions, 0 deletions
diff --git a/deps/v8/src/inspector/wasm-translation.cc b/deps/v8/src/inspector/wasm-translation.cc
new file mode 100644
index 0000000000..825341e122
--- /dev/null
+++ b/deps/v8/src/inspector/wasm-translation.cc
@@ -0,0 +1,309 @@
+// 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 "src/debug/debug-interface.h"
+#include "src/inspector/protocol/Debugger.h"
+#include "src/inspector/script-breakpoint.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"
+
+using namespace v8_inspector;
+using namespace v8;
+
+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(script_id),
+ line(line),
+ column(column) {}
+ };
+
+ virtual void Translate(TransLocation *loc) = 0;
+ virtual void TranslateBack(TransLocation *loc) = 0;
+
+ class RawTranslator;
+ class DisassemblingTranslator;
+};
+
+class WasmTranslation::TranslatorImpl::RawTranslator
+ : public WasmTranslation::TranslatorImpl {
+ public:
+ void Translate(TransLocation *loc) {}
+ void TranslateBack(TransLocation *loc) {}
+};
+
+class WasmTranslation::TranslatorImpl::DisassemblingTranslator
+ : public WasmTranslation::TranslatorImpl {
+ using OffsetTable = debug::WasmDisassembly::OffsetTable;
+
+ public:
+ DisassemblingTranslator(Isolate *isolate, Local<debug::WasmScript> script,
+ WasmTranslation *translation,
+ V8DebuggerAgentImpl *agent)
+ : script_(isolate, script) {
+ // Register fake scripts for each function in this wasm module/script.
+ 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) {
+ AddFakeScript(isolate, script_id, func_idx, translation, agent);
+ }
+ }
+
+ void Translate(TransLocation *loc) {
+ const OffsetTable &offset_table = GetOffsetTable(loc);
+ DCHECK(!offset_table.empty());
+ uint32_t byte_offset = static_cast<uint32_t>(loc->column);
+
+ // 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;
+ }
+ }
+
+ void TranslateBack(TransLocation *loc) {
+ int func_index = GetFunctionIndexFromFakeScriptId(loc->script_id);
+ const OffsetTable *reverse_table = GetReverseTable(func_index);
+ if (!reverse_table) return;
+ DCHECK(!reverse_table->empty());
+
+ // 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;
+ }
+ }
+
+ int found_byte_offset = 0;
+ // If we found an exact match, use it. Otherwise check whether the next
+ // bigger entry is still in the same line. Report that one then.
+ 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) {
+ found_byte_offset = (*reverse_table)[left + 1].byte_offset;
+ }
+
+ v8::Isolate *isolate = loc->translation->isolate_;
+ loc->script_id = String16::fromInteger(script_.Get(isolate)->Id());
+ loc->line = func_index;
+ loc->column = found_byte_offset;
+ }
+
+ private:
+ String16 GetFakeScriptUrl(v8::Isolate *isolate, int func_index) {
+ Local<debug::WasmScript> script = script_.Get(isolate);
+ String16 script_name = toProtocolString(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, loc->line);
+ }
+
+ void AddFakeScript(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);
+
+ v8::Local<debug::WasmScript> script = script_.Get(isolate);
+ // TODO(clemensh): Generate disassembly lazily when queried by the frontend.
+ 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, script, fake_script_id,
+ std::move(fake_script_url), source);
+
+ translation->AddFakeScript(fake_script->scriptId(), this);
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ Global<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_;
+};
+
+WasmTranslation::WasmTranslation(v8::Isolate *isolate)
+ : isolate_(isolate), mode_(Disassemble) {}
+
+WasmTranslation::~WasmTranslation() { Clear(); }
+
+void WasmTranslation::AddScript(Local<debug::WasmScript> script,
+ V8DebuggerAgentImpl *agent) {
+ int script_id = script->Id();
+ DCHECK_EQ(0, wasm_translators_.count(script_id));
+ std::unique_ptr<TranslatorImpl> impl;
+ switch (mode_) {
+ case Raw:
+ impl.reset(new TranslatorImpl::RawTranslator());
+ break;
+ case Disassemble:
+ impl.reset(new TranslatorImpl::DisassemblingTranslator(isolate_, script,
+ this, agent));
+ break;
+ }
+ DCHECK(impl);
+ wasm_translators_.insert(std::make_pair(script_id, std::move(impl)));
+}
+
+void WasmTranslation::Clear() {
+ wasm_translators_.clear();
+ fake_scripts_.clear();
+}
+
+// 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;
+}
+
+void WasmTranslation::AddFakeScript(const String16 &scriptId,
+ TranslatorImpl *translator) {
+ DCHECK_EQ(0, fake_scripts_.count(scriptId));
+ fake_scripts_.insert(std::make_pair(scriptId, translator));
+}