Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include <unordered_map>
6 :
7 : #include "src/assembler-inl.h"
8 : #include "src/assert-scope.h"
9 : #include "src/compiler/wasm-compiler.h"
10 : #include "src/debug/debug-scopes.h"
11 : #include "src/debug/debug.h"
12 : #include "src/factory.h"
13 : #include "src/frames-inl.h"
14 : #include "src/identity-map.h"
15 : #include "src/isolate.h"
16 : #include "src/wasm/module-decoder.h"
17 : #include "src/wasm/wasm-interpreter.h"
18 : #include "src/wasm/wasm-limits.h"
19 : #include "src/wasm/wasm-module.h"
20 : #include "src/wasm/wasm-objects.h"
21 : #include "src/zone/accounting-allocator.h"
22 :
23 : using namespace v8::internal;
24 : using namespace v8::internal::wasm;
25 :
26 : namespace {
27 :
28 : template <bool internal, typename... Args>
29 234 : Handle<String> PrintFToOneByteString(Isolate* isolate, const char* format,
30 : Args... args) {
31 : // Maximum length of a formatted value name ("param#%d", "local#%d",
32 : // "global#%d").
33 : constexpr int kMaxStrLen = 18;
34 : EmbeddedVector<char, kMaxStrLen> value;
35 234 : int len = SNPrintF(value, format, args...);
36 234 : CHECK(len > 0 && len < value.length());
37 : Vector<uint8_t> name = Vector<uint8_t>::cast(value.SubVector(0, len));
38 : return internal
39 : ? isolate->factory()->InternalizeOneByteString(name)
40 234 : : isolate->factory()->NewStringFromOneByte(name).ToHandleChecked();
41 : }
42 :
43 294 : Handle<Object> WasmValToValueObject(Isolate* isolate, WasmVal value) {
44 294 : switch (value.type) {
45 : case kWasmI32:
46 : if (Smi::IsValid(value.to<int32_t>()))
47 294 : return handle(Smi::FromInt(value.to<int32_t>()), isolate);
48 : return PrintFToOneByteString<false>(isolate, "%d", value.to<int32_t>());
49 : case kWasmI64:
50 0 : if (Smi::IsValid(value.to<int64_t>()))
51 0 : return handle(Smi::FromIntptr(value.to<int64_t>()), isolate);
52 : return PrintFToOneByteString<false>(isolate, "%" PRId64,
53 0 : value.to<int64_t>());
54 : case kWasmF32:
55 0 : return isolate->factory()->NewNumber(value.to<float>());
56 : case kWasmF64:
57 0 : return isolate->factory()->NewNumber(value.to<double>());
58 : default:
59 0 : UNIMPLEMENTED();
60 : return isolate->factory()->undefined_value();
61 : }
62 : }
63 :
64 : // Forward declaration.
65 : class InterpreterHandle;
66 : InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info);
67 :
68 : class InterpreterHandle {
69 : WasmInstance instance_;
70 : WasmInterpreter interpreter_;
71 : Isolate* isolate_;
72 : StepAction next_step_action_ = StepNone;
73 : int last_step_stack_depth_ = 0;
74 : std::unordered_map<Address, uint32_t> activations_;
75 :
76 51425 : uint32_t StartActivation(Address frame_pointer) {
77 51425 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
78 51425 : uint32_t activation_id = thread->StartActivation();
79 : DCHECK_EQ(0, activations_.count(frame_pointer));
80 102850 : activations_.insert(std::make_pair(frame_pointer, activation_id));
81 51425 : return activation_id;
82 : }
83 :
84 51425 : void FinishActivation(Address frame_pointer, uint32_t activation_id) {
85 51425 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
86 51425 : thread->FinishActivation(activation_id);
87 : DCHECK_EQ(1, activations_.count(frame_pointer));
88 : activations_.erase(frame_pointer);
89 51425 : }
90 :
91 3630 : std::pair<uint32_t, uint32_t> GetActivationFrameRange(
92 : WasmInterpreter::Thread* thread, Address frame_pointer) {
93 : DCHECK_EQ(1, activations_.count(frame_pointer));
94 3630 : uint32_t activation_id = activations_.find(frame_pointer)->second;
95 3630 : uint32_t num_activations = static_cast<uint32_t>(activations_.size() - 1);
96 3630 : uint32_t frame_base = thread->ActivationFrameBase(activation_id);
97 : uint32_t frame_limit = activation_id == num_activations
98 3495 : ? thread->GetFrameCount()
99 7125 : : thread->ActivationFrameBase(activation_id + 1);
100 : DCHECK_LE(frame_base, frame_limit);
101 : DCHECK_LE(frame_limit, thread->GetFrameCount());
102 3630 : return {frame_base, frame_limit};
103 : }
104 :
105 : public:
106 : // Initialize in the right order, using helper methods to make this possible.
107 : // WasmInterpreter has to be allocated in place, since it is not movable.
108 1153 : InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info)
109 1153 : : instance_(debug_info->wasm_instance()->compiled_module()->module()),
110 : interpreter_(isolate, GetBytesEnv(&instance_, debug_info)),
111 2306 : isolate_(isolate) {
112 : DisallowHeapAllocation no_gc;
113 :
114 1153 : WasmInstanceObject* instance = debug_info->wasm_instance();
115 :
116 : // Store a global handle to the wasm instance in the interpreter.
117 1153 : interpreter_.SetInstanceObject(instance);
118 :
119 : // Set memory start pointer and size.
120 1153 : instance_.mem_start = nullptr;
121 1153 : instance_.mem_size = 0;
122 1153 : if (instance->has_memory_buffer()) {
123 15 : UpdateMemory(instance->memory_buffer());
124 : } else {
125 : DCHECK_EQ(0, instance_.module->min_mem_pages);
126 : }
127 :
128 : // Set pointer to globals storage.
129 : instance_.globals_start =
130 1153 : debug_info->wasm_instance()->compiled_module()->GetGlobalsStartOrNull();
131 1153 : }
132 :
133 2270 : ~InterpreterHandle() {
134 : DCHECK_EQ(0, activations_.size());
135 1135 : }
136 :
137 1153 : static ModuleBytesEnv GetBytesEnv(WasmInstance* instance,
138 : WasmDebugInfo* debug_info) {
139 : // Return raw pointer into heap. The WasmInterpreter will make its own copy
140 : // of this data anyway, and there is no heap allocation in-between.
141 : SeqOneByteString* bytes_str =
142 1153 : debug_info->wasm_instance()->compiled_module()->module_bytes();
143 1153 : Vector<const byte> bytes(bytes_str->GetChars(), bytes_str->length());
144 2306 : return ModuleBytesEnv(instance->module, instance, bytes);
145 : }
146 :
147 : WasmInterpreter* interpreter() { return &interpreter_; }
148 : const WasmModule* module() { return instance_.module; }
149 :
150 : void PrepareStep(StepAction step_action) {
151 244 : next_step_action_ = step_action;
152 244 : last_step_stack_depth_ = CurrentStackDepth();
153 : }
154 :
155 349 : void ClearStepping() { next_step_action_ = StepNone; }
156 :
157 244 : int CurrentStackDepth() {
158 : DCHECK_EQ(1, interpreter()->GetThreadCount());
159 244 : return interpreter()->GetThread(0)->GetFrameCount();
160 : }
161 :
162 : // Returns true if exited regularly, false if a trap/exception occured and was
163 : // not handled inside this activation. In the latter case, a pending exception
164 : // will have been set on the isolate.
165 51425 : bool Execute(Address frame_pointer, uint32_t func_index,
166 154630 : uint8_t* arg_buffer) {
167 : DCHECK_GE(module()->functions.size(), func_index);
168 329303 : FunctionSig* sig = module()->functions[func_index].sig;
169 : DCHECK_GE(kMaxInt, sig->parameter_count());
170 51425 : int num_params = static_cast<int>(sig->parameter_count());
171 : ScopedVector<WasmVal> wasm_args(num_params);
172 : uint8_t* arg_buf_ptr = arg_buffer;
173 124325 : for (int i = 0; i < num_params; ++i) {
174 145800 : uint32_t param_size = 1 << ElementSizeLog2Of(sig->GetParam(i));
175 : #define CASE_ARG_TYPE(type, ctype) \
176 : case type: \
177 : DCHECK_EQ(param_size, sizeof(ctype)); \
178 : wasm_args[i] = WasmVal(ReadUnalignedValue<ctype>(arg_buf_ptr)); \
179 : break;
180 72900 : switch (sig->GetParam(i)) {
181 11562 : CASE_ARG_TYPE(kWasmI32, uint32_t)
182 23100 : CASE_ARG_TYPE(kWasmI64, uint64_t)
183 2415 : CASE_ARG_TYPE(kWasmF32, float)
184 35823 : CASE_ARG_TYPE(kWasmF64, double)
185 : #undef CASE_ARG_TYPE
186 : default:
187 0 : UNREACHABLE();
188 : }
189 72900 : arg_buf_ptr += param_size;
190 : }
191 :
192 51425 : uint32_t activation_id = StartActivation(frame_pointer);
193 :
194 51425 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
195 102850 : thread->InitFrame(&module()->functions[func_index], wasm_args.start());
196 : bool finished = false;
197 51425 : while (!finished) {
198 : // TODO(clemensh): Add occasional StackChecks.
199 51780 : WasmInterpreter::State state = ContinueExecution(thread);
200 51780 : switch (state) {
201 : case WasmInterpreter::State::PAUSED:
202 355 : NotifyDebugEventListeners(thread);
203 355 : break;
204 : case WasmInterpreter::State::FINISHED:
205 : // Perfect, just break the switch and exit the loop.
206 : finished = true;
207 : break;
208 : case WasmInterpreter::State::TRAPPED: {
209 : int message_id =
210 120 : WasmOpcodes::TrapReasonToMessageId(thread->GetTrapReason());
211 : Handle<Object> exception = isolate_->factory()->NewWasmRuntimeError(
212 120 : static_cast<MessageTemplate::Template>(message_id));
213 120 : isolate_->Throw(*exception);
214 : // Handle this exception. Return without trying to read back the
215 : // return value.
216 120 : auto result = thread->HandleException(isolate_);
217 120 : return result == WasmInterpreter::Thread::HANDLED;
218 : } break;
219 : case WasmInterpreter::State::STOPPED:
220 : // An exception happened, and the current activation was unwound.
221 : DCHECK_EQ(thread->ActivationFrameBase(activation_id),
222 : thread->GetFrameCount());
223 : return false;
224 : // RUNNING should never occur here.
225 : case WasmInterpreter::State::RUNNING:
226 : default:
227 0 : UNREACHABLE();
228 : }
229 : }
230 :
231 : // Copy back the return value
232 : DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count());
233 : // TODO(wasm): Handle multi-value returns.
234 : DCHECK_EQ(1, kV8MaxWasmFunctionReturns);
235 51200 : if (sig->return_count()) {
236 50928 : WasmVal ret_val = thread->GetReturnValue(0);
237 : #define CASE_RET_TYPE(type, ctype) \
238 : case type: \
239 : DCHECK_EQ(1 << ElementSizeLog2Of(sig->GetReturn(0)), sizeof(ctype)); \
240 : WriteUnalignedValue<ctype>(arg_buffer, ret_val.to<ctype>()); \
241 : break;
242 50928 : switch (sig->GetReturn(0)) {
243 : CASE_RET_TYPE(kWasmI32, uint32_t)
244 : CASE_RET_TYPE(kWasmI64, uint64_t)
245 : CASE_RET_TYPE(kWasmF32, float)
246 : CASE_RET_TYPE(kWasmF64, double)
247 : #undef CASE_RET_TYPE
248 : default:
249 0 : UNREACHABLE();
250 : }
251 : }
252 :
253 51200 : FinishActivation(frame_pointer, activation_id);
254 :
255 51200 : return true;
256 : }
257 :
258 51780 : WasmInterpreter::State ContinueExecution(WasmInterpreter::Thread* thread) {
259 51780 : switch (next_step_action_) {
260 : case StepNone:
261 51530 : return thread->Run();
262 : case StepIn:
263 : return thread->Step();
264 : case StepOut:
265 25 : thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterReturn);
266 25 : return thread->Run();
267 : case StepNext: {
268 38 : int stack_depth = thread->GetFrameCount();
269 38 : if (stack_depth == last_step_stack_depth_) return thread->Step();
270 : thread->AddBreakFlags(stack_depth > last_step_stack_depth_
271 : ? WasmInterpreter::BreakFlag::AfterReturn
272 6 : : WasmInterpreter::BreakFlag::AfterCall);
273 6 : return thread->Run();
274 : }
275 : default:
276 0 : UNREACHABLE();
277 : return WasmInterpreter::STOPPED;
278 : }
279 : }
280 :
281 355 : Handle<WasmInstanceObject> GetInstanceObject() {
282 355 : StackTraceFrameIterator it(isolate_);
283 : WasmInterpreterEntryFrame* frame =
284 : WasmInterpreterEntryFrame::cast(it.frame());
285 355 : Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_);
286 : DCHECK_EQ(this, GetInterpreterHandle(instance_obj->debug_info()));
287 710 : return instance_obj;
288 : }
289 :
290 355 : void NotifyDebugEventListeners(WasmInterpreter::Thread* thread) {
291 : // Enter the debugger.
292 1059 : DebugScope debug_scope(isolate_->debug());
293 485 : if (debug_scope.failed()) return;
294 :
295 : // Postpone interrupt during breakpoint processing.
296 355 : PostponeInterruptsScope postpone(isolate_);
297 :
298 : // Check whether we hit a breakpoint.
299 710 : if (isolate_->debug()->break_points_active()) {
300 : Handle<WasmCompiledModule> compiled_module(
301 1065 : GetInstanceObject()->compiled_module(), isolate_);
302 355 : int position = GetTopPosition(compiled_module);
303 : Handle<FixedArray> breakpoints;
304 710 : if (compiled_module->CheckBreakPoints(position).ToHandle(&breakpoints)) {
305 : // We hit one or several breakpoints. Clear stepping, notify the
306 : // listeners and return.
307 : ClearStepping();
308 : Handle<Object> hit_breakpoints_js =
309 124 : isolate_->factory()->NewJSArrayWithElements(breakpoints);
310 248 : isolate_->debug()->OnDebugBreak(hit_breakpoints_js);
311 : return;
312 : }
313 : }
314 :
315 : // We did not hit a breakpoint, so maybe this pause is related to stepping.
316 : bool hit_step = false;
317 231 : switch (next_step_action_) {
318 : case StepNone:
319 : break;
320 : case StepIn:
321 : hit_step = true;
322 174 : break;
323 : case StepOut:
324 19 : hit_step = thread->GetFrameCount() < last_step_stack_depth_;
325 19 : break;
326 : case StepNext: {
327 38 : hit_step = thread->GetFrameCount() == last_step_stack_depth_;
328 38 : break;
329 : }
330 : default:
331 0 : UNREACHABLE();
332 : }
333 231 : if (!hit_step) return;
334 : ClearStepping();
335 675 : isolate_->debug()->OnDebugBreak(isolate_->factory()->undefined_value());
336 : }
337 :
338 355 : int GetTopPosition(Handle<WasmCompiledModule> compiled_module) {
339 : DCHECK_EQ(1, interpreter()->GetThreadCount());
340 355 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
341 : DCHECK_LT(0, thread->GetFrameCount());
342 :
343 355 : auto frame = thread->GetFrame(thread->GetFrameCount() - 1);
344 710 : return compiled_module->GetFunctionOffset(frame->function()->func_index) +
345 710 : frame->pc();
346 : }
347 :
348 3001 : std::vector<std::pair<uint32_t, int>> GetInterpretedStack(
349 : Address frame_pointer) {
350 : DCHECK_EQ(1, interpreter()->GetThreadCount());
351 3001 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
352 :
353 : std::pair<uint32_t, uint32_t> frame_range =
354 3001 : GetActivationFrameRange(thread, frame_pointer);
355 :
356 : std::vector<std::pair<uint32_t, int>> stack;
357 3001 : stack.reserve(frame_range.second - frame_range.first);
358 1973031 : for (uint32_t fp = frame_range.first; fp < frame_range.second; ++fp) {
359 1970030 : auto frame = thread->GetFrame(fp);
360 3940060 : stack.emplace_back(frame->function()->func_index, frame->pc());
361 : }
362 3001 : return stack;
363 : }
364 :
365 629 : std::unique_ptr<wasm::InterpretedFrame> GetInterpretedFrame(
366 : Address frame_pointer, int idx) {
367 : DCHECK_EQ(1, interpreter()->GetThreadCount());
368 629 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
369 :
370 : std::pair<uint32_t, uint32_t> frame_range =
371 629 : GetActivationFrameRange(thread, frame_pointer);
372 : DCHECK_LE(0, idx);
373 : DCHECK_GT(frame_range.second - frame_range.first, idx);
374 :
375 629 : return thread->GetFrame(frame_range.first + idx);
376 : }
377 :
378 225 : void Unwind(Address frame_pointer) {
379 : // Find the current activation.
380 : DCHECK_EQ(1, activations_.count(frame_pointer));
381 : // Activations must be properly stacked:
382 : DCHECK_EQ(activations_.size() - 1, activations_[frame_pointer]);
383 225 : uint32_t activation_id = static_cast<uint32_t>(activations_.size() - 1);
384 :
385 : // Unwind the frames of the current activation if not already unwound.
386 225 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
387 450 : if (static_cast<uint32_t>(thread->GetFrameCount()) >
388 225 : thread->ActivationFrameBase(activation_id)) {
389 : using ExceptionResult = WasmInterpreter::Thread::ExceptionHandlingResult;
390 0 : ExceptionResult result = thread->HandleException(isolate_);
391 : // TODO(wasm): Handle exceptions caught in wasm land.
392 0 : CHECK_EQ(ExceptionResult::UNWOUND, result);
393 : }
394 :
395 225 : FinishActivation(frame_pointer, activation_id);
396 225 : }
397 :
398 83708 : uint64_t NumInterpretedCalls() {
399 : DCHECK_EQ(1, interpreter()->GetThreadCount());
400 83708 : return interpreter()->GetThread(0)->NumInterpretedCalls();
401 : }
402 :
403 45 : void UpdateMemory(JSArrayBuffer* new_memory) {
404 45 : instance_.mem_start = reinterpret_cast<byte*>(new_memory->backing_store());
405 90 : CHECK(new_memory->byte_length()->ToUint32(&instance_.mem_size));
406 45 : }
407 :
408 276 : Handle<JSArray> GetScopeDetails(Address frame_pointer, int frame_index,
409 : Handle<WasmInstanceObject> instance) {
410 276 : auto frame = GetInterpretedFrame(frame_pointer, frame_index);
411 :
412 : Handle<FixedArray> global_scope =
413 276 : isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
414 : global_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
415 : Smi::FromInt(ScopeIterator::ScopeTypeGlobal));
416 : Handle<JSObject> global_scope_object =
417 276 : isolate_->factory()->NewJSObjectWithNullProto();
418 : global_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
419 276 : *global_scope_object);
420 :
421 : // TODO(clemensh): Add globals to the global scope.
422 :
423 276 : if (instance->has_memory_buffer()) {
424 : Handle<String> name = isolate_->factory()->InternalizeOneByteString(
425 0 : STATIC_CHAR_VECTOR("memory"));
426 0 : Handle<JSArrayBuffer> memory_buffer(instance->memory_buffer(), isolate_);
427 : uint32_t byte_length;
428 0 : CHECK(memory_buffer->byte_length()->ToUint32(&byte_length));
429 : Handle<JSTypedArray> uint8_array = isolate_->factory()->NewJSTypedArray(
430 0 : kExternalUint8Array, memory_buffer, 0, byte_length);
431 : JSObject::SetOwnPropertyIgnoreAttributes(global_scope_object, name,
432 : uint8_array, NONE)
433 0 : .Check();
434 : }
435 :
436 : Handle<FixedArray> local_scope =
437 276 : isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
438 : local_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
439 : Smi::FromInt(ScopeIterator::ScopeTypeLocal));
440 : Handle<JSObject> local_scope_object =
441 276 : isolate_->factory()->NewJSObjectWithNullProto();
442 : local_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
443 276 : *local_scope_object);
444 :
445 : // Fill parameters and locals.
446 276 : int num_params = frame->GetParameterCount();
447 276 : int num_locals = frame->GetLocalCount();
448 : DCHECK_LE(num_params, num_locals);
449 510 : for (int i = 0; i < num_locals; ++i) {
450 : // TODO(clemensh): Use names from name section if present.
451 234 : const char* label = i < num_params ? "param#%d" : "local#%d";
452 234 : Handle<String> name = PrintFToOneByteString<true>(isolate_, label, i);
453 234 : WasmVal value = frame->GetLocalValue(i);
454 234 : Handle<Object> value_obj = WasmValToValueObject(isolate_, value);
455 : JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, name,
456 : value_obj, NONE)
457 468 : .Check();
458 : }
459 :
460 : // Fill stack values.
461 276 : int stack_count = frame->GetStackHeight();
462 : // Use an object without prototype instead of an Array, for nicer displaying
463 : // in DevTools. For Arrays, the length field and prototype is displayed,
464 : // which does not make too much sense here.
465 : Handle<JSObject> stack_obj =
466 276 : isolate_->factory()->NewJSObjectWithNullProto();
467 336 : for (int i = 0; i < stack_count; ++i) {
468 60 : WasmVal value = frame->GetStackValue(i);
469 60 : Handle<Object> value_obj = WasmValToValueObject(isolate_, value);
470 : JSObject::SetOwnElementIgnoreAttributes(
471 : stack_obj, static_cast<uint32_t>(i), value_obj, NONE)
472 120 : .Check();
473 : }
474 : Handle<String> stack_name = isolate_->factory()->InternalizeOneByteString(
475 276 : STATIC_CHAR_VECTOR("stack"));
476 : JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, stack_name,
477 : stack_obj, NONE)
478 552 : .Check();
479 :
480 : Handle<JSArray> global_jsarr =
481 276 : isolate_->factory()->NewJSArrayWithElements(global_scope);
482 : Handle<JSArray> local_jsarr =
483 276 : isolate_->factory()->NewJSArrayWithElements(local_scope);
484 276 : Handle<FixedArray> all_scopes = isolate_->factory()->NewFixedArray(2);
485 276 : all_scopes->set(0, *global_jsarr);
486 276 : all_scopes->set(1, *local_jsarr);
487 552 : return isolate_->factory()->NewJSArrayWithElements(all_scopes);
488 : }
489 : };
490 :
491 1334 : InterpreterHandle* GetOrCreateInterpreterHandle(
492 : Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
493 : Handle<Object> handle(debug_info->get(WasmDebugInfo::kInterpreterHandle),
494 : isolate);
495 1334 : if (handle->IsUndefined(isolate)) {
496 1153 : InterpreterHandle* cpp_handle = new InterpreterHandle(isolate, *debug_info);
497 1153 : handle = Managed<InterpreterHandle>::New(isolate, cpp_handle);
498 1153 : debug_info->set(WasmDebugInfo::kInterpreterHandle, *handle);
499 : }
500 :
501 1334 : return Handle<Managed<InterpreterHandle>>::cast(handle)->get();
502 : }
503 :
504 55524 : InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info) {
505 : Object* handle_obj = debug_info->get(WasmDebugInfo::kInterpreterHandle);
506 : DCHECK(!handle_obj->IsUndefined(debug_info->GetIsolate()));
507 55524 : return Managed<InterpreterHandle>::cast(handle_obj)->get();
508 : }
509 :
510 83738 : InterpreterHandle* GetInterpreterHandleOrNull(WasmDebugInfo* debug_info) {
511 : Object* handle_obj = debug_info->get(WasmDebugInfo::kInterpreterHandle);
512 83738 : if (handle_obj->IsUndefined(debug_info->GetIsolate())) return nullptr;
513 83738 : return Managed<InterpreterHandle>::cast(handle_obj)->get();
514 : }
515 :
516 2381 : int GetNumFunctions(WasmInstanceObject* instance) {
517 : size_t num_functions =
518 2381 : instance->compiled_module()->module()->functions.size();
519 : DCHECK_GE(kMaxInt, num_functions);
520 2381 : return static_cast<int>(num_functions);
521 : }
522 :
523 1228 : Handle<FixedArray> GetOrCreateInterpretedFunctions(
524 : Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
525 : Handle<Object> obj(debug_info->get(WasmDebugInfo::kInterpretedFunctions),
526 : isolate);
527 1228 : if (!obj->IsUndefined(isolate)) return Handle<FixedArray>::cast(obj);
528 :
529 : Handle<FixedArray> new_arr = isolate->factory()->NewFixedArray(
530 1153 : GetNumFunctions(debug_info->wasm_instance()));
531 1153 : debug_info->set(WasmDebugInfo::kInterpretedFunctions, *new_arr);
532 1153 : return new_arr;
533 : }
534 :
535 : using CodeRelocationMap = IdentityMap<Handle<Code>, FreeStoreAllocationPolicy>;
536 :
537 4140 : void RedirectCallsitesInCode(Code* code, CodeRelocationMap& map) {
538 : DisallowHeapAllocation no_gc;
539 17644 : for (RelocIterator it(code, RelocInfo::kCodeTargetMask); !it.done();
540 9364 : it.next()) {
541 : DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode()));
542 18728 : Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
543 : Handle<Code>* new_target = map.Find(target);
544 9364 : if (!new_target) continue;
545 : it.rinfo()->set_target_address(code->GetIsolate(),
546 2678 : (*new_target)->instruction_start());
547 : }
548 4140 : }
549 :
550 1228 : void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance,
551 : CodeRelocationMap& map) {
552 : DisallowHeapAllocation no_gc;
553 : // Redirect all calls in wasm functions.
554 1228 : FixedArray* code_table = instance->compiled_module()->ptr_to_code_table();
555 3927 : for (int i = 0, e = GetNumFunctions(instance); i < e; ++i) {
556 2699 : RedirectCallsitesInCode(Code::cast(code_table->get(i)), map);
557 : }
558 :
559 : // Redirect all calls in exported functions.
560 : FixedArray* weak_exported_functions =
561 1228 : instance->compiled_module()->ptr_to_weak_exported_functions();
562 1441 : for (int i = 0, e = weak_exported_functions->length(); i != e; ++i) {
563 : WeakCell* weak_function = WeakCell::cast(weak_exported_functions->get(i));
564 1441 : if (weak_function->cleared()) continue;
565 1441 : Code* code = JSFunction::cast(weak_function->value())->code();
566 1441 : RedirectCallsitesInCode(code, map);
567 : }
568 1228 : }
569 :
570 : } // namespace
571 :
572 1153 : Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<WasmInstanceObject> instance) {
573 : Isolate* isolate = instance->GetIsolate();
574 : Factory* factory = isolate->factory();
575 1153 : Handle<FixedArray> arr = factory->NewFixedArray(kFieldCount, TENURED);
576 : arr->set(kWrapperTracerHeader, Smi::kZero);
577 1153 : arr->set(kInstance, *instance);
578 1153 : return Handle<WasmDebugInfo>::cast(arr);
579 : }
580 :
581 0 : bool WasmDebugInfo::IsDebugInfo(Object* object) {
582 0 : if (!object->IsFixedArray()) return false;
583 : FixedArray* arr = FixedArray::cast(object);
584 0 : if (arr->length() != kFieldCount) return false;
585 0 : if (!IsWasmInstance(arr->get(kInstance))) return false;
586 : Isolate* isolate = arr->GetIsolate();
587 0 : if (!arr->get(kInterpreterHandle)->IsUndefined(isolate) &&
588 : !arr->get(kInterpreterHandle)->IsForeign())
589 : return false;
590 0 : return true;
591 : }
592 :
593 56079 : WasmDebugInfo* WasmDebugInfo::cast(Object* object) {
594 : DCHECK(IsDebugInfo(object));
595 56079 : return reinterpret_cast<WasmDebugInfo*>(object);
596 : }
597 :
598 7269 : WasmInstanceObject* WasmDebugInfo::wasm_instance() {
599 7269 : return WasmInstanceObject::cast(get(kInstance));
600 : }
601 :
602 106 : void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
603 : int func_index, int offset) {
604 : Isolate* isolate = debug_info->GetIsolate();
605 212 : InterpreterHandle* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
606 106 : RedirectToInterpreter(debug_info, Vector<int>(&func_index, 1));
607 212 : const WasmFunction* func = &handle->module()->functions[func_index];
608 106 : handle->interpreter()->SetBreakpoint(func, offset, true);
609 106 : }
610 :
611 1228 : void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
612 : Vector<int> func_indexes) {
613 : Isolate* isolate = debug_info->GetIsolate();
614 : // Ensure that the interpreter is instantiated.
615 1228 : GetOrCreateInterpreterHandle(isolate, debug_info);
616 : Handle<FixedArray> interpreted_functions =
617 1228 : GetOrCreateInterpretedFunctions(isolate, debug_info);
618 1228 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
619 1228 : Handle<FixedArray> code_table = instance->compiled_module()->code_table();
620 1228 : CodeRelocationMap code_to_relocate(isolate->heap());
621 3879 : for (int func_index : func_indexes) {
622 : DCHECK_LE(0, func_index);
623 : DCHECK_GT(debug_info->wasm_instance()->module()->functions.size(),
624 : func_index);
625 1477 : if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) continue;
626 :
627 : Handle<Code> new_code = compiler::CompileWasmInterpreterEntry(
628 : isolate, func_index,
629 2738 : instance->compiled_module()->module()->functions[func_index].sig,
630 1369 : instance);
631 :
632 : Code* old_code = Code::cast(code_table->get(func_index));
633 1369 : interpreted_functions->set(func_index, *new_code);
634 : DCHECK_NULL(code_to_relocate.Find(old_code));
635 : code_to_relocate.Set(old_code, new_code);
636 : }
637 1228 : RedirectCallsitesInInstance(isolate, *instance, code_to_relocate);
638 1228 : }
639 :
640 244 : void WasmDebugInfo::PrepareStep(StepAction step_action) {
641 244 : GetInterpreterHandle(this)->PrepareStep(step_action);
642 244 : }
643 :
644 51425 : bool WasmDebugInfo::RunInterpreter(Address frame_pointer, int func_index,
645 : uint8_t* arg_buffer) {
646 : DCHECK_LE(0, func_index);
647 : return GetInterpreterHandle(this)->Execute(
648 51425 : frame_pointer, static_cast<uint32_t>(func_index), arg_buffer);
649 : }
650 :
651 3001 : std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack(
652 : Address frame_pointer) {
653 3001 : return GetInterpreterHandle(this)->GetInterpretedStack(frame_pointer);
654 : }
655 :
656 353 : std::unique_ptr<wasm::InterpretedFrame> WasmDebugInfo::GetInterpretedFrame(
657 : Address frame_pointer, int idx) {
658 353 : return GetInterpreterHandle(this)->GetInterpretedFrame(frame_pointer, idx);
659 : }
660 :
661 225 : void WasmDebugInfo::Unwind(Address frame_pointer) {
662 225 : return GetInterpreterHandle(this)->Unwind(frame_pointer);
663 : }
664 :
665 83708 : uint64_t WasmDebugInfo::NumInterpretedCalls() {
666 83708 : auto handle = GetInterpreterHandleOrNull(this);
667 83708 : return handle ? handle->NumInterpretedCalls() : 0;
668 : }
669 :
670 30 : void WasmDebugInfo::UpdateMemory(JSArrayBuffer* new_memory) {
671 30 : InterpreterHandle* interp_handle = GetInterpreterHandleOrNull(this);
672 60 : if (!interp_handle) return;
673 30 : interp_handle->UpdateMemory(new_memory);
674 : }
675 :
676 : // static
677 276 : Handle<JSArray> WasmDebugInfo::GetScopeDetails(Handle<WasmDebugInfo> debug_info,
678 : Address frame_pointer,
679 : int frame_index) {
680 276 : InterpreterHandle* interp_handle = GetInterpreterHandle(*debug_info);
681 276 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance());
682 276 : return interp_handle->GetScopeDetails(frame_pointer, frame_index, instance);
683 : }
|