Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/wasm/wasm-debug.cc

Issue 2649533002: [wasm] Implement stepping in wasm code (Closed)
Patch Set: Add TODOs Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698