Chromium Code Reviews| 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/assembler-inl.h" | 5 #include "src/assembler-inl.h" |
| 6 #include "src/assert-scope.h" | 6 #include "src/assert-scope.h" |
| 7 #include "src/compiler/wasm-compiler.h" | 7 #include "src/compiler/wasm-compiler.h" |
| 8 #include "src/debug/debug.h" | 8 #include "src/debug/debug.h" |
| 9 #include "src/factory.h" | 9 #include "src/factory.h" |
| 10 #include "src/frames-inl.h" | 10 #include "src/frames-inl.h" |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 | 23 |
| 24 // Forward declaration. | 24 // Forward declaration. |
| 25 class InterpreterHandle; | 25 class InterpreterHandle; |
| 26 InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info); | 26 InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info); |
| 27 | 27 |
| 28 class InterpreterHandle { | 28 class InterpreterHandle { |
| 29 AccountingAllocator allocator_; | 29 AccountingAllocator allocator_; |
| 30 WasmInstance instance_; | 30 WasmInstance instance_; |
| 31 WasmInterpreter interpreter_; | 31 WasmInterpreter interpreter_; |
| 32 Isolate* isolate_; | 32 Isolate* isolate_; |
| 33 StepAction next_step_action_ = StepNone; | |
| 34 int last_step_stack_depth_ = 0; | |
| 33 | 35 |
| 34 public: | 36 public: |
| 35 // Initialize in the right order, using helper methods to make this possible. | 37 // Initialize in the right order, using helper methods to make this possible. |
| 36 // WasmInterpreter has to be allocated in place, since it is not movable. | 38 // WasmInterpreter has to be allocated in place, since it is not movable. |
| 37 InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info) | 39 InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info) |
| 38 : instance_(debug_info->wasm_instance()->compiled_module()->module()), | 40 : instance_(debug_info->wasm_instance()->compiled_module()->module()), |
| 39 interpreter_(GetBytesEnv(&instance_, debug_info), &allocator_), | 41 interpreter_(GetBytesEnv(&instance_, debug_info), &allocator_), |
| 40 isolate_(isolate) { | 42 isolate_(isolate) { |
| 41 if (debug_info->wasm_instance()->has_memory_buffer()) { | 43 if (debug_info->wasm_instance()->has_memory_buffer()) { |
| 42 JSArrayBuffer* mem_buffer = debug_info->wasm_instance()->memory_buffer(); | 44 JSArrayBuffer* mem_buffer = debug_info->wasm_instance()->memory_buffer(); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 56 // of this data anyway, and there is no heap allocation in-between. | 58 // of this data anyway, and there is no heap allocation in-between. |
| 57 SeqOneByteString* bytes_str = | 59 SeqOneByteString* bytes_str = |
| 58 debug_info->wasm_instance()->compiled_module()->module_bytes(); | 60 debug_info->wasm_instance()->compiled_module()->module_bytes(); |
| 59 Vector<const byte> bytes(bytes_str->GetChars(), bytes_str->length()); | 61 Vector<const byte> bytes(bytes_str->GetChars(), bytes_str->length()); |
| 60 return ModuleBytesEnv(instance->module, instance, bytes); | 62 return ModuleBytesEnv(instance->module, instance, bytes); |
| 61 } | 63 } |
| 62 | 64 |
| 63 WasmInterpreter* interpreter() { return &interpreter_; } | 65 WasmInterpreter* interpreter() { return &interpreter_; } |
| 64 const WasmModule* module() { return instance_.module; } | 66 const WasmModule* module() { return instance_.module; } |
| 65 | 67 |
| 68 void PrepareStep(StepAction step_action) { | |
| 69 next_step_action_ = step_action; | |
| 70 last_step_stack_depth_ = CurrentStackDepth(); | |
| 71 } | |
| 72 | |
| 73 void ClearStepping() { next_step_action_ = StepNone; } | |
| 74 | |
| 75 int CurrentStackDepth() { | |
| 76 DCHECK_EQ(1, interpreter()->GetThreadCount()); | |
| 77 return interpreter()->GetThread(0)->GetFrameCount(); | |
| 78 } | |
| 79 | |
| 66 void Execute(uint32_t func_index, uint8_t* arg_buffer) { | 80 void Execute(uint32_t func_index, uint8_t* arg_buffer) { |
| 67 DCHECK_GE(module()->functions.size(), func_index); | 81 DCHECK_GE(module()->functions.size(), func_index); |
| 68 FunctionSig* sig = module()->functions[func_index].sig; | 82 FunctionSig* sig = module()->functions[func_index].sig; |
| 69 DCHECK_GE(kMaxInt, sig->parameter_count()); | 83 DCHECK_GE(kMaxInt, sig->parameter_count()); |
| 70 int num_params = static_cast<int>(sig->parameter_count()); | 84 int num_params = static_cast<int>(sig->parameter_count()); |
| 71 ScopedVector<WasmVal> wasm_args(num_params); | 85 ScopedVector<WasmVal> wasm_args(num_params); |
| 72 uint8_t* arg_buf_ptr = arg_buffer; | 86 uint8_t* arg_buf_ptr = arg_buffer; |
| 73 for (int i = 0; i < num_params; ++i) { | 87 for (int i = 0; i < num_params; ++i) { |
| 74 uint32_t param_size = 1 << ElementSizeLog2Of(sig->GetParam(i)); | 88 uint32_t param_size = 1 << ElementSizeLog2Of(sig->GetParam(i)); |
| 75 #define CASE_ARG_TYPE(type, ctype) \ | 89 #define CASE_ARG_TYPE(type, ctype) \ |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 89 arg_buf_ptr += param_size; | 103 arg_buf_ptr += param_size; |
| 90 } | 104 } |
| 91 | 105 |
| 92 WasmInterpreter::Thread* thread = interpreter_.GetThread(0); | 106 WasmInterpreter::Thread* thread = interpreter_.GetThread(0); |
| 93 // We do not support reentering an already running interpreter at the moment | 107 // We do not support reentering an already running interpreter at the moment |
| 94 // (like INTERPRETER -> JS -> WASM -> INTERPRETER). | 108 // (like INTERPRETER -> JS -> WASM -> INTERPRETER). |
| 95 DCHECK(thread->state() == WasmInterpreter::STOPPED || | 109 DCHECK(thread->state() == WasmInterpreter::STOPPED || |
| 96 thread->state() == WasmInterpreter::FINISHED); | 110 thread->state() == WasmInterpreter::FINISHED); |
| 97 thread->Reset(); | 111 thread->Reset(); |
| 98 thread->PushFrame(&module()->functions[func_index], wasm_args.start()); | 112 thread->PushFrame(&module()->functions[func_index], wasm_args.start()); |
| 99 WasmInterpreter::State state; | 113 bool finished = false; |
|
titzer
2017/01/23 10:10:10
Can you drop in a TODO here that the interpreter r
Clemens Hammacher
2017/01/23 12:25:34
Done.
| |
| 100 do { | 114 while (!finished) { |
| 101 state = thread->Run(); | 115 WasmInterpreter::State state = ContinueExecution(thread); |
| 102 switch (state) { | 116 switch (state) { |
| 103 case WasmInterpreter::State::PAUSED: | 117 case WasmInterpreter::State::PAUSED: |
| 104 NotifyDebugEventListeners(); | 118 NotifyDebugEventListeners(thread); |
| 105 break; | 119 break; |
| 106 case WasmInterpreter::State::FINISHED: | 120 case WasmInterpreter::State::FINISHED: |
| 107 // Perfect, just break the switch and exit the loop. | 121 // Perfect, just break the switch and exit the loop. |
| 122 finished = true; | |
| 108 break; | 123 break; |
| 109 case WasmInterpreter::State::TRAPPED: | 124 case WasmInterpreter::State::TRAPPED: |
| 110 // TODO(clemensh): Generate appropriate JS exception. | 125 // TODO(clemensh): Generate appropriate JS exception. |
| 111 UNIMPLEMENTED(); | 126 UNIMPLEMENTED(); |
| 112 break; | 127 break; |
| 113 // STOPPED and RUNNING should never occur here. | 128 // STOPPED and RUNNING should never occur here. |
| 114 case WasmInterpreter::State::STOPPED: | 129 case WasmInterpreter::State::STOPPED: |
| 115 case WasmInterpreter::State::RUNNING: | 130 case WasmInterpreter::State::RUNNING: |
| 116 default: | 131 default: |
| 117 UNREACHABLE(); | 132 UNREACHABLE(); |
| 118 } | 133 } |
| 119 } while (state != WasmInterpreter::State::FINISHED); | 134 } |
| 120 | 135 |
| 121 // Copy back the return value | 136 // Copy back the return value |
| 122 DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count()); | 137 DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count()); |
| 123 // TODO(wasm): Handle multi-value returns. | 138 // TODO(wasm): Handle multi-value returns. |
| 124 DCHECK_EQ(1, kV8MaxWasmFunctionReturns); | 139 DCHECK_EQ(1, kV8MaxWasmFunctionReturns); |
| 125 if (sig->return_count()) { | 140 if (sig->return_count()) { |
| 126 WasmVal ret_val = thread->GetReturnValue(0); | 141 WasmVal ret_val = thread->GetReturnValue(0); |
| 127 #define CASE_RET_TYPE(type, ctype) \ | 142 #define CASE_RET_TYPE(type, ctype) \ |
| 128 case type: \ | 143 case type: \ |
| 129 DCHECK_EQ(1 << ElementSizeLog2Of(sig->GetReturn(0)), sizeof(ctype)); \ | 144 DCHECK_EQ(1 << ElementSizeLog2Of(sig->GetReturn(0)), sizeof(ctype)); \ |
| 130 *reinterpret_cast<ctype*>(arg_buffer) = ret_val.to<ctype>(); \ | 145 *reinterpret_cast<ctype*>(arg_buffer) = ret_val.to<ctype>(); \ |
| 131 break; | 146 break; |
| 132 switch (sig->GetReturn(0)) { | 147 switch (sig->GetReturn(0)) { |
| 133 CASE_RET_TYPE(kWasmI32, uint32_t) | 148 CASE_RET_TYPE(kWasmI32, uint32_t) |
| 134 CASE_RET_TYPE(kWasmI64, uint64_t) | 149 CASE_RET_TYPE(kWasmI64, uint64_t) |
| 135 CASE_RET_TYPE(kWasmF32, float) | 150 CASE_RET_TYPE(kWasmF32, float) |
| 136 CASE_RET_TYPE(kWasmF64, double) | 151 CASE_RET_TYPE(kWasmF64, double) |
| 137 #undef CASE_RET_TYPE | 152 #undef CASE_RET_TYPE |
| 138 default: | 153 default: |
| 139 UNREACHABLE(); | 154 UNREACHABLE(); |
| 140 } | 155 } |
| 141 } | 156 } |
| 142 } | 157 } |
| 143 | 158 |
| 159 WasmInterpreter::State ContinueExecution(WasmInterpreter::Thread* thread) { | |
| 160 switch (next_step_action_) { | |
| 161 case StepNone: | |
| 162 return thread->Run(); | |
| 163 case StepIn: | |
| 164 return thread->Step(); | |
| 165 case StepOut: | |
| 166 thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterReturn); | |
| 167 return thread->Step(); | |
| 168 case StepNext: { | |
| 169 int stack_depth = thread->GetFrameCount(); | |
| 170 if (stack_depth == last_step_stack_depth_) return thread->Step(); | |
| 171 thread->AddBreakFlags(stack_depth > last_step_stack_depth_ | |
| 172 ? WasmInterpreter::BreakFlag::AfterReturn | |
| 173 : WasmInterpreter::BreakFlag::AfterCall); | |
| 174 return thread->Run(); | |
| 175 } | |
| 176 case StepFrame: | |
| 177 thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterCall | | |
| 178 WasmInterpreter::BreakFlag::AfterReturn); | |
| 179 return thread->Run(); | |
| 180 default: | |
| 181 UNREACHABLE(); | |
| 182 return WasmInterpreter::STOPPED; | |
| 183 } | |
| 184 } | |
| 185 | |
| 144 Handle<WasmInstanceObject> GetInstanceObject() { | 186 Handle<WasmInstanceObject> GetInstanceObject() { |
| 145 StackTraceFrameIterator it(isolate_); | 187 StackTraceFrameIterator it(isolate_); |
| 146 WasmInterpreterEntryFrame* frame = | 188 WasmInterpreterEntryFrame* frame = |
| 147 WasmInterpreterEntryFrame::cast(it.frame()); | 189 WasmInterpreterEntryFrame::cast(it.frame()); |
| 148 Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_); | 190 Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_); |
| 149 DCHECK_EQ(this, GetInterpreterHandle(instance_obj->debug_info())); | 191 DCHECK_EQ(this, GetInterpreterHandle(instance_obj->debug_info())); |
| 150 return instance_obj; | 192 return instance_obj; |
| 151 } | 193 } |
| 152 | 194 |
| 153 void NotifyDebugEventListeners() { | 195 void NotifyDebugEventListeners(WasmInterpreter::Thread* thread) { |
| 154 // Enter the debugger. | 196 // Enter the debugger. |
| 155 DebugScope debug_scope(isolate_->debug()); | 197 DebugScope debug_scope(isolate_->debug()); |
| 156 if (debug_scope.failed()) return; | 198 if (debug_scope.failed()) return; |
| 157 | 199 |
| 158 // Postpone interrupt during breakpoint processing. | 200 // Postpone interrupt during breakpoint processing. |
| 159 PostponeInterruptsScope postpone(isolate_); | 201 PostponeInterruptsScope postpone(isolate_); |
| 160 | 202 |
| 161 // If we are paused on a breakpoint, clear all stepping and notify the | 203 // Check whether we hit a breakpoint. |
| 162 // listeners. | |
| 163 Handle<WasmCompiledModule> compiled_module( | |
| 164 GetInstanceObject()->compiled_module(), isolate_); | |
| 165 int position = GetTopPosition(compiled_module); | |
| 166 MaybeHandle<FixedArray> hit_breakpoints; | |
| 167 if (isolate_->debug()->break_points_active()) { | 204 if (isolate_->debug()->break_points_active()) { |
| 168 hit_breakpoints = compiled_module->CheckBreakPoints(position); | 205 Handle<WasmCompiledModule> compiled_module( |
|
titzer
2017/01/23 10:10:10
Should probably discuss more about how this works,
Clemens Hammacher
2017/01/23 12:25:34
Breakpoints are currently still created from JS, a
| |
| 206 GetInstanceObject()->compiled_module(), isolate_); | |
| 207 int position = GetTopPosition(compiled_module); | |
| 208 Handle<FixedArray> breakpoints; | |
| 209 if (compiled_module->CheckBreakPoints(position).ToHandle(&breakpoints)) { | |
| 210 // We hit one or several breakpoints. Clear stepping, notify the | |
| 211 // listeners and return. | |
| 212 ClearStepping(); | |
| 213 Handle<Object> hit_breakpoints_js = | |
| 214 isolate_->factory()->NewJSArrayWithElements(breakpoints); | |
| 215 isolate_->debug()->OnDebugBreak(hit_breakpoints_js, false); | |
| 216 return; | |
| 217 } | |
| 169 } | 218 } |
| 170 | 219 |
| 171 // If we hit a breakpoint, pass a JSArray with all breakpoints, otherwise | 220 // We did not hit a breakpoint, so maybe this pause is related to stepping. |
| 172 // pass undefined. | 221 bool hit_step = false; |
| 173 Handle<Object> hit_breakpoints_js; | 222 switch (next_step_action_) { |
| 174 if (hit_breakpoints.is_null()) { | 223 case StepNone: |
| 175 hit_breakpoints_js = isolate_->factory()->undefined_value(); | 224 break; |
| 176 } else { | 225 case StepIn: |
| 177 hit_breakpoints_js = isolate_->factory()->NewJSArrayWithElements( | 226 hit_step = true; |
| 178 hit_breakpoints.ToHandleChecked()); | 227 break; |
| 228 case StepOut: | |
| 229 hit_step = thread->GetFrameCount() < last_step_stack_depth_; | |
| 230 break; | |
| 231 case StepNext: { | |
| 232 hit_step = thread->GetFrameCount() == last_step_stack_depth_; | |
| 233 break; | |
| 234 } | |
| 235 case StepFrame: | |
| 236 hit_step = thread->GetFrameCount() != last_step_stack_depth_; | |
| 237 break; | |
| 238 default: | |
| 239 UNREACHABLE(); | |
| 179 } | 240 } |
| 180 | 241 if (!hit_step) return; |
| 181 isolate_->debug()->OnDebugBreak(hit_breakpoints_js, false); | 242 ClearStepping(); |
| 243 isolate_->debug()->OnDebugBreak(isolate_->factory()->undefined_value(), | |
| 244 false); | |
| 182 } | 245 } |
| 183 | 246 |
| 184 int GetTopPosition(Handle<WasmCompiledModule> compiled_module) { | 247 int GetTopPosition(Handle<WasmCompiledModule> compiled_module) { |
| 185 DCHECK_EQ(1, interpreter()->GetThreadCount()); | 248 DCHECK_EQ(1, interpreter()->GetThreadCount()); |
| 186 WasmInterpreter::Thread* thread = interpreter()->GetThread(0); | 249 WasmInterpreter::Thread* thread = interpreter()->GetThread(0); |
| 187 DCHECK_LT(0, thread->GetFrameCount()); | 250 DCHECK_LT(0, thread->GetFrameCount()); |
| 188 | 251 |
| 189 wasm::InterpretedFrame frame = | 252 wasm::InterpretedFrame frame = |
| 190 thread->GetFrame(thread->GetFrameCount() - 1); | 253 thread->GetFrame(thread->GetFrameCount() - 1); |
| 191 return compiled_module->GetFunctionOffset(frame.function()->func_index) + | 254 return compiled_module->GetFunctionOffset(frame.function()->func_index) + |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 345 Isolate* isolate = debug_info->GetIsolate(); | 408 Isolate* isolate = debug_info->GetIsolate(); |
| 346 InterpreterHandle* handle = GetOrCreateInterpreterHandle(isolate, debug_info); | 409 InterpreterHandle* handle = GetOrCreateInterpreterHandle(isolate, debug_info); |
| 347 WasmInterpreter* interpreter = handle->interpreter(); | 410 WasmInterpreter* interpreter = handle->interpreter(); |
| 348 DCHECK_LE(0, func_index); | 411 DCHECK_LE(0, func_index); |
| 349 DCHECK_GT(handle->module()->functions.size(), func_index); | 412 DCHECK_GT(handle->module()->functions.size(), func_index); |
| 350 const WasmFunction* func = &handle->module()->functions[func_index]; | 413 const WasmFunction* func = &handle->module()->functions[func_index]; |
| 351 interpreter->SetBreakpoint(func, offset, true); | 414 interpreter->SetBreakpoint(func, offset, true); |
| 352 EnsureRedirectToInterpreter(isolate, debug_info, func_index); | 415 EnsureRedirectToInterpreter(isolate, debug_info, func_index); |
| 353 } | 416 } |
| 354 | 417 |
| 418 void WasmDebugInfo::PrepareStep(StepAction step_action) { | |
| 419 GetInterpreterHandle(this)->PrepareStep(step_action); | |
| 420 } | |
| 421 | |
| 355 void WasmDebugInfo::RunInterpreter(int func_index, uint8_t* arg_buffer) { | 422 void WasmDebugInfo::RunInterpreter(int func_index, uint8_t* arg_buffer) { |
| 356 DCHECK_LE(0, func_index); | 423 DCHECK_LE(0, func_index); |
| 357 GetInterpreterHandle(this)->Execute(static_cast<uint32_t>(func_index), | 424 GetInterpreterHandle(this)->Execute(static_cast<uint32_t>(func_index), |
| 358 arg_buffer); | 425 arg_buffer); |
| 359 } | 426 } |
| 360 | 427 |
| 361 std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack( | 428 std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack( |
| 362 Address frame_pointer) { | 429 Address frame_pointer) { |
| 363 return GetInterpreterHandle(this)->GetInterpretedStack(frame_pointer); | 430 return GetInterpreterHandle(this)->GetInterpretedStack(frame_pointer); |
| 364 } | 431 } |
| 365 | 432 |
| 366 std::unique_ptr<wasm::InterpretedFrame> WasmDebugInfo::GetInterpretedFrame( | 433 std::unique_ptr<wasm::InterpretedFrame> WasmDebugInfo::GetInterpretedFrame( |
| 367 Address frame_pointer, int idx) { | 434 Address frame_pointer, int idx) { |
| 368 return GetInterpreterHandle(this)->GetInterpretedFrame(frame_pointer, idx); | 435 return GetInterpreterHandle(this)->GetInterpretedFrame(frame_pointer, idx); |
| 369 } | 436 } |
| OLD | NEW |