5 #include "src/inspector/wasm-translation.h" 10 #include "src/debug/debug-interface.h" 11 #include "src/inspector/string-util.h" 12 #include "src/inspector/v8-debugger-agent-impl.h" 13 #include "src/inspector/v8-debugger-script.h" 14 #include "src/inspector/v8-debugger.h" 15 #include "src/inspector/v8-inspector-impl.h" 19 using OffsetTable = v8::debug::WasmDisassembly::OffsetTable;
26 OffsetTable offset_table;
27 OffsetTable reverse_offset_table;
30 : source(std::move(source)), offset_table(std::move(offset_table)) {
32 int last_newline = -1;
33 size_t next_newline = this->source.find(
'\n', last_newline + 1);
34 while (next_newline != String16::kNotFound) {
35 last_newline =
static_cast<int>(next_newline);
36 next_newline = this->source.find(
'\n', last_newline + 1);
40 end_column =
static_cast<int>(this->source.length()) - last_newline - 1;
42 reverse_offset_table = this->offset_table;
44 auto cmp = [](OffsetTable::value_type el1, OffsetTable::value_type el2) {
45 if (el1.line != el2.line)
return el1.line < el2.line;
46 if (el1.column != el2.column)
return el1.column < el2.column;
47 return el1.byte_offset < el2.byte_offset;
49 std::sort(reverse_offset_table.begin(), reverse_offset_table.end(), cmp);
64 : translation(translation),
65 script_id(std::move(script_id)),
71 : script_(isolate, script) {}
77 int num_functions = script->NumFunctions();
78 int num_imported_functions = script->NumImportedFunctions();
79 DCHECK_LE(0, num_imported_functions);
80 DCHECK_LE(0, num_functions);
81 DCHECK_GE(num_functions, num_imported_functions);
82 String16 script_id = String16::fromInteger(script->Id());
83 for (
int func_idx = num_imported_functions; func_idx < num_functions;
85 AddFakeScript(isolate, script_id, func_idx, translation, agent);
89 void Translate(TransLocation* loc) {
90 const OffsetTable& offset_table = GetOffsetTable(loc);
91 DCHECK(!offset_table.empty());
96 unsigned right =
static_cast<unsigned>(offset_table.size());
97 while (right - left > 1) {
98 unsigned mid = (left + right) / 2;
99 if (offset_table[mid].byte_offset <= byte_offset) {
106 loc->script_id = GetFakeScriptId(loc);
107 if (offset_table[left].byte_offset == byte_offset) {
108 loc->line = offset_table[left].line;
109 loc->column = offset_table[left].column;
117 const TransLocation& loc) {
118 return entry.line < loc.line ||
119 (entry.line == loc.line && entry.column < loc.column);
122 void TranslateBack(TransLocation* loc) {
123 v8::Isolate* isolate = loc->translation->isolate_;
124 int func_index = GetFunctionIndexFromFakeScriptId(loc->script_id);
125 const OffsetTable& reverse_table = GetReverseTable(isolate, func_index);
126 if (reverse_table.empty())
return;
129 auto element = std::lower_bound(reverse_table.begin(), reverse_table.end(),
132 int found_byte_offset = 0;
134 if (element == reverse_table.end()) {
136 std::pair<int, int> func_range =
137 script_.Get(isolate)->GetFunctionRange(func_index);
138 DCHECK_LE(func_range.first, func_range.second);
139 found_byte_offset = func_range.second - func_range.first;
140 }
else if (element->line == loc->line || element == reverse_table.begin()) {
141 found_byte_offset = element->byte_offset;
143 auto prev = element - 1;
144 DCHECK(prev->line == loc->line);
145 found_byte_offset = prev->byte_offset;
148 loc->script_id = String16::fromInteger(script_.Get(isolate)->Id());
149 loc->line = func_index;
150 loc->column = found_byte_offset;
153 const WasmSourceInformation& GetSourceInformation(v8::Isolate* isolate,
155 auto it = source_informations_.find(index);
156 if (it != source_informations_.end())
return it->second;
161 auto inserted = source_informations_.insert(std::make_pair(
162 index, WasmSourceInformation({disassembly.disassembly.data(),
163 disassembly.disassembly.length()},
164 std::move(disassembly.offset_table))));
165 DCHECK(inserted.second);
166 return inserted.first->second;
169 const String16 GetHash(v8::Isolate* isolate,
int index) {
172 uint32_t hash = script->GetFunctionHash(index);
173 String16Builder builder;
174 builder.appendUnsignedAsHex(hash);
175 return builder.toString();
178 int GetContextId(v8::Isolate* isolate) {
181 return script->ContextId().FromMaybe(0);
185 String16 GetFakeScriptUrl(v8::Isolate* isolate,
int func_index) {
187 String16 script_name =
188 toProtocolString(isolate, script->Name().ToLocalChecked());
189 int numFunctions = script->NumFunctions();
190 int numImported = script->NumImportedFunctions();
191 String16Builder builder;
192 builder.appendAll(
"wasm://wasm/", script_name,
'/');
193 if (numFunctions - numImported > 300) {
194 size_t digits = String16::fromInteger(numFunctions - 1).length();
195 String16 thisCategory = String16::fromInteger((func_index / 100) * 100);
196 DCHECK_LE(thisCategory.length(), digits);
197 for (
size_t i = thisCategory.length();
i < digits; ++
i)
199 builder.appendAll(thisCategory,
'/');
201 builder.appendAll(script_name,
'-');
202 builder.appendNumber(func_index);
203 return builder.toString();
206 String16 GetFakeScriptId(
const String16& script_id,
int func_index) {
207 return String16::concat(script_id,
'-', String16::fromInteger(func_index));
209 String16 GetFakeScriptId(
const TransLocation* loc) {
210 return GetFakeScriptId(loc->script_id, loc->line);
213 void AddFakeScript(v8::Isolate* isolate,
const String16& underlyingScriptId,
214 int func_idx, WasmTranslation* translation,
215 V8DebuggerAgentImpl* agent) {
216 String16 fake_script_id = GetFakeScriptId(underlyingScriptId, func_idx);
217 String16 fake_script_url = GetFakeScriptUrl(isolate, func_idx);
219 std::unique_ptr<V8DebuggerScript> fake_script =
220 V8DebuggerScript::CreateWasm(isolate, translation, script_.Get(isolate),
221 fake_script_id, std::move(fake_script_url),
224 translation->AddFakeScript(fake_script->scriptId(),
this);
225 agent->didParseSource(std::move(fake_script),
true);
228 int GetFunctionIndexFromFakeScriptId(
const String16& fake_script_id) {
229 size_t last_dash_pos = fake_script_id.reverseFind(
'-');
230 DCHECK_GT(fake_script_id.length(), last_dash_pos);
232 int func_index = fake_script_id.substring(last_dash_pos + 1).toInteger(&ok);
237 const OffsetTable& GetOffsetTable(
const TransLocation* loc) {
238 int func_index = loc->line;
239 return GetSourceInformation(loc->translation->isolate_, func_index)
243 const OffsetTable& GetReverseTable(v8::Isolate* isolate,
int func_index) {
244 return GetSourceInformation(isolate, func_index).reverse_offset_table;
251 std::unordered_map<int, WasmSourceInformation> source_informations_;
254 WasmTranslation::WasmTranslation(v8::Isolate* isolate) : isolate_(isolate) {}
256 WasmTranslation::~WasmTranslation() { Clear(); }
259 V8DebuggerAgentImpl* agent) {
260 std::unique_ptr<TranslatorImpl> impl;
261 impl.reset(
new TranslatorImpl(isolate_, script));
264 wasm_translators_.insert(std::make_pair(script->Id(), std::move(impl)));
266 DCHECK(inserted.second);
268 inserted.first->second->Init(isolate_,
this, agent);
271 void WasmTranslation::Clear() {
272 wasm_translators_.clear();
273 fake_scripts_.clear();
276 void WasmTranslation::Clear(v8::Isolate* isolate,
277 const std::vector<int>& contextIdsToClear) {
278 for (
auto iter = fake_scripts_.begin(); iter != fake_scripts_.end();) {
279 auto contextId = iter->second->GetContextId(isolate);
280 auto it = std::find(std::begin(contextIdsToClear),
281 std::end(contextIdsToClear), contextId);
282 if (it != std::end(contextIdsToClear)) {
283 iter = fake_scripts_.erase(iter);
289 for (
auto iter = wasm_translators_.begin();
290 iter != wasm_translators_.end();) {
291 auto contextId = iter->second->GetContextId(isolate);
292 auto it = std::find(std::begin(contextIdsToClear),
293 std::end(contextIdsToClear), contextId);
294 if (it != std::end(contextIdsToClear)) {
295 iter = wasm_translators_.erase(iter);
302 const String16& WasmTranslation::GetSource(
const String16& script_id,
304 auto it = fake_scripts_.find(script_id);
305 DCHECK_NE(it, fake_scripts_.end());
306 return it->second->GetSourceInformation(isolate_, func_index).source;
309 int WasmTranslation::GetEndLine(
const String16& script_id,
int func_index) {
310 auto it = fake_scripts_.find(script_id);
311 DCHECK_NE(it, fake_scripts_.end());
312 return it->second->GetSourceInformation(isolate_, func_index).end_line;
315 int WasmTranslation::GetEndColumn(
const String16& script_id,
int func_index) {
316 auto it = fake_scripts_.find(script_id);
317 DCHECK_NE(it, fake_scripts_.end());
318 return it->second->GetSourceInformation(isolate_, func_index).end_column;
321 String16 WasmTranslation::GetHash(
const String16& script_id,
int func_index) {
322 auto it = fake_scripts_.find(script_id);
323 DCHECK_NE(it, fake_scripts_.end());
324 return it->second->GetHash(isolate_, func_index);
328 bool WasmTranslation::TranslateWasmScriptLocationToProtocolLocation(
329 String16* script_id,
int* line_number,
int* column_number) {
330 DCHECK(script_id && line_number && column_number);
332 int script_id_int = script_id->toInteger(&ok);
333 if (!ok)
return false;
335 auto it = wasm_translators_.find(script_id_int);
336 if (it == wasm_translators_.end())
return false;
337 TranslatorImpl* translator = it->second.get();
339 TranslatorImpl::TransLocation trans_loc(
this, std::move(*script_id),
340 *line_number, *column_number);
341 translator->Translate(&trans_loc);
343 *script_id = std::move(trans_loc.script_id);
344 *line_number = trans_loc.line;
345 *column_number = trans_loc.column;
351 bool WasmTranslation::TranslateProtocolLocationToWasmScriptLocation(
352 String16* script_id,
int* line_number,
int* column_number) {
353 auto it = fake_scripts_.find(*script_id);
354 if (it == fake_scripts_.end())
return false;
355 TranslatorImpl* translator = it->second;
357 TranslatorImpl::TransLocation trans_loc(
this, std::move(*script_id),
358 *line_number, *column_number);
359 translator->TranslateBack(&trans_loc);
361 *script_id = std::move(trans_loc.script_id);
362 *line_number = trans_loc.line;
363 *column_number = trans_loc.column;
368 void WasmTranslation::AddFakeScript(
const String16& scriptId,
369 TranslatorImpl* translator) {
370 DCHECK_EQ(0, fake_scripts_.count(scriptId));
371 fake_scripts_.insert(std::make_pair(scriptId, translator));