Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(785)

Side by Side Diff: src/inspector/wasm-translation.cc

Issue 2493773003: [inspector] Introduce translation of wasm frames (Closed)
Patch Set: More signed/unsigned Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/inspector/wasm-translation.h"
6
7 #include <algorithm>
8
9 #include "src/debug/debug-interface.h"
10 #include "src/inspector/protocol/Debugger.h"
11 #include "src/inspector/script-breakpoint.h"
12 #include "src/inspector/string-util.h"
13 #include "src/inspector/v8-debugger-agent-impl.h"
14 #include "src/inspector/v8-debugger-script.h"
15
16 using namespace v8_inspector;
17 using namespace v8;
18
19 namespace {
20 int GetScriptId(Isolate *isolate, Local<Object> script_wrapper) {
21 Local<Value> script_id = script_wrapper
22 ->Get(isolate->GetCurrentContext(),
23 toV8StringInternalized(isolate, "id"))
24 .ToLocalChecked();
25 DCHECK(script_id->IsInt32());
26 return script_id->Int32Value(isolate->GetCurrentContext()).FromJust();
27 }
28
29 String16 GetScriptName(Isolate *isolate, Local<Object> script_wrapper) {
30 Local<Value> script_name = script_wrapper
31 ->Get(isolate->GetCurrentContext(),
32 toV8StringInternalized(isolate, "name"))
33 .ToLocalChecked();
34 DCHECK(script_name->IsString());
35 return toProtocolString(script_name.As<String>());
36 }
37
38 } // namespace
39
40 class WasmTranslation::TranslatorImpl {
41 public:
42 struct TransLocation {
43 v8::Isolate *isolate;
44 WasmTranslation *translation;
45 String16 script_id;
46 int line;
47 int column;
48 TransLocation(v8::Isolate *isolate, WasmTranslation *translation,
49 String16 script_id, int line, int column)
50 : isolate(isolate),
51 translation(translation),
52 script_id(script_id),
53 line(line),
54 column(column) {}
55 };
56
57 virtual void Translate(TransLocation *loc) = 0;
58 virtual void TranslateBack(TransLocation *loc) = 0;
59
60 class RawTranslator;
61 class DisassemblingTranslator;
62 };
63
64 class WasmTranslation::TranslatorImpl::RawTranslator
65 : public WasmTranslation::TranslatorImpl {
66 public:
67 void Translate(TransLocation *loc) {}
68 void TranslateBack(TransLocation *loc) {}
69 };
70
71 class WasmTranslation::TranslatorImpl::DisassemblingTranslator
72 : public WasmTranslation::TranslatorImpl {
73 using OffsetTable = std::vector<std::tuple<uint32_t, int, int>>;
74
75 public:
76 DisassemblingTranslator(Isolate *isolate, Local<Object> script)
77 : script_(isolate, script) {}
78
79 void Translate(TransLocation *loc) {
80 const OffsetTable &offset_table = GetOffsetTable(loc);
81 DCHECK(!offset_table.empty());
82 DCHECK_EQ(offset_table.size(), static_cast<int>(offset_table.size()));
83 uint32_t byte_offset = static_cast<uint32_t>(loc->column);
84
85 // Binary search for the given offset.
86 unsigned left = 0; // inclusive
87 unsigned right = static_cast<int>(offset_table.size()); // exclusive
88 while (right - left > 1) {
89 unsigned mid = (left + right) / 2;
90 if (std::get<0>(offset_table[mid]) <= byte_offset) {
91 left = mid;
92 } else {
93 right = mid;
94 }
95 }
96
97 loc->script_id = GetFakeScriptId(loc);
98 if (std::get<0>(offset_table[left]) == byte_offset) {
99 loc->line = std::get<1>(offset_table[left]);
100 loc->column = std::get<2>(offset_table[left]);
101 } else {
102 loc->line = 0;
103 loc->column = 0;
104 }
105 }
106
107 void TranslateBack(TransLocation *loc) {
108 int func_index = GetFunctionIndexFromFakeScriptId(loc->script_id);
109 const OffsetTable *reverse_table = GetReverseTable(func_index);
110 if (!reverse_table) return;
111 DCHECK(!reverse_table->empty());
112 DCHECK_EQ(reverse_table->size(), static_cast<int>(reverse_table->size()));
113
114 // Binary search for the given line and column.
115 unsigned left = 0; // inclusive
116 unsigned right = static_cast<int>(reverse_table->size()); // exclusive
117 while (right - left > 1) {
118 unsigned mid = (left + right) / 2;
119 auto &entry = (*reverse_table)[mid];
120 if (std::get<1>(entry) < loc->line ||
121 (std::get<1>(entry) == loc->line &&
122 std::get<2>(entry) <= loc->column)) {
123 left = mid;
124 } else {
125 right = mid;
126 }
127 }
128
129 int found_byte_offset = 0;
130 // If we found an exact match, use it. Otherwise check whether the next
131 // bigger entry is still in the same line. Report that one then.
132 if (std::get<1>((*reverse_table)[left]) == loc->line &&
133 std::get<2>((*reverse_table)[left]) == loc->column) {
134 found_byte_offset = std::get<0>((*reverse_table)[left]);
135 } else if (left + 1 < reverse_table->size() &&
136 std::get<1>((*reverse_table)[left + 1]) == loc->line) {
137 found_byte_offset = std::get<0>((*reverse_table)[left + 1]);
138 }
139
140 loc->script_id = String16::fromInteger(
141 GetScriptId(loc->isolate, script_.Get(loc->isolate)));
142 loc->line = func_index;
143 loc->column = found_byte_offset;
144 }
145
146 private:
147 String16 GetFakeScriptUrl(const TransLocation *loc) {
148 String16 script_name =
149 GetScriptName(loc->isolate, script_.Get(loc->isolate));
150 return String16::concat("wasm://wasm/", script_name, '/', script_name, '-',
151 loc->line);
152 }
153
154 String16 GetFakeScriptId(const TransLocation *loc) {
155 return String16::concat(loc->script_id, '-', loc->line);
156 }
157
158 int GetFunctionIndexFromFakeScriptId(const String16 &fake_script_id) {
159 size_t last_dash_pos = fake_script_id.reverseFind('-');
160 DCHECK_GT(fake_script_id.length(), last_dash_pos);
161 bool ok = true;
162 int func_index = fake_script_id.substring(last_dash_pos + 1).toInteger(&ok);
163 DCHECK(ok);
164 return func_index;
165 }
166
167 const OffsetTable &GetOffsetTable(const TransLocation *loc) {
168 int func_index = loc->line;
169 auto it = offset_tables_.find(func_index);
170 if (it != offset_tables_.end()) return it->second;
171
172 std::pair<std::string, OffsetTable> disassembly =
173 DebugInterface::DisassembleWasmFunction(
174 loc->isolate, script_.Get(loc->isolate), func_index);
175
176 it = offset_tables_
177 .insert(std::make_pair(func_index, std::move(disassembly.second)))
178 .first;
179
180 String16 fake_script_id = GetFakeScriptId(loc);
181 String16 fake_script_url = GetFakeScriptUrl(loc);
182 String16 source(disassembly.first.data(), disassembly.first.length());
183 std::unique_ptr<V8DebuggerScript> fake_script(new V8DebuggerScript(
184 fake_script_id, std::move(fake_script_url), source));
185
186 loc->translation->AddFakeScript(std::move(fake_script), this);
187
188 return it->second;
189 }
190
191 const OffsetTable *GetReverseTable(int func_index) {
192 auto it = reverse_tables_.find(func_index);
193 if (it != reverse_tables_.end()) return &it->second;
194
195 // Find offset table, copy and sort it to get reverse table.
196 it = offset_tables_.find(func_index);
197 if (it == offset_tables_.end()) return nullptr;
198
199 OffsetTable reverse_table = it->second;
200 // Order by line, column, then byte offset.
201 auto cmp = [](std::tuple<uint32_t, int, int> el1,
202 std::tuple<uint32_t, int, int> el2) {
203 if (std::get<1>(el1) != std::get<1>(el2))
204 return std::get<1>(el1) < std::get<1>(el2);
205 if (std::get<2>(el1) != std::get<2>(el2))
206 return std::get<2>(el1) < std::get<2>(el2);
207 return std::get<0>(el1) < std::get<0>(el2);
208 };
209 std::sort(reverse_table.begin(), reverse_table.end(), cmp);
210
211 auto inserted = reverse_tables_.insert(
212 std::make_pair(func_index, std::move(reverse_table)));
213 DCHECK(inserted.second);
214 return &inserted.first->second;
215 }
216
217 Global<Object> script_;
218
219 // We assume to only disassemble a subset of the functions, so store them in a
220 // map instead of an array.
221 std::unordered_map<int, const OffsetTable> offset_tables_;
222 std::unordered_map<int, const OffsetTable> reverse_tables_;
223 };
224
225 WasmTranslation::WasmTranslation(Isolate *isolate,
226 V8DebuggerAgentImpl *debugger_agent)
227 : isolate_(isolate), debugger_agent_(debugger_agent), mode_(Disassemble) {}
228
229 WasmTranslation::~WasmTranslation() { Clear(); }
230
231 void WasmTranslation::AddScript(Local<Object> script_wrapper) {
232 int script_id = GetScriptId(isolate_, script_wrapper);
233 DCHECK_EQ(0, wasm_translators_.count(script_id));
234 std::unique_ptr<TranslatorImpl> impl;
235 switch (mode_) {
236 case Raw:
237 impl.reset(new TranslatorImpl::RawTranslator());
238 break;
239 case Disassemble:
240 impl.reset(new TranslatorImpl::DisassemblingTranslator(isolate_,
241 script_wrapper));
242 break;
243 }
244 DCHECK(impl);
245 wasm_translators_.insert(std::make_pair(script_id, std::move(impl)));
246 }
247
248 void WasmTranslation::Clear() {
249 wasm_translators_.clear();
250 fake_scripts_.clear();
251 }
252
253 bool WasmTranslation::Translate(protocol::Debugger::Location *location) {
254 // Line and column in protocol Location are 0-based.
255 String16 script_id = location->getScriptId();
256 int line_number = location->getLineNumber();
257 int column_number = location->getColumnNumber(-1);
258
259 if (column_number < 0 || !Translate(&script_id, &line_number, &column_number))
260 return false;
261
262 location->setScriptId(std::move(script_id));
263 location->setLineNumber(line_number);
264 location->setColumnNumber(column_number);
265
266 return true;
267 }
268
269 bool WasmTranslation::Translate(String16 *script_id, int *line_number,
270 int *column_number) {
271 DCHECK(script_id && line_number && column_number);
272 bool ok = true;
273 int script_id_int = script_id->toInteger(&ok);
274 if (!ok) return false;
275
276 auto it = wasm_translators_.find(script_id_int);
277 if (it == wasm_translators_.end()) return false;
278 TranslatorImpl *translator = it->second.get();
279
280 TranslatorImpl::TransLocation trans_loc(isolate_, this, std::move(*script_id),
281 *line_number, *column_number);
282 translator->Translate(&trans_loc);
283
284 *script_id = std::move(trans_loc.script_id);
285 *line_number = trans_loc.line;
286 *column_number = trans_loc.column;
287
288 return true;
289 }
290
291 bool WasmTranslation::TranslateBack(ScriptBreakpoint *breakpoint) {
292 auto it = fake_scripts_.find(breakpoint->script_id);
293 if (it == fake_scripts_.end()) return false;
294 TranslatorImpl *translator = it->second;
295
296 TranslatorImpl::TransLocation trans_loc(
297 isolate_, this, std::move(breakpoint->script_id), breakpoint->line_number,
298 breakpoint->column_number);
299 translator->TranslateBack(&trans_loc);
300
301 breakpoint->script_id = std::move(trans_loc.script_id);
302 breakpoint->line_number = trans_loc.line;
303 breakpoint->column_number = trans_loc.column;
304
305 return true;
306 }
307
308 void WasmTranslation::AddFakeScript(
309 std::unique_ptr<V8DebuggerScript> fake_script, TranslatorImpl *translator) {
310 bool inserted =
311 fake_scripts_.insert(std::make_pair(fake_script->scriptId(), translator))
312 .second;
313 DCHECK(inserted);
314 USE(inserted);
315 debugger_agent_->didParseSource(std::move(fake_script), true);
316 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698