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; |
100 do { | 114 while (!finished) { |
101 state = thread->Run(); | 115 // TODO(clemensh): Add occasional StackChecks. |
| 116 WasmInterpreter::State state = ContinueExecution(thread); |
102 switch (state) { | 117 switch (state) { |
103 case WasmInterpreter::State::PAUSED: | 118 case WasmInterpreter::State::PAUSED: |
104 NotifyDebugEventListeners(); | 119 NotifyDebugEventListeners(thread); |
105 break; | 120 break; |
106 case WasmInterpreter::State::FINISHED: | 121 case WasmInterpreter::State::FINISHED: |
107 // Perfect, just break the switch and exit the loop. | 122 // Perfect, just break the switch and exit the loop. |
| 123 finished = true; |
108 break; | 124 break; |
109 case WasmInterpreter::State::TRAPPED: | 125 case WasmInterpreter::State::TRAPPED: |
110 // TODO(clemensh): Generate appropriate JS exception. | 126 // TODO(clemensh): Generate appropriate JS exception. |
111 UNIMPLEMENTED(); | 127 UNIMPLEMENTED(); |
112 break; | 128 break; |
113 // STOPPED and RUNNING should never occur here. | 129 // STOPPED and RUNNING should never occur here. |
114 case WasmInterpreter::State::STOPPED: | 130 case WasmInterpreter::State::STOPPED: |
115 case WasmInterpreter::State::RUNNING: | 131 case WasmInterpreter::State::RUNNING: |
116 default: | 132 default: |
117 UNREACHABLE(); | 133 UNREACHABLE(); |
118 } | 134 } |
119 } while (state != WasmInterpreter::State::FINISHED); | 135 } |
120 | 136 |
121 // Copy back the return value | 137 // Copy back the return value |
122 DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count()); | 138 DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count()); |
123 // TODO(wasm): Handle multi-value returns. | 139 // TODO(wasm): Handle multi-value returns. |
124 DCHECK_EQ(1, kV8MaxWasmFunctionReturns); | 140 DCHECK_EQ(1, kV8MaxWasmFunctionReturns); |
125 if (sig->return_count()) { | 141 if (sig->return_count()) { |
126 WasmVal ret_val = thread->GetReturnValue(0); | 142 WasmVal ret_val = thread->GetReturnValue(0); |
127 #define CASE_RET_TYPE(type, ctype) \ | 143 #define CASE_RET_TYPE(type, ctype) \ |
128 case type: \ | 144 case type: \ |
129 DCHECK_EQ(1 << ElementSizeLog2Of(sig->GetReturn(0)), sizeof(ctype)); \ | 145 DCHECK_EQ(1 << ElementSizeLog2Of(sig->GetReturn(0)), sizeof(ctype)); \ |
130 *reinterpret_cast<ctype*>(arg_buffer) = ret_val.to<ctype>(); \ | 146 *reinterpret_cast<ctype*>(arg_buffer) = ret_val.to<ctype>(); \ |
131 break; | 147 break; |
132 switch (sig->GetReturn(0)) { | 148 switch (sig->GetReturn(0)) { |
133 CASE_RET_TYPE(kWasmI32, uint32_t) | 149 CASE_RET_TYPE(kWasmI32, uint32_t) |
134 CASE_RET_TYPE(kWasmI64, uint64_t) | 150 CASE_RET_TYPE(kWasmI64, uint64_t) |
135 CASE_RET_TYPE(kWasmF32, float) | 151 CASE_RET_TYPE(kWasmF32, float) |
136 CASE_RET_TYPE(kWasmF64, double) | 152 CASE_RET_TYPE(kWasmF64, double) |
137 #undef CASE_RET_TYPE | 153 #undef CASE_RET_TYPE |
138 default: | 154 default: |
139 UNREACHABLE(); | 155 UNREACHABLE(); |
140 } | 156 } |
141 } | 157 } |
142 } | 158 } |
143 | 159 |
| 160 WasmInterpreter::State ContinueExecution(WasmInterpreter::Thread* thread) { |
| 161 switch (next_step_action_) { |
| 162 case StepNone: |
| 163 return thread->Run(); |
| 164 case StepIn: |
| 165 return thread->Step(); |
| 166 case StepOut: |
| 167 thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterReturn); |
| 168 return thread->Step(); |
| 169 case StepNext: { |
| 170 int stack_depth = thread->GetFrameCount(); |
| 171 if (stack_depth == last_step_stack_depth_) return thread->Step(); |
| 172 thread->AddBreakFlags(stack_depth > last_step_stack_depth_ |
| 173 ? WasmInterpreter::BreakFlag::AfterReturn |
| 174 : WasmInterpreter::BreakFlag::AfterCall); |
| 175 return thread->Run(); |
| 176 } |
| 177 case StepFrame: |
| 178 thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterCall | |
| 179 WasmInterpreter::BreakFlag::AfterReturn); |
| 180 return thread->Run(); |
| 181 default: |
| 182 UNREACHABLE(); |
| 183 return WasmInterpreter::STOPPED; |
| 184 } |
| 185 } |
| 186 |
144 Handle<WasmInstanceObject> GetInstanceObject() { | 187 Handle<WasmInstanceObject> GetInstanceObject() { |
145 StackTraceFrameIterator it(isolate_); | 188 StackTraceFrameIterator it(isolate_); |
146 WasmInterpreterEntryFrame* frame = | 189 WasmInterpreterEntryFrame* frame = |
147 WasmInterpreterEntryFrame::cast(it.frame()); | 190 WasmInterpreterEntryFrame::cast(it.frame()); |
148 Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_); | 191 Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_); |
149 DCHECK_EQ(this, GetInterpreterHandle(instance_obj->debug_info())); | 192 DCHECK_EQ(this, GetInterpreterHandle(instance_obj->debug_info())); |
150 return instance_obj; | 193 return instance_obj; |
151 } | 194 } |
152 | 195 |
153 void NotifyDebugEventListeners() { | 196 void NotifyDebugEventListeners(WasmInterpreter::Thread* thread) { |
154 // Enter the debugger. | 197 // Enter the debugger. |
155 DebugScope debug_scope(isolate_->debug()); | 198 DebugScope debug_scope(isolate_->debug()); |
156 if (debug_scope.failed()) return; | 199 if (debug_scope.failed()) return; |
157 | 200 |
158 // Postpone interrupt during breakpoint processing. | 201 // Postpone interrupt during breakpoint processing. |
159 PostponeInterruptsScope postpone(isolate_); | 202 PostponeInterruptsScope postpone(isolate_); |
160 | 203 |
161 // If we are paused on a breakpoint, clear all stepping and notify the | 204 // 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()) { | 205 if (isolate_->debug()->break_points_active()) { |
168 hit_breakpoints = compiled_module->CheckBreakPoints(position); | 206 Handle<WasmCompiledModule> compiled_module( |
| 207 GetInstanceObject()->compiled_module(), isolate_); |
| 208 int position = GetTopPosition(compiled_module); |
| 209 Handle<FixedArray> breakpoints; |
| 210 if (compiled_module->CheckBreakPoints(position).ToHandle(&breakpoints)) { |
| 211 // We hit one or several breakpoints. Clear stepping, notify the |
| 212 // listeners and return. |
| 213 ClearStepping(); |
| 214 Handle<Object> hit_breakpoints_js = |
| 215 isolate_->factory()->NewJSArrayWithElements(breakpoints); |
| 216 isolate_->debug()->OnDebugBreak(hit_breakpoints_js); |
| 217 return; |
| 218 } |
169 } | 219 } |
170 | 220 |
171 // If we hit a breakpoint, pass a JSArray with all breakpoints, otherwise | 221 // We did not hit a breakpoint, so maybe this pause is related to stepping. |
172 // pass undefined. | 222 bool hit_step = false; |
173 Handle<Object> hit_breakpoints_js; | 223 switch (next_step_action_) { |
174 if (hit_breakpoints.is_null()) { | 224 case StepNone: |
175 hit_breakpoints_js = isolate_->factory()->undefined_value(); | 225 break; |
176 } else { | 226 case StepIn: |
177 hit_breakpoints_js = isolate_->factory()->NewJSArrayWithElements( | 227 hit_step = true; |
178 hit_breakpoints.ToHandleChecked()); | 228 break; |
| 229 case StepOut: |
| 230 hit_step = thread->GetFrameCount() < last_step_stack_depth_; |
| 231 break; |
| 232 case StepNext: { |
| 233 hit_step = thread->GetFrameCount() == last_step_stack_depth_; |
| 234 break; |
| 235 } |
| 236 case StepFrame: |
| 237 hit_step = thread->GetFrameCount() != last_step_stack_depth_; |
| 238 break; |
| 239 default: |
| 240 UNREACHABLE(); |
179 } | 241 } |
180 | 242 if (!hit_step) return; |
181 isolate_->debug()->OnDebugBreak(hit_breakpoints_js); | 243 ClearStepping(); |
| 244 isolate_->debug()->OnDebugBreak(isolate_->factory()->undefined_value()); |
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 |