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

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

Issue 2649533002: [wasm] Implement stepping in wasm code (Closed)
Patch Set: Rebase 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
« no previous file with comments | « src/runtime/runtime-debug.cc ('k') | src/wasm/wasm-interpreter.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
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
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
« no previous file with comments | « src/runtime/runtime-debug.cc ('k') | src/wasm/wasm-interpreter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698