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" |
11 #include "src/isolate.h" | 11 #include "src/isolate.h" |
12 #include "src/wasm/module-decoder.h" | 12 #include "src/wasm/module-decoder.h" |
13 #include "src/wasm/wasm-interpreter.h" | 13 #include "src/wasm/wasm-interpreter.h" |
14 #include "src/wasm/wasm-limits.h" | 14 #include "src/wasm/wasm-limits.h" |
15 #include "src/wasm/wasm-module.h" | 15 #include "src/wasm/wasm-module.h" |
16 #include "src/wasm/wasm-objects.h" | 16 #include "src/wasm/wasm-objects.h" |
17 #include "src/zone/accounting-allocator.h" | 17 #include "src/zone/accounting-allocator.h" |
18 | 18 |
19 using namespace v8::internal; | 19 using namespace v8::internal; |
20 using namespace v8::internal::wasm; | 20 using namespace v8::internal::wasm; |
21 | 21 |
22 namespace { | 22 namespace { |
23 | 23 |
| 24 // Forward declaration. |
| 25 class InterpreterHandle; |
| 26 InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info); |
| 27 |
24 class InterpreterHandle { | 28 class InterpreterHandle { |
25 AccountingAllocator allocator_; | 29 AccountingAllocator allocator_; |
26 WasmInstance instance_; | 30 WasmInstance instance_; |
27 WasmInterpreter interpreter_; | 31 WasmInterpreter interpreter_; |
| 32 Isolate* isolate_; |
28 | 33 |
29 public: | 34 public: |
30 // Initialize in the right order, using helper methods to make this possible. | 35 // Initialize in the right order, using helper methods to make this possible. |
31 // WasmInterpreter has to be allocated in place, since it is not movable. | 36 // WasmInterpreter has to be allocated in place, since it is not movable. |
32 InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info) | 37 InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info) |
33 : instance_(debug_info->wasm_instance()->compiled_module()->module()), | 38 : instance_(debug_info->wasm_instance()->compiled_module()->module()), |
34 interpreter_(GetBytesEnv(&instance_, debug_info), &allocator_) { | 39 interpreter_(GetBytesEnv(&instance_, debug_info), &allocator_), |
| 40 isolate_(isolate) { |
35 Handle<JSArrayBuffer> mem_buffer = | 41 Handle<JSArrayBuffer> mem_buffer = |
36 handle(debug_info->wasm_instance()->memory_buffer(), isolate); | 42 handle(debug_info->wasm_instance()->memory_buffer(), isolate); |
37 if (mem_buffer->IsUndefined(isolate)) { | 43 if (mem_buffer->IsUndefined(isolate)) { |
38 DCHECK_EQ(0, instance_.module->min_mem_pages); | 44 DCHECK_EQ(0, instance_.module->min_mem_pages); |
39 instance_.mem_start = nullptr; | 45 instance_.mem_start = nullptr; |
40 instance_.mem_size = 0; | 46 instance_.mem_size = 0; |
41 } else { | 47 } else { |
42 instance_.mem_start = | 48 instance_.mem_start = |
43 reinterpret_cast<byte*>(mem_buffer->backing_store()); | 49 reinterpret_cast<byte*>(mem_buffer->backing_store()); |
44 CHECK(mem_buffer->byte_length()->ToUint32(&instance_.mem_size)); | 50 CHECK(mem_buffer->byte_length()->ToUint32(&instance_.mem_size)); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 // We do not support reentering an already running interpreter at the moment | 94 // We do not support reentering an already running interpreter at the moment |
89 // (like INTERPRETER -> JS -> WASM -> INTERPRETER). | 95 // (like INTERPRETER -> JS -> WASM -> INTERPRETER). |
90 DCHECK(thread->state() == WasmInterpreter::STOPPED || | 96 DCHECK(thread->state() == WasmInterpreter::STOPPED || |
91 thread->state() == WasmInterpreter::FINISHED); | 97 thread->state() == WasmInterpreter::FINISHED); |
92 thread->Reset(); | 98 thread->Reset(); |
93 thread->PushFrame(&module()->functions[func_index], wasm_args.start()); | 99 thread->PushFrame(&module()->functions[func_index], wasm_args.start()); |
94 WasmInterpreter::State state; | 100 WasmInterpreter::State state; |
95 do { | 101 do { |
96 state = thread->Run(); | 102 state = thread->Run(); |
97 switch (state) { | 103 switch (state) { |
98 case WasmInterpreter::State::PAUSED: { | 104 case WasmInterpreter::State::PAUSED: |
99 // We hit a breakpoint. | 105 NotifyDebugEventListeners(); |
100 // TODO(clemensh): Handle this. | 106 break; |
101 } break; | |
102 case WasmInterpreter::State::FINISHED: | 107 case WasmInterpreter::State::FINISHED: |
103 // Perfect, just break the switch and exit the loop. | 108 // Perfect, just break the switch and exit the loop. |
104 break; | 109 break; |
105 case WasmInterpreter::State::TRAPPED: | 110 case WasmInterpreter::State::TRAPPED: |
106 // TODO(clemensh): Generate appropriate JS exception. | 111 // TODO(clemensh): Generate appropriate JS exception. |
107 UNIMPLEMENTED(); | 112 UNIMPLEMENTED(); |
108 break; | 113 break; |
109 // STOPPED and RUNNING should never occur here. | 114 // STOPPED and RUNNING should never occur here. |
110 case WasmInterpreter::State::STOPPED: | 115 case WasmInterpreter::State::STOPPED: |
111 case WasmInterpreter::State::RUNNING: | 116 case WasmInterpreter::State::RUNNING: |
(...skipping 17 matching lines...) Expand all Loading... |
129 CASE_RET_TYPE(kWasmI32, uint32_t) | 134 CASE_RET_TYPE(kWasmI32, uint32_t) |
130 CASE_RET_TYPE(kWasmI64, uint64_t) | 135 CASE_RET_TYPE(kWasmI64, uint64_t) |
131 CASE_RET_TYPE(kWasmF32, float) | 136 CASE_RET_TYPE(kWasmF32, float) |
132 CASE_RET_TYPE(kWasmF64, double) | 137 CASE_RET_TYPE(kWasmF64, double) |
133 #undef CASE_RET_TYPE | 138 #undef CASE_RET_TYPE |
134 default: | 139 default: |
135 UNREACHABLE(); | 140 UNREACHABLE(); |
136 } | 141 } |
137 } | 142 } |
138 } | 143 } |
| 144 |
| 145 Handle<WasmInstanceObject> GetInstanceObject() { |
| 146 StackTraceFrameIterator it(isolate_); |
| 147 WasmInterpreterEntryFrame* frame = |
| 148 WasmInterpreterEntryFrame::cast(it.frame()); |
| 149 Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_); |
| 150 DCHECK_EQ(this, GetInterpreterHandle(instance_obj->debug_info())); |
| 151 return instance_obj; |
| 152 } |
| 153 |
| 154 void NotifyDebugEventListeners() { |
| 155 // Enter the debugger. |
| 156 DebugScope debug_scope(isolate_->debug()); |
| 157 if (debug_scope.failed()) return; |
| 158 |
| 159 // Postpone interrupt during breakpoint processing. |
| 160 PostponeInterruptsScope postpone(isolate_); |
| 161 |
| 162 // If we are paused on a breakpoint, clear all stepping and notify the |
| 163 // listeners. |
| 164 Handle<WasmCompiledModule> compiled_module( |
| 165 GetInstanceObject()->compiled_module(), isolate_); |
| 166 int position = GetTopPosition(compiled_module); |
| 167 MaybeHandle<FixedArray> hit_breakpoints; |
| 168 if (isolate_->debug()->break_points_active()) { |
| 169 hit_breakpoints = compiled_module->CheckBreakPoints(position); |
| 170 } |
| 171 |
| 172 // If we hit a breakpoint, pass a JSArray with all breakpoints, otherwise |
| 173 // pass undefined. |
| 174 Handle<Object> hit_breakpoints_js; |
| 175 if (hit_breakpoints.is_null()) { |
| 176 hit_breakpoints_js = isolate_->factory()->undefined_value(); |
| 177 } else { |
| 178 hit_breakpoints_js = isolate_->factory()->NewJSArrayWithElements( |
| 179 hit_breakpoints.ToHandleChecked()); |
| 180 } |
| 181 |
| 182 isolate_->debug()->OnDebugBreak(hit_breakpoints_js, false); |
| 183 } |
| 184 |
| 185 int GetTopPosition(Handle<WasmCompiledModule> compiled_module) { |
| 186 DCHECK_EQ(1, interpreter()->GetThreadCount()); |
| 187 WasmInterpreter::Thread* thread = interpreter()->GetThread(0); |
| 188 DCHECK_LT(0, thread->GetFrameCount()); |
| 189 |
| 190 wasm::InterpretedFrame frame = |
| 191 thread->GetFrame(thread->GetFrameCount() - 1); |
| 192 return compiled_module->GetFunctionOffset(frame.function()->func_index) + |
| 193 frame.pc(); |
| 194 } |
| 195 |
| 196 std::vector<std::pair<uint32_t, int>> GetInterpretedStack( |
| 197 Address frame_pointer) { |
| 198 // TODO(clemensh): Use frame_pointer. |
| 199 USE(frame_pointer); |
| 200 |
| 201 DCHECK_EQ(1, interpreter()->GetThreadCount()); |
| 202 WasmInterpreter::Thread* thread = interpreter()->GetThread(0); |
| 203 std::vector<std::pair<uint32_t, int>> stack(thread->GetFrameCount()); |
| 204 for (int i = 0, e = thread->GetFrameCount(); i < e; ++i) { |
| 205 wasm::InterpretedFrame frame = thread->GetFrame(i); |
| 206 stack[i] = {frame.function()->func_index, frame.pc()}; |
| 207 } |
| 208 return stack; |
| 209 } |
| 210 |
| 211 std::unique_ptr<wasm::InterpretedFrame> GetInterpretedFrame( |
| 212 Address frame_pointer, int idx) { |
| 213 // TODO(clemensh): Use frame_pointer. |
| 214 USE(frame_pointer); |
| 215 |
| 216 DCHECK_EQ(1, interpreter()->GetThreadCount()); |
| 217 WasmInterpreter::Thread* thread = interpreter()->GetThread(0); |
| 218 return std::unique_ptr<wasm::InterpretedFrame>( |
| 219 new wasm::InterpretedFrame(thread->GetMutableFrame(idx))); |
| 220 } |
139 }; | 221 }; |
140 | 222 |
141 InterpreterHandle* GetOrCreateInterpreterHandle( | 223 InterpreterHandle* GetOrCreateInterpreterHandle( |
142 Isolate* isolate, Handle<WasmDebugInfo> debug_info) { | 224 Isolate* isolate, Handle<WasmDebugInfo> debug_info) { |
143 Handle<Object> handle(debug_info->get(WasmDebugInfo::kInterpreterHandle), | 225 Handle<Object> handle(debug_info->get(WasmDebugInfo::kInterpreterHandle), |
144 isolate); | 226 isolate); |
145 if (handle->IsUndefined(isolate)) { | 227 if (handle->IsUndefined(isolate)) { |
146 InterpreterHandle* cpp_handle = new InterpreterHandle(isolate, *debug_info); | 228 InterpreterHandle* cpp_handle = new InterpreterHandle(isolate, *debug_info); |
147 handle = Managed<InterpreterHandle>::New(isolate, cpp_handle); | 229 handle = Managed<InterpreterHandle>::New(isolate, cpp_handle); |
148 debug_info->set(WasmDebugInfo::kInterpreterHandle, *handle); | 230 debug_info->set(WasmDebugInfo::kInterpreterHandle, *handle); |
149 } | 231 } |
150 | 232 |
151 return Handle<Managed<InterpreterHandle>>::cast(handle)->get(); | 233 return Handle<Managed<InterpreterHandle>>::cast(handle)->get(); |
152 } | 234 } |
153 | 235 |
| 236 InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info) { |
| 237 Object* handle_obj = debug_info->get(WasmDebugInfo::kInterpreterHandle); |
| 238 DCHECK(!handle_obj->IsUndefined(debug_info->GetIsolate())); |
| 239 return Managed<InterpreterHandle>::cast(handle_obj)->get(); |
| 240 } |
| 241 |
154 int GetNumFunctions(WasmInstanceObject* instance) { | 242 int GetNumFunctions(WasmInstanceObject* instance) { |
155 size_t num_functions = | 243 size_t num_functions = |
156 instance->compiled_module()->module()->functions.size(); | 244 instance->compiled_module()->module()->functions.size(); |
157 DCHECK_GE(kMaxInt, num_functions); | 245 DCHECK_GE(kMaxInt, num_functions); |
158 return static_cast<int>(num_functions); | 246 return static_cast<int>(num_functions); |
159 } | 247 } |
160 | 248 |
161 Handle<FixedArray> GetOrCreateInterpretedFunctions( | 249 Handle<FixedArray> GetOrCreateInterpretedFunctions( |
162 Isolate* isolate, Handle<WasmDebugInfo> debug_info) { | 250 Isolate* isolate, Handle<WasmDebugInfo> debug_info) { |
163 Handle<Object> obj(debug_info->get(WasmDebugInfo::kInterpretedFunctions), | 251 Handle<Object> obj(debug_info->get(WasmDebugInfo::kInterpretedFunctions), |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 Isolate* isolate = debug_info->GetIsolate(); | 346 Isolate* isolate = debug_info->GetIsolate(); |
259 InterpreterHandle* handle = GetOrCreateInterpreterHandle(isolate, debug_info); | 347 InterpreterHandle* handle = GetOrCreateInterpreterHandle(isolate, debug_info); |
260 WasmInterpreter* interpreter = handle->interpreter(); | 348 WasmInterpreter* interpreter = handle->interpreter(); |
261 DCHECK_LE(0, func_index); | 349 DCHECK_LE(0, func_index); |
262 DCHECK_GT(handle->module()->functions.size(), func_index); | 350 DCHECK_GT(handle->module()->functions.size(), func_index); |
263 const WasmFunction* func = &handle->module()->functions[func_index]; | 351 const WasmFunction* func = &handle->module()->functions[func_index]; |
264 interpreter->SetBreakpoint(func, offset, true); | 352 interpreter->SetBreakpoint(func, offset, true); |
265 EnsureRedirectToInterpreter(isolate, debug_info, func_index); | 353 EnsureRedirectToInterpreter(isolate, debug_info, func_index); |
266 } | 354 } |
267 | 355 |
268 void WasmDebugInfo::RunInterpreter(Handle<WasmDebugInfo> debug_info, | 356 void WasmDebugInfo::RunInterpreter(int func_index, uint8_t* arg_buffer) { |
269 int func_index, uint8_t* arg_buffer) { | |
270 DCHECK_LE(0, func_index); | 357 DCHECK_LE(0, func_index); |
271 InterpreterHandle* interp_handle = | 358 GetInterpreterHandle(this)->Execute(static_cast<uint32_t>(func_index), |
272 GetOrCreateInterpreterHandle(debug_info->GetIsolate(), debug_info); | 359 arg_buffer); |
273 interp_handle->Execute(static_cast<uint32_t>(func_index), arg_buffer); | |
274 } | 360 } |
| 361 |
| 362 std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack( |
| 363 Address frame_pointer) { |
| 364 return GetInterpreterHandle(this)->GetInterpretedStack(frame_pointer); |
| 365 } |
| 366 |
| 367 std::unique_ptr<wasm::InterpretedFrame> WasmDebugInfo::GetInterpretedFrame( |
| 368 Address frame_pointer, int idx) { |
| 369 return GetInterpreterHandle(this)->GetInterpretedFrame(frame_pointer, idx); |
| 370 } |
OLD | NEW |