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/wasm/wasm-debug.h" | 5 #include "src/wasm/wasm-debug.h" |
6 | 6 |
7 #include "src/assert-scope.h" | 7 #include "src/assert-scope.h" |
| 8 #include "src/compiler/wasm-compiler.h" |
8 #include "src/debug/debug.h" | 9 #include "src/debug/debug.h" |
9 #include "src/factory.h" | 10 #include "src/factory.h" |
| 11 #include "src/frames-inl.h" |
10 #include "src/isolate.h" | 12 #include "src/isolate.h" |
| 13 // We need src/assembler-$arch-inl.h, and macro-assembler.h includes this. |
| 14 #include "src/macro-assembler.h" |
11 #include "src/wasm/module-decoder.h" | 15 #include "src/wasm/module-decoder.h" |
| 16 #include "src/wasm/wasm-interpreter.h" |
12 #include "src/wasm/wasm-module.h" | 17 #include "src/wasm/wasm-module.h" |
13 | 18 |
14 using namespace v8::internal; | 19 using namespace v8::internal; |
15 using namespace v8::internal::wasm; | 20 using namespace v8::internal::wasm; |
16 | 21 |
17 namespace { | 22 namespace { |
18 | 23 |
19 enum { | 24 enum { |
20 kWasmDebugInfoWasmObj, | 25 kWasmDebugInfoWasmObj, |
21 kWasmDebugInfoWasmBytesHash, | 26 kWasmDebugInfoWasmBytesHash, |
22 kWasmDebugInfoFunctionByteOffsets, | 27 kWasmDebugInfoFunctionByteOffsets, |
23 kWasmDebugInfoFunctionScripts, | 28 kWasmDebugInfoFunctionScripts, |
| 29 kWasmDebugInfoInterpreterAddr, |
| 30 kWasmDebugInfoInterpretedFunctions, |
| 31 kWasmDebugInfoDebugInfos, |
24 kWasmDebugInfoNumEntries | 32 kWasmDebugInfoNumEntries |
25 }; | 33 }; |
26 | 34 |
27 ByteArray *GetOrCreateFunctionOffsetTable(Handle<WasmDebugInfo> debug_info) { | 35 ByteArray *GetOrCreateFunctionOffsetTable(Handle<WasmDebugInfo> debug_info) { |
28 Object *offset_table = debug_info->get(kWasmDebugInfoFunctionByteOffsets); | 36 Object *offset_table = debug_info->get(kWasmDebugInfoFunctionByteOffsets); |
29 Isolate *isolate = debug_info->GetIsolate(); | 37 Isolate *isolate = debug_info->GetIsolate(); |
30 if (!offset_table->IsUndefined(isolate)) return ByteArray::cast(offset_table); | 38 if (!offset_table->IsUndefined(isolate)) return ByteArray::cast(offset_table); |
31 | 39 |
32 FunctionOffsetsResult function_offsets; | 40 FunctionOffsetsResult function_offsets; |
33 { | 41 { |
(...skipping 27 matching lines...) Expand all Loading... |
61 | 69 |
62 int offset = arr->get_int(2 * func_index); | 70 int offset = arr->get_int(2 * func_index); |
63 int length = arr->get_int(2 * func_index + 1); | 71 int length = arr->get_int(2 * func_index + 1); |
64 // Assert that it's distinguishable from the "illegal function index" return. | 72 // Assert that it's distinguishable from the "illegal function index" return. |
65 DCHECK(offset > 0 && length > 0); | 73 DCHECK(offset > 0 && length > 0); |
66 return {offset, length}; | 74 return {offset, length}; |
67 } | 75 } |
68 | 76 |
69 Vector<const uint8_t> GetFunctionBytes(Handle<WasmDebugInfo> debug_info, | 77 Vector<const uint8_t> GetFunctionBytes(Handle<WasmDebugInfo> debug_info, |
70 int func_index) { | 78 int func_index) { |
| 79 std::pair<int, int> offset_and_length = |
| 80 GetFunctionOffsetAndLength(debug_info, func_index); |
71 SeqOneByteString *module_bytes = | 81 SeqOneByteString *module_bytes = |
72 wasm::GetWasmBytes(debug_info->wasm_object()); | 82 wasm::GetWasmBytes(debug_info->wasm_object()); |
73 std::pair<int, int> offset_and_length = | |
74 GetFunctionOffsetAndLength(debug_info, func_index); | |
75 return Vector<const uint8_t>( | 83 return Vector<const uint8_t>( |
76 module_bytes->GetChars() + offset_and_length.first, | 84 module_bytes->GetChars() + offset_and_length.first, |
77 offset_and_length.second); | 85 offset_and_length.second); |
78 } | 86 } |
79 | 87 |
| 88 FixedArray *GetOrCreateInterpretedFunctions(Handle<WasmDebugInfo> debug_info) { |
| 89 Object *maybe_arr = debug_info->get(kWasmDebugInfoInterpretedFunctions); |
| 90 Isolate *isolate = debug_info->GetIsolate(); |
| 91 if (!maybe_arr->IsUndefined(isolate)) return FixedArray::cast(maybe_arr); |
| 92 |
| 93 FixedArray *new_arr = *isolate->factory()->NewFixedArray( |
| 94 wasm::GetNumberOfFunctions(debug_info->wasm_object())); |
| 95 debug_info->set(kWasmDebugInfoInterpretedFunctions, new_arr); |
| 96 return new_arr; |
| 97 } |
| 98 |
| 99 void RedirectFunction(Code *code, Code *old_target, Code *new_target) { |
| 100 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); !it.done(); |
| 101 it.next()) { |
| 102 DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode())); |
| 103 Code *target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
| 104 if (target != old_target) continue; |
| 105 it.rinfo()->set_target_address(new_target->instruction_start(), |
| 106 SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH); |
| 107 } |
| 108 } |
| 109 |
| 110 void RedirectFunctionEverywhere(Handle<JSObject> wasm, Handle<Code> old_target, |
| 111 Handle<Code> new_target) { |
| 112 // Redirect in all wasm functions. |
| 113 for (int i = 0, e = wasm::GetNumberOfFunctions(*wasm); i < e; ++i) |
| 114 RedirectFunction(wasm::GetWasmFunctionCode(*wasm, i), *old_target, |
| 115 *new_target); |
| 116 |
| 117 // Redirect in the code of all exported functions. |
| 118 Isolate *isolate = wasm->GetIsolate(); |
| 119 // For AsmJs modules, the exports are stored on the wasm object itself. |
| 120 MaybeHandle<Object> maybe_exports = |
| 121 JSReceiver::GetProperty(isolate, wasm, "exports"); |
| 122 Handle<JSObject> exports_object = |
| 123 maybe_exports.is_null() |
| 124 ? wasm |
| 125 : Handle<JSObject>::cast(maybe_exports.ToHandleChecked()); |
| 126 |
| 127 Handle<FixedArray> values; |
| 128 if (JSReceiver::GetOwnValues(Handle<JSReceiver>::cast(exports_object), |
| 129 ALL_PROPERTIES) |
| 130 .ToHandle(&values)) { |
| 131 for (int i = 0, e = values->length(); i != e; ++i) { |
| 132 if (!values->get(i)->IsJSFunction()) continue; |
| 133 Code *code = JSFunction::cast(values->get(i))->code(); |
| 134 RedirectFunction(code, *old_target, *new_target); |
| 135 } |
| 136 } |
| 137 } |
| 138 |
| 139 class InterpreterHandle { |
| 140 v8::base::AccountingAllocator allocator; |
| 141 Zone zone; |
| 142 Handle<Object> global_ref; |
| 143 std::unique_ptr<const WasmModule> module; |
| 144 std::unique_ptr<WasmModuleInstance> module_instance; |
| 145 Isolate *isolate; |
| 146 |
| 147 uint8_t *parameter_buffer; |
| 148 uint32_t parameter_buffer_size = 0; |
| 149 #ifdef DEBUG |
| 150 // Track the function index for which the last buffer was allocated. |
| 151 // This is updated on AllocateParameterBuffer, and checked at Execute. |
| 152 uint32_t parameter_buffer_taken = static_cast<uint32_t>(-1); |
| 153 #endif |
| 154 |
| 155 public: |
| 156 WasmInterpreter interpreter; |
| 157 |
| 158 // Initialize in the right order. WasmInterpreter has to be allocate in place, |
| 159 // since it's not std::move'able. |
| 160 explicit InterpreterHandle(WasmDebugInfo *debug_info) |
| 161 : allocator(), |
| 162 zone(&allocator), |
| 163 module(CreateModule(&zone, debug_info)), |
| 164 isolate(debug_info->GetIsolate()), |
| 165 interpreter(CreateModuleInstance(module.get(), debug_info), &zone) { |
| 166 global_ref = debug_info->GetIsolate()->global_handles()->Create(debug_info); |
| 167 GlobalHandles::MakeWeak(global_ref.location(), this, |
| 168 InterpreterHandle::Finalize, |
| 169 v8::WeakCallbackType::kParameter); |
| 170 } |
| 171 |
| 172 static void Finalize(const v8::WeakCallbackInfo<void> &data) { |
| 173 void *param = data.GetParameter(); |
| 174 InterpreterHandle *handle = reinterpret_cast<InterpreterHandle *>(param); |
| 175 GlobalHandles::ClearWeakness(handle->global_ref.location()); |
| 176 GlobalHandles::Destroy(handle->global_ref.location()); |
| 177 delete handle; |
| 178 } |
| 179 |
| 180 static const WasmModule *CreateModule(Zone *zone, WasmDebugInfo *debug_info) { |
| 181 SeqOneByteString *wasm_bytes = |
| 182 wasm::GetWasmBytes(debug_info->wasm_object()); |
| 183 const byte *bytes_start = wasm_bytes->GetChars(); |
| 184 const byte *bytes_end = bytes_start + wasm_bytes->length(); |
| 185 ModuleResult module_result = |
| 186 DecodeWasmModule(debug_info->GetIsolate(), zone, bytes_start, bytes_end, |
| 187 false, ModuleOrigin::kWasmOrigin); |
| 188 DCHECK(module_result.ok()); |
| 189 return module_result.val; |
| 190 } |
| 191 |
| 192 static WasmModuleInstance *CreateModuleInstance(const WasmModule *module, |
| 193 WasmDebugInfo *debug_info) { |
| 194 JSArrayBuffer *memory = |
| 195 wasm::GetWasmMemoryBuffer(debug_info->wasm_object()); |
| 196 |
| 197 WasmModuleInstance *instance = new WasmModuleInstance(module); |
| 198 instance->mem_start = reinterpret_cast<byte *>(memory->backing_store()); |
| 199 instance->mem_size = memory->byte_length()->Number(); |
| 200 instance->mem_buffer = handle(memory, debug_info->GetIsolate()); |
| 201 |
| 202 return instance; |
| 203 } |
| 204 |
| 205 uint8_t *GetParameterBuffer(uint32_t function_index) { |
| 206 DCHECK_LE(function_index, module->functions.size()); |
| 207 DCHECK_EQ(static_cast<uint32_t>(-1), parameter_buffer_taken); |
| 208 #ifdef DEBUG |
| 209 parameter_buffer_taken = function_index; |
| 210 #endif |
| 211 uint32_t size_needed = 0; |
| 212 FunctionSig *sig = module->functions[function_index].sig; |
| 213 for (size_t i = 0, e = sig->parameter_count(); i != e; ++i) { |
| 214 size_needed += 1 << ElementSizeLog2Of(sig->GetParam(i)); |
| 215 } |
| 216 if (size_needed > parameter_buffer_size) { |
| 217 uint32_t alloc_size = 2 * parameter_buffer_size; |
| 218 if (size_needed > alloc_size) alloc_size = size_needed; |
| 219 parameter_buffer = zone.NewArray<uint8_t>(alloc_size); |
| 220 parameter_buffer_size = alloc_size; |
| 221 } |
| 222 return parameter_buffer; |
| 223 } |
| 224 |
| 225 void Execute(uint32_t func_index) { |
| 226 DCHECK_EQ(parameter_buffer_taken, func_index); |
| 227 #ifdef DEBUG |
| 228 parameter_buffer_taken = static_cast<uint32_t>(-1); |
| 229 #endif |
| 230 FunctionSig *sig = module->functions[func_index].sig; |
| 231 DCHECK_LE(sig->parameter_count(), static_cast<size_t>(kMaxInt)); |
| 232 int num_params = static_cast<int>(sig->parameter_count()); |
| 233 ScopedVector<WasmVal> wasm_args(num_params); |
| 234 uint8_t *buf_ptr = parameter_buffer; |
| 235 for (int i = 0; i < num_params; ++i) { |
| 236 uint32_t param_size = 1 << ElementSizeLog2Of(sig->GetParam(i)); |
| 237 switch (sig->GetParam(i)) { |
| 238 case kAstI32: |
| 239 DCHECK_EQ(param_size, sizeof(uint32_t)); |
| 240 wasm_args[i] = WasmVal(*reinterpret_cast<uint32_t *>(buf_ptr)); |
| 241 break; |
| 242 case kAstI64: |
| 243 DCHECK_EQ(param_size, sizeof(uint64_t)); |
| 244 wasm_args[i] = WasmVal(*reinterpret_cast<uint64_t *>(buf_ptr)); |
| 245 break; |
| 246 case kAstF32: |
| 247 DCHECK_EQ(param_size, sizeof(float)); |
| 248 wasm_args[i] = WasmVal(*reinterpret_cast<float *>(buf_ptr)); |
| 249 break; |
| 250 case kAstF64: |
| 251 DCHECK_EQ(param_size, sizeof(double)); |
| 252 wasm_args[i] = WasmVal(*reinterpret_cast<double *>(buf_ptr)); |
| 253 break; |
| 254 default: |
| 255 UNREACHABLE(); |
| 256 } |
| 257 buf_ptr += param_size; |
| 258 } |
| 259 |
| 260 WasmInterpreter::Thread *thread = interpreter.GetThread(0); |
| 261 // We do not support reentering an already running interpreter at the moment |
| 262 // (like INTERPRETER -> JS -> WASM -> INTERPRETER). |
| 263 DCHECK(thread->state() == WasmInterpreter::STOPPED || |
| 264 thread->state() == WasmInterpreter::FINISHED); |
| 265 thread->Reset(); |
| 266 thread->PushFrame(&module->functions[func_index], wasm_args.start()); |
| 267 WasmInterpreter::State state; |
| 268 do { |
| 269 state = thread->Run(); |
| 270 switch (state) { |
| 271 case WasmInterpreter::State::PAUSED: { |
| 272 // We hit a breakpoint. |
| 273 StackTraceFrameIterator frame_it(isolate); |
| 274 WasmInterpretedFrame *top_frame = |
| 275 WasmInterpretedFrame::cast(frame_it.frame()); |
| 276 isolate->debug()->Break(top_frame); |
| 277 } break; |
| 278 case WasmInterpreter::State::FINISHED: |
| 279 // Perfect, just break the switch and exit the loop. |
| 280 break; |
| 281 case WasmInterpreter::State::TRAPPED: |
| 282 // TODO(clemensh): Generate appropriate JS exception. |
| 283 UNIMPLEMENTED(); |
| 284 break; |
| 285 // STOPPED and RUNNING should never occur here. |
| 286 case WasmInterpreter::State::STOPPED: |
| 287 case WasmInterpreter::State::RUNNING: |
| 288 default: |
| 289 UNREACHABLE(); |
| 290 } |
| 291 } while (state != WasmInterpreter::State::FINISHED); |
| 292 } |
| 293 |
| 294 void EnsureInterpreterRedirect(Handle<WasmDebugInfo> debug_info, |
| 295 int func_index) { |
| 296 Isolate *isolate = debug_info->GetIsolate(); |
| 297 Handle<FixedArray> interpreted_functions( |
| 298 GetOrCreateInterpretedFunctions(debug_info), isolate); |
| 299 DCHECK_LT(func_index, interpreted_functions->length()); |
| 300 if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) return; |
| 301 |
| 302 Handle<JSObject> wasm(debug_info->wasm_object(), isolate); |
| 303 Handle<Code> new_code = compiler::CompileWasmToInterpreter( |
| 304 isolate, func_index, module->functions[func_index].sig, wasm); |
| 305 Handle<Code> old_code(wasm::GetWasmFunctionCode(*wasm, func_index), |
| 306 isolate); |
| 307 interpreted_functions->set(func_index, *new_code); |
| 308 |
| 309 RedirectFunctionEverywhere(wasm, old_code, new_code); |
| 310 } |
| 311 }; |
| 312 |
| 313 InterpreterHandle *GetOrCreateInterpreterHandle(WasmDebugInfo *debug_info) { |
| 314 DisallowHeapAllocation no_gc; |
| 315 // We store the raw pointer to the InterpreterHandle in a slot in the debug |
| 316 // info. |
| 317 // Since the pointer is aligned, it will look like a Smi, and the gc will |
| 318 // ignore it. |
| 319 Object *handle_obj = debug_info->get(kWasmDebugInfoInterpreterAddr); |
| 320 if (!handle_obj->IsUndefined(debug_info->GetIsolate())) { |
| 321 DCHECK(!handle_obj->IsHeapObject()); |
| 322 return reinterpret_cast<InterpreterHandle *>(handle_obj); |
| 323 } |
| 324 |
| 325 InterpreterHandle *handle = new InterpreterHandle(debug_info); |
| 326 handle_obj = reinterpret_cast<Object *>(handle); |
| 327 DCHECK(!handle_obj->IsHeapObject()); |
| 328 debug_info->set(kWasmDebugInfoInterpreterAddr, handle_obj); |
| 329 return handle; |
| 330 } |
| 331 |
| 332 InterpreterHandle *GetInterpreterHandleIfExists(WasmDebugInfo *debug_info) { |
| 333 DisallowHeapAllocation no_gc; |
| 334 Object *handle_obj = debug_info->get(kWasmDebugInfoInterpreterAddr); |
| 335 return handle_obj->IsUndefined(debug_info->GetIsolate()) |
| 336 ? nullptr |
| 337 : reinterpret_cast<InterpreterHandle *>(handle_obj); |
| 338 } |
| 339 |
80 } // namespace | 340 } // namespace |
81 | 341 |
| 342 WasmInstructionIterator::WasmInstructionIterator(const byte *start, |
| 343 const byte *end) |
| 344 : start_(start), end_(end) { |
| 345 base::AccountingAllocator allocator; |
| 346 Zone tmp_zone(&allocator); |
| 347 AstLocalDecls locals(&tmp_zone); |
| 348 bool valid = DecodeLocalDecls(locals, start, end); |
| 349 DCHECK(valid); |
| 350 USE(valid); |
| 351 pc_ = start + locals.decls_encoded_size; |
| 352 } |
| 353 |
| 354 void WasmInstructionIterator::Next() { |
| 355 DCHECK(!Done()); |
| 356 int len = OpcodeLength(pc_, end_); |
| 357 DCHECK_LE(0, len); // 0 means validation error / read past the end. |
| 358 pc_ += len; |
| 359 } |
| 360 |
| 361 Script *InterpreterFrameInfo::GetScript() const { |
| 362 return WasmDebugInfo::GetFunctionScript(debug_info_, func_index_); |
| 363 } |
| 364 |
| 365 InterpreterFrameIterator::InterpreterFrameIterator( |
| 366 Handle<WasmDebugInfo> debug_info) |
| 367 : frame_nr_(0), |
| 368 frame_count_(GetOrCreateInterpreterHandle(*debug_info) |
| 369 ->interpreter.GetThread(0) |
| 370 ->GetFrameCount()), |
| 371 debug_info_(debug_info) {} |
| 372 |
| 373 InterpreterFrameInfo InterpreterFrameIterator::GetFrameInfo() const { |
| 374 DCHECK(!Done()); |
| 375 WasmInterpreter::Thread *thread = |
| 376 GetOrCreateInterpreterHandle(*debug_info_)->interpreter.GetThread(0); |
| 377 DCHECK_EQ(frame_count_, thread->GetFrameCount()); |
| 378 DCHECK_LE(0, frame_nr_); |
| 379 std::unique_ptr<const WasmInterpreterFrame> frame( |
| 380 thread->GetFrame(frame_nr_)); |
| 381 return InterpreterFrameInfo(debug_info_, frame->function()->func_index, |
| 382 frame->pc()); |
| 383 } |
| 384 |
82 Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<JSObject> wasm) { | 385 Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<JSObject> wasm) { |
83 Isolate *isolate = wasm->GetIsolate(); | 386 Isolate *isolate = wasm->GetIsolate(); |
84 Factory *factory = isolate->factory(); | 387 Factory *factory = isolate->factory(); |
85 Handle<FixedArray> arr = | 388 Handle<FixedArray> arr = |
86 factory->NewFixedArray(kWasmDebugInfoNumEntries, TENURED); | 389 factory->NewFixedArray(kWasmDebugInfoNumEntries, TENURED); |
87 arr->set(kWasmDebugInfoWasmObj, *wasm); | 390 arr->set(kWasmDebugInfoWasmObj, *wasm); |
88 int hash = 0; | 391 int hash = 0; |
89 Handle<SeqOneByteString> wasm_bytes(GetWasmBytes(*wasm), isolate); | 392 Handle<SeqOneByteString> wasm_bytes(GetWasmBytes(*wasm), isolate); |
90 { | 393 { |
91 DisallowHeapAllocation no_gc; | 394 DisallowHeapAllocation no_gc; |
92 hash = StringHasher::HashSequentialString( | 395 hash = StringHasher::HashSequentialString( |
93 wasm_bytes->GetChars(), wasm_bytes->length(), kZeroHashSeed); | 396 wasm_bytes->GetChars(), wasm_bytes->length(), kZeroHashSeed); |
94 } | 397 } |
95 Handle<Object> hash_obj = factory->NewNumberFromInt(hash, TENURED); | 398 Handle<Object> hash_obj = factory->NewNumberFromInt(hash, TENURED); |
96 arr->set(kWasmDebugInfoWasmBytesHash, *hash_obj); | 399 arr->set(kWasmDebugInfoWasmBytesHash, *hash_obj); |
97 | 400 |
98 return Handle<WasmDebugInfo>::cast(arr); | 401 return Handle<WasmDebugInfo>::cast(arr); |
99 } | 402 } |
100 | 403 |
101 bool WasmDebugInfo::IsDebugInfo(Object *object) { | 404 bool WasmDebugInfo::IsWasmDebugInfo(Object *object) { |
102 if (!object->IsFixedArray()) return false; | 405 if (!object->IsFixedArray()) return false; |
103 FixedArray *arr = FixedArray::cast(object); | 406 FixedArray *arr = FixedArray::cast(object); |
104 Isolate *isolate = arr->GetIsolate(); | 407 Isolate *isolate = arr->GetIsolate(); |
105 return arr->length() == kWasmDebugInfoNumEntries && | 408 return arr->length() == kWasmDebugInfoNumEntries && |
106 IsWasmObject(arr->get(kWasmDebugInfoWasmObj)) && | 409 IsWasmObject(arr->get(kWasmDebugInfoWasmObj)) && |
107 arr->get(kWasmDebugInfoWasmBytesHash)->IsNumber() && | 410 arr->get(kWasmDebugInfoWasmBytesHash)->IsNumber() && |
108 (arr->get(kWasmDebugInfoFunctionByteOffsets)->IsUndefined(isolate) || | 411 (arr->get(kWasmDebugInfoFunctionByteOffsets)->IsUndefined(isolate) || |
109 arr->get(kWasmDebugInfoFunctionByteOffsets)->IsByteArray()) && | 412 arr->get(kWasmDebugInfoFunctionByteOffsets)->IsByteArray()) && |
110 (arr->get(kWasmDebugInfoFunctionScripts)->IsUndefined(isolate) || | 413 (arr->get(kWasmDebugInfoFunctionScripts)->IsUndefined(isolate) || |
111 arr->get(kWasmDebugInfoFunctionScripts)->IsFixedArray()); | 414 arr->get(kWasmDebugInfoFunctionScripts)->IsFixedArray()) && |
| 415 (arr->get(kWasmDebugInfoInterpretedFunctions)->IsUndefined(isolate) || |
| 416 arr->get(kWasmDebugInfoInterpretedFunctions)->IsFixedArray()) && |
| 417 (arr->get(kWasmDebugInfoDebugInfos)->IsUndefined(isolate) || |
| 418 arr->get(kWasmDebugInfoDebugInfos)->IsFixedArray()); |
112 } | 419 } |
113 | 420 |
114 WasmDebugInfo *WasmDebugInfo::cast(Object *object) { | 421 WasmDebugInfo *WasmDebugInfo::cast(Object *object) { |
115 DCHECK(IsDebugInfo(object)); | 422 DCHECK(IsWasmDebugInfo(object)); |
116 return reinterpret_cast<WasmDebugInfo *>(object); | 423 return reinterpret_cast<WasmDebugInfo *>(object); |
117 } | 424 } |
118 | 425 |
119 JSObject *WasmDebugInfo::wasm_object() { | 426 JSObject *WasmDebugInfo::wasm_object() { |
120 return JSObject::cast(get(kWasmDebugInfoWasmObj)); | 427 return JSObject::cast(get(kWasmDebugInfoWasmObj)); |
121 } | 428 } |
122 | 429 |
| 430 void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info, |
| 431 int func_index, int byte_offset) { |
| 432 DCHECK_LE(0, func_index); |
| 433 DCHECK_LE(0, byte_offset); |
| 434 InterpreterHandle *handle = GetOrCreateInterpreterHandle(*debug_info); |
| 435 handle->EnsureInterpreterRedirect(debug_info, func_index); |
| 436 handle->interpreter.SetBreakpoint(static_cast<uint32_t>(func_index), |
| 437 byte_offset, true); |
| 438 } |
| 439 |
| 440 bool WasmDebugInfo::HasBreakpoint(int func_index, int byte_offset) { |
| 441 DCHECK_LE(0, func_index); |
| 442 DCHECK_LE(0, byte_offset); |
| 443 InterpreterHandle *handle = GetInterpreterHandleIfExists(this); |
| 444 return handle && |
| 445 handle->interpreter.GetBreakpoint(static_cast<uint32_t>(func_index), |
| 446 byte_offset); |
| 447 } |
| 448 |
123 Script *WasmDebugInfo::GetFunctionScript(Handle<WasmDebugInfo> debug_info, | 449 Script *WasmDebugInfo::GetFunctionScript(Handle<WasmDebugInfo> debug_info, |
124 int func_index) { | 450 int func_index) { |
125 Isolate *isolate = debug_info->GetIsolate(); | 451 Isolate *isolate = debug_info->GetIsolate(); |
126 Object *scripts_obj = debug_info->get(kWasmDebugInfoFunctionScripts); | 452 Object *scripts_obj = debug_info->get(kWasmDebugInfoFunctionScripts); |
127 Handle<FixedArray> scripts; | 453 Handle<FixedArray> scripts; |
128 if (scripts_obj->IsUndefined(isolate)) { | 454 if (scripts_obj->IsUndefined(isolate)) { |
129 int num_functions = wasm::GetNumberOfFunctions(debug_info->wasm_object()); | 455 int num_functions = wasm::GetNumberOfFunctions(debug_info->wasm_object()); |
130 scripts = isolate->factory()->NewFixedArray(num_functions, TENURED); | 456 scripts = isolate->factory()->NewFixedArray(num_functions, TENURED); |
131 debug_info->set(kWasmDebugInfoFunctionScripts, *scripts); | 457 debug_info->set(kWasmDebugInfoFunctionScripts, *scripts); |
132 } else { | 458 } else { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 int idx = 0; | 547 int idx = 0; |
222 for (std::tuple<uint32_t, int, int> elem : offset_table_vec) { | 548 for (std::tuple<uint32_t, int, int> elem : offset_table_vec) { |
223 offset_table->set(idx++, Smi::FromInt(std::get<0>(elem))); | 549 offset_table->set(idx++, Smi::FromInt(std::get<0>(elem))); |
224 offset_table->set(idx++, Smi::FromInt(std::get<1>(elem))); | 550 offset_table->set(idx++, Smi::FromInt(std::get<1>(elem))); |
225 offset_table->set(idx++, Smi::FromInt(std::get<2>(elem))); | 551 offset_table->set(idx++, Smi::FromInt(std::get<2>(elem))); |
226 } | 552 } |
227 DCHECK_EQ(idx, offset_table->length()); | 553 DCHECK_EQ(idx, offset_table->length()); |
228 | 554 |
229 return offset_table; | 555 return offset_table; |
230 } | 556 } |
| 557 |
| 558 DebugInfo *WasmDebugInfo::GetDebugInfo(Handle<WasmDebugInfo> debug_info, |
| 559 int func_index) { |
| 560 Object *maybe_arr = debug_info->get(kWasmDebugInfoDebugInfos); |
| 561 Isolate *isolate = debug_info->GetIsolate(); |
| 562 Handle<FixedArray> arr; |
| 563 if (maybe_arr->IsUndefined(isolate)) { |
| 564 arr = isolate->factory()->NewFixedArray( |
| 565 wasm::GetNumberOfFunctions(debug_info->wasm_object())); |
| 566 debug_info->set(kWasmDebugInfoDebugInfos, *arr); |
| 567 } else { |
| 568 arr = handle(FixedArray::cast(maybe_arr)); |
| 569 } |
| 570 |
| 571 DCHECK_LE(func_index, static_cast<uint32_t>(arr->length())); |
| 572 Object *maybe_info = arr->get(static_cast<int>(func_index)); |
| 573 if (!maybe_info->IsUndefined(isolate)) return DebugInfo::cast(maybe_info); |
| 574 |
| 575 Handle<AbstractCode> code(AbstractCode::cast( |
| 576 wasm::GetWasmFunctionCode(debug_info->wasm_object(), func_index))); |
| 577 Handle<DebugInfo> new_debug_info = isolate->factory()->NewDebugInfo(code); |
| 578 arr->set(static_cast<int>(func_index), *new_debug_info); |
| 579 return *new_debug_info; |
| 580 } |
| 581 |
| 582 WasmDebugInfo::InstructionType WasmDebugInfo::GetInstructionType( |
| 583 int func_index, int byte_offset) { |
| 584 SeqOneByteString *bytes = wasm::GetWasmBytes(wasm_object()); |
| 585 DCHECK(byte_offset >= 0 && byte_offset < bytes->length()); |
| 586 switch (static_cast<WasmOpcode>(bytes->Get(byte_offset))) { |
| 587 case WasmOpcode::kExprReturn: |
| 588 return RETURN; |
| 589 case WasmOpcode::kExprCallImport: |
| 590 case WasmOpcode::kExprCallFunction: |
| 591 case WasmOpcode::kExprCallIndirect: |
| 592 return CALL; |
| 593 default: |
| 594 return OTHER; |
| 595 } |
| 596 } |
| 597 |
| 598 WasmInstructionIterator WasmDebugInfo::GetInstructionIterator( |
| 599 Handle<WasmDebugInfo> debug_info, int func_index) { |
| 600 Vector<const uint8_t> function_bytes = |
| 601 GetFunctionBytes(debug_info, func_index); |
| 602 |
| 603 return WasmInstructionIterator(function_bytes.start(), function_bytes.end()); |
| 604 } |
| 605 |
| 606 InterpreterFrameIterator WasmDebugInfo::GetInterpreterFrameIterator() { |
| 607 return InterpreterFrameIterator(handle(this)); |
| 608 } |
| 609 |
| 610 Object *WasmDebugInfo::GetInterpreterArgBuffer(int func_index) { |
| 611 printf("GetInterpreterArgBuffer %d\n", func_index); |
| 612 DCHECK_LE(0, func_index); |
| 613 InterpreterHandle *interp_handle = GetOrCreateInterpreterHandle(this); |
| 614 uint8_t *buf = |
| 615 interp_handle->GetParameterBuffer(static_cast<uint32_t>(func_index)); |
| 616 Object *obj = reinterpret_cast<Object *>(buf); |
| 617 DCHECK(!obj->IsHeapObject()); |
| 618 return obj; |
| 619 } |
| 620 |
| 621 void WasmDebugInfo::RunInterpreter(int func_index) { |
| 622 printf("RunInterpreter %d\n", func_index); |
| 623 DCHECK_LE(0, func_index); |
| 624 InterpreterHandle *interp_handle = GetOrCreateInterpreterHandle(this); |
| 625 interp_handle->Execute(static_cast<uint32_t>(func_index)); |
| 626 } |
OLD | NEW |