| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/inspector/wasm-translation.h" | 5 #include "src/inspector/wasm-translation.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "src/debug/debug-interface.h" | 9 #include "src/debug/debug-interface.h" |
| 10 #include "src/inspector/protocol/Debugger.h" | 10 #include "src/inspector/protocol/Debugger.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 int line; | 26 int line; |
| 27 int column; | 27 int column; |
| 28 TransLocation(WasmTranslation *translation, String16 script_id, int line, | 28 TransLocation(WasmTranslation *translation, String16 script_id, int line, |
| 29 int column) | 29 int column) |
| 30 : translation(translation), | 30 : translation(translation), |
| 31 script_id(script_id), | 31 script_id(script_id), |
| 32 line(line), | 32 line(line), |
| 33 column(column) {} | 33 column(column) {} |
| 34 }; | 34 }; |
| 35 | 35 |
| 36 TranslatorImpl(WasmTranslation* translation, int script_id) { |
| 37 DCHECK_EQ(0, translation->wasm_translators_.count(script_id)); |
| 38 translation->wasm_translators_.insert( |
| 39 std::make_pair(script_id, std::unique_ptr<TranslatorImpl>(this))); |
| 40 } |
| 41 |
| 36 virtual void Translate(TransLocation *loc) = 0; | 42 virtual void Translate(TransLocation *loc) = 0; |
| 37 virtual void TranslateBack(TransLocation *loc) = 0; | 43 virtual void TranslateBack(TransLocation *loc) = 0; |
| 38 | 44 |
| 39 class RawTranslator; | 45 class RawTranslator; |
| 40 class DisassemblingTranslator; | 46 class DisassemblingTranslator; |
| 41 }; | 47 }; |
| 42 | 48 |
| 43 class WasmTranslation::TranslatorImpl::RawTranslator | 49 class WasmTranslation::TranslatorImpl::RawTranslator |
| 44 : public WasmTranslation::TranslatorImpl { | 50 : public WasmTranslation::TranslatorImpl { |
| 45 public: | 51 public: |
| 52 RawTranslator(WasmTranslation* translation, Local<debug::WasmScript> script) |
| 53 : TranslatorImpl(translation, script->Id()) {} |
| 46 void Translate(TransLocation *loc) {} | 54 void Translate(TransLocation *loc) {} |
| 47 void TranslateBack(TransLocation *loc) {} | 55 void TranslateBack(TransLocation *loc) {} |
| 48 }; | 56 }; |
| 49 | 57 |
| 50 class WasmTranslation::TranslatorImpl::DisassemblingTranslator | 58 class WasmTranslation::TranslatorImpl::DisassemblingTranslator |
| 51 : public WasmTranslation::TranslatorImpl { | 59 : public WasmTranslation::TranslatorImpl { |
| 52 using OffsetTable = debug::WasmDisassembly::OffsetTable; | 60 using OffsetTable = debug::WasmDisassembly::OffsetTable; |
| 53 | 61 |
| 54 public: | 62 public: |
| 55 DisassemblingTranslator(Isolate *isolate, Local<debug::WasmScript> script, | 63 DisassemblingTranslator(Isolate* isolate, Local<debug::WasmScript> script, |
| 56 WasmTranslation *translation, | 64 WasmTranslation* translation, |
| 57 V8DebuggerAgentImpl *agent) | 65 V8DebuggerAgentImpl* agent) |
| 58 : script_(isolate, script) { | 66 : TranslatorImpl(translation, script->Id()), script_(isolate, script) { |
| 59 // Register fake scripts for each function in this wasm module/script. | 67 // Register fake scripts for each function in this wasm module/script. |
| 60 int num_functions = script->NumFunctions(); | 68 int num_functions = script->NumFunctions(); |
| 61 int num_imported_functions = script->NumImportedFunctions(); | 69 int num_imported_functions = script->NumImportedFunctions(); |
| 62 DCHECK_LE(0, num_imported_functions); | 70 DCHECK_LE(0, num_imported_functions); |
| 63 DCHECK_LE(0, num_functions); | 71 DCHECK_LE(0, num_functions); |
| 64 DCHECK_GE(num_functions, num_imported_functions); | 72 DCHECK_GE(num_functions, num_imported_functions); |
| 65 String16 script_id = String16::fromInteger(script->Id()); | 73 String16 script_id = String16::fromInteger(script->Id()); |
| 66 for (int func_idx = num_imported_functions; func_idx < num_functions; | 74 for (int func_idx = num_imported_functions; func_idx < num_functions; |
| 67 ++func_idx) { | 75 ++func_idx) { |
| 68 AddFakeScript(isolate, script_id, func_idx, translation, agent); | 76 AddFakeScript(isolate, script_id, func_idx, translation, agent); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 94 loc->line = 0; | 102 loc->line = 0; |
| 95 loc->column = 0; | 103 loc->column = 0; |
| 96 } | 104 } |
| 97 } | 105 } |
| 98 | 106 |
| 99 void TranslateBack(TransLocation *loc) { | 107 void TranslateBack(TransLocation *loc) { |
| 100 int func_index = GetFunctionIndexFromFakeScriptId(loc->script_id); | 108 int func_index = GetFunctionIndexFromFakeScriptId(loc->script_id); |
| 101 const OffsetTable *reverse_table = GetReverseTable(func_index); | 109 const OffsetTable *reverse_table = GetReverseTable(func_index); |
| 102 if (!reverse_table) return; | 110 if (!reverse_table) return; |
| 103 DCHECK(!reverse_table->empty()); | 111 DCHECK(!reverse_table->empty()); |
| 112 v8::Isolate* isolate = loc->translation->isolate_; |
| 104 | 113 |
| 105 // Binary search for the given line and column. | 114 // Binary search for the given line and column. |
| 106 unsigned left = 0; // inclusive | 115 unsigned left = 0; // inclusive |
| 107 unsigned right = static_cast<unsigned>(reverse_table->size()); // exclusive | 116 unsigned right = static_cast<unsigned>(reverse_table->size()); // exclusive |
| 108 while (right - left > 1) { | 117 while (right - left > 1) { |
| 109 unsigned mid = (left + right) / 2; | 118 unsigned mid = (left + right) / 2; |
| 110 auto &entry = (*reverse_table)[mid]; | 119 auto &entry = (*reverse_table)[mid]; |
| 111 if (entry.line < loc->line || | 120 if (entry.line < loc->line || |
| 112 (entry.line == loc->line && entry.column <= loc->column)) { | 121 (entry.line == loc->line && entry.column <= loc->column)) { |
| 113 left = mid; | 122 left = mid; |
| 114 } else { | 123 } else { |
| 115 right = mid; | 124 right = mid; |
| 116 } | 125 } |
| 117 } | 126 } |
| 118 | 127 |
| 119 int found_byte_offset = 0; | 128 int found_byte_offset = 0; |
| 120 // If we found an exact match, use it. Otherwise check whether the next | 129 // If we found an exact match, use it. Otherwise check whether the next |
| 121 // bigger entry is still in the same line. Report that one then. | 130 // bigger entry is still in the same line. Report that one then. |
| 131 // Otherwise we might have hit the special case of pointing after the last |
| 132 // line, which is translated to the end of the function (one byte after the |
| 133 // last function byte). |
| 122 if ((*reverse_table)[left].line == loc->line && | 134 if ((*reverse_table)[left].line == loc->line && |
| 123 (*reverse_table)[left].column == loc->column) { | 135 (*reverse_table)[left].column == loc->column) { |
| 124 found_byte_offset = (*reverse_table)[left].byte_offset; | 136 found_byte_offset = (*reverse_table)[left].byte_offset; |
| 125 } else if (left + 1 < reverse_table->size() && | 137 } else if (left + 1 < reverse_table->size() && |
| 126 (*reverse_table)[left + 1].line == loc->line) { | 138 (*reverse_table)[left + 1].line == loc->line) { |
| 127 found_byte_offset = (*reverse_table)[left + 1].byte_offset; | 139 found_byte_offset = (*reverse_table)[left + 1].byte_offset; |
| 140 } else if (left == reverse_table->size() - 1 && |
| 141 (*reverse_table)[left].line == loc->line - 1 && |
| 142 loc->column == 0) { |
| 143 std::pair<int, int> func_range = |
| 144 script_.Get(isolate)->GetFunctionRange(func_index); |
| 145 DCHECK_LE(func_range.first, func_range.second); |
| 146 found_byte_offset = func_range.second - func_range.first; |
| 128 } | 147 } |
| 129 | 148 |
| 130 v8::Isolate *isolate = loc->translation->isolate_; | |
| 131 loc->script_id = String16::fromInteger(script_.Get(isolate)->Id()); | 149 loc->script_id = String16::fromInteger(script_.Get(isolate)->Id()); |
| 132 loc->line = func_index; | 150 loc->line = func_index; |
| 133 loc->column = found_byte_offset; | 151 loc->column = found_byte_offset; |
| 134 } | 152 } |
| 135 | 153 |
| 136 private: | 154 private: |
| 137 String16 GetFakeScriptUrl(v8::Isolate *isolate, int func_index) { | 155 String16 GetFakeScriptUrl(v8::Isolate *isolate, int func_index) { |
| 138 Local<debug::WasmScript> script = script_.Get(isolate); | 156 Local<debug::WasmScript> script = script_.Get(isolate); |
| 139 String16 script_name = toProtocolString(script->Name().ToLocalChecked()); | 157 String16 script_name = toProtocolString(script->Name().ToLocalChecked()); |
| 140 int numFunctions = script->NumFunctions(); | 158 int numFunctions = script->NumFunctions(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 170 v8::Local<debug::WasmScript> script = script_.Get(isolate); | 188 v8::Local<debug::WasmScript> script = script_.Get(isolate); |
| 171 // TODO(clemensh): Generate disassembly lazily when queried by the frontend. | 189 // TODO(clemensh): Generate disassembly lazily when queried by the frontend. |
| 172 debug::WasmDisassembly disassembly = script->DisassembleFunction(func_idx); | 190 debug::WasmDisassembly disassembly = script->DisassembleFunction(func_idx); |
| 173 | 191 |
| 174 DCHECK_EQ(0, offset_tables_.count(func_idx)); | 192 DCHECK_EQ(0, offset_tables_.count(func_idx)); |
| 175 offset_tables_.insert( | 193 offset_tables_.insert( |
| 176 std::make_pair(func_idx, std::move(disassembly.offset_table))); | 194 std::make_pair(func_idx, std::move(disassembly.offset_table))); |
| 177 String16 source(disassembly.disassembly.data(), | 195 String16 source(disassembly.disassembly.data(), |
| 178 disassembly.disassembly.length()); | 196 disassembly.disassembly.length()); |
| 179 std::unique_ptr<V8DebuggerScript> fake_script = | 197 std::unique_ptr<V8DebuggerScript> fake_script = |
| 180 V8DebuggerScript::CreateWasm(isolate, script, fake_script_id, | 198 V8DebuggerScript::CreateWasm(isolate, translation, script, |
| 181 std::move(fake_script_url), source); | 199 fake_script_id, std::move(fake_script_url), |
| 200 source); |
| 182 | 201 |
| 183 translation->AddFakeScript(fake_script->scriptId(), this); | 202 translation->AddFakeScript(fake_script->scriptId(), this); |
| 184 agent->didParseSource(std::move(fake_script), true); | 203 agent->didParseSource(std::move(fake_script), true); |
| 185 } | 204 } |
| 186 | 205 |
| 187 int GetFunctionIndexFromFakeScriptId(const String16 &fake_script_id) { | 206 int GetFunctionIndexFromFakeScriptId(const String16 &fake_script_id) { |
| 188 size_t last_dash_pos = fake_script_id.reverseFind('-'); | 207 size_t last_dash_pos = fake_script_id.reverseFind('-'); |
| 189 DCHECK_GT(fake_script_id.length(), last_dash_pos); | 208 DCHECK_GT(fake_script_id.length(), last_dash_pos); |
| 190 bool ok = true; | 209 bool ok = true; |
| 191 int func_index = fake_script_id.substring(last_dash_pos + 1).toInteger(&ok); | 210 int func_index = fake_script_id.substring(last_dash_pos + 1).toInteger(&ok); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 std::unordered_map<int, const OffsetTable> reverse_tables_; | 252 std::unordered_map<int, const OffsetTable> reverse_tables_; |
| 234 }; | 253 }; |
| 235 | 254 |
| 236 WasmTranslation::WasmTranslation(v8::Isolate *isolate) | 255 WasmTranslation::WasmTranslation(v8::Isolate *isolate) |
| 237 : isolate_(isolate), mode_(Disassemble) {} | 256 : isolate_(isolate), mode_(Disassemble) {} |
| 238 | 257 |
| 239 WasmTranslation::~WasmTranslation() { Clear(); } | 258 WasmTranslation::~WasmTranslation() { Clear(); } |
| 240 | 259 |
| 241 void WasmTranslation::AddScript(Local<debug::WasmScript> script, | 260 void WasmTranslation::AddScript(Local<debug::WasmScript> script, |
| 242 V8DebuggerAgentImpl *agent) { | 261 V8DebuggerAgentImpl *agent) { |
| 243 int script_id = script->Id(); | 262 // Instantiate new TranslatorImpls via new, the base class will register them |
| 244 DCHECK_EQ(0, wasm_translators_.count(script_id)); | 263 // in wasm_translators_, taking ownership. This early registration is |
| 245 std::unique_ptr<TranslatorImpl> impl; | 264 // necessary since the DisassemblingTranslator constructor already registers |
| 265 // the fake scripts, which triggers setting breakpoints. |
| 246 switch (mode_) { | 266 switch (mode_) { |
| 247 case Raw: | 267 case Raw: |
| 248 impl.reset(new TranslatorImpl::RawTranslator()); | 268 new TranslatorImpl::RawTranslator(this, script); |
| 249 break; | 269 return; |
| 250 case Disassemble: | 270 case Disassemble: |
| 251 impl.reset(new TranslatorImpl::DisassemblingTranslator(isolate_, script, | 271 new TranslatorImpl::DisassemblingTranslator(isolate_, script, this, |
| 252 this, agent)); | 272 agent); |
| 253 break; | 273 return; |
| 254 } | 274 } |
| 255 DCHECK(impl); | 275 UNREACHABLE(); |
| 256 wasm_translators_.insert(std::make_pair(script_id, std::move(impl))); | |
| 257 } | 276 } |
| 258 | 277 |
| 259 void WasmTranslation::Clear() { | 278 void WasmTranslation::Clear() { |
| 260 wasm_translators_.clear(); | 279 wasm_translators_.clear(); |
| 261 fake_scripts_.clear(); | 280 fake_scripts_.clear(); |
| 262 } | 281 } |
| 263 | 282 |
| 264 // Translation "forward" (to artificial scripts). | 283 // Translation "forward" (to artificial scripts). |
| 265 bool WasmTranslation::TranslateWasmScriptLocationToProtocolLocation( | 284 bool WasmTranslation::TranslateWasmScriptLocationToProtocolLocation( |
| 266 String16 *script_id, int *line_number, int *column_number) { | 285 String16 *script_id, int *line_number, int *column_number) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 *column_number = trans_loc.column; | 319 *column_number = trans_loc.column; |
| 301 | 320 |
| 302 return true; | 321 return true; |
| 303 } | 322 } |
| 304 | 323 |
| 305 void WasmTranslation::AddFakeScript(const String16 &scriptId, | 324 void WasmTranslation::AddFakeScript(const String16 &scriptId, |
| 306 TranslatorImpl *translator) { | 325 TranslatorImpl *translator) { |
| 307 DCHECK_EQ(0, fake_scripts_.count(scriptId)); | 326 DCHECK_EQ(0, fake_scripts_.count(scriptId)); |
| 308 fake_scripts_.insert(std::make_pair(scriptId, translator)); | 327 fake_scripts_.insert(std::make_pair(scriptId, translator)); |
| 309 } | 328 } |
| OLD | NEW |