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 |