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/base/optional.h"
10 : #include "src/compiler/wasm-compiler.h"
11 : #include "src/debug/debug-scopes.h"
12 : #include "src/debug/debug.h"
13 : #include "src/frames-inl.h"
14 : #include "src/heap/factory.h"
15 : #include "src/identity-map.h"
16 : #include "src/isolate.h"
17 : #include "src/wasm/module-decoder.h"
18 : #include "src/wasm/wasm-code-manager.h"
19 : #include "src/wasm/wasm-interpreter.h"
20 : #include "src/wasm/wasm-limits.h"
21 : #include "src/wasm/wasm-module.h"
22 : #include "src/wasm/wasm-objects-inl.h"
23 : #include "src/zone/accounting-allocator.h"
24 :
25 : namespace v8 {
26 : namespace internal {
27 : namespace wasm {
28 :
29 : namespace {
30 :
31 : template <bool internal, typename... Args>
32 456 : Handle<String> PrintFToOneByteString(Isolate* isolate, const char* format,
33 : Args... args) {
34 : // Maximum length of a formatted value name ("arg#%d", "local#%d",
35 : // "global#%d", i32 constants, i64 constants), including null character.
36 : static constexpr int kMaxStrLen = 21;
37 : EmbeddedVector<char, kMaxStrLen> value;
38 456 : int len = SNPrintF(value, format, args...);
39 912 : CHECK(len > 0 && len < value.length());
40 456 : Vector<uint8_t> name = Vector<uint8_t>::cast(value.SubVector(0, len));
41 : return internal
42 : ? isolate->factory()->InternalizeOneByteString(name)
43 500 : : isolate->factory()->NewStringFromOneByte(name).ToHandleChecked();
44 : }
45 :
46 792 : Handle<Object> WasmValueToValueObject(Isolate* isolate, WasmValue value) {
47 792 : switch (value.type()) {
48 : case kWasmI32:
49 : if (Smi::IsValid(value.to<int32_t>()))
50 644 : return handle(Smi::FromInt(value.to<int32_t>()), isolate);
51 : return PrintFToOneByteString<false>(isolate, "%d", value.to<int32_t>());
52 : case kWasmI64: {
53 : int64_t i64 = value.to<int64_t>();
54 68 : int32_t i32 = static_cast<int32_t>(i64);
55 68 : if (i32 == i64 && Smi::IsValid(i32))
56 24 : return handle(Smi::FromIntptr(i32), isolate);
57 44 : return PrintFToOneByteString<false>(isolate, "%" PRId64, i64);
58 : }
59 : case kWasmF32:
60 0 : return isolate->factory()->NewNumber(value.to<float>());
61 : case kWasmF64:
62 80 : return isolate->factory()->NewNumber(value.to<double>());
63 : default:
64 0 : UNIMPLEMENTED();
65 : return isolate->factory()->undefined_value();
66 : }
67 : }
68 :
69 592 : MaybeHandle<String> GetLocalName(Isolate* isolate,
70 : Handle<WasmDebugInfo> debug_info,
71 : int func_index, int local_index) {
72 : DCHECK_LE(0, func_index);
73 : DCHECK_LE(0, local_index);
74 592 : if (!debug_info->has_locals_names()) {
75 : Handle<WasmModuleObject> module_object(
76 : debug_info->wasm_instance()->module_object(), isolate);
77 20 : Handle<FixedArray> locals_names = DecodeLocalNames(isolate, module_object);
78 20 : debug_info->set_locals_names(*locals_names);
79 : }
80 :
81 : Handle<FixedArray> locals_names(debug_info->locals_names(), isolate);
82 832 : if (func_index >= locals_names->length() ||
83 : locals_names->get(func_index)->IsUndefined(isolate)) {
84 352 : return {};
85 : }
86 :
87 : Handle<FixedArray> func_locals_names(
88 : FixedArray::cast(locals_names->get(func_index)), isolate);
89 480 : if (local_index >= func_locals_names->length() ||
90 : func_locals_names->get(local_index)->IsUndefined(isolate)) {
91 60 : return {};
92 : }
93 180 : return handle(String::cast(func_locals_names->get(local_index)), isolate);
94 : }
95 :
96 : class InterpreterHandle {
97 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(InterpreterHandle);
98 : Isolate* isolate_;
99 : const WasmModule* module_;
100 : WasmInterpreter interpreter_;
101 : StepAction next_step_action_ = StepNone;
102 : int last_step_stack_depth_ = 0;
103 : std::unordered_map<Address, uint32_t> activations_;
104 :
105 37381 : uint32_t StartActivation(Address frame_pointer) {
106 37381 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
107 37381 : uint32_t activation_id = thread->StartActivation();
108 : DCHECK_EQ(0, activations_.count(frame_pointer));
109 74762 : activations_.insert(std::make_pair(frame_pointer, activation_id));
110 37381 : return activation_id;
111 : }
112 :
113 37381 : void FinishActivation(Address frame_pointer, uint32_t activation_id) {
114 37381 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
115 37381 : thread->FinishActivation(activation_id);
116 : DCHECK_EQ(1, activations_.count(frame_pointer));
117 : activations_.erase(frame_pointer);
118 37381 : }
119 :
120 7049 : std::pair<uint32_t, uint32_t> GetActivationFrameRange(
121 : WasmInterpreter::Thread* thread, Address frame_pointer) {
122 : DCHECK_EQ(1, activations_.count(frame_pointer));
123 7049 : uint32_t activation_id = activations_.find(frame_pointer)->second;
124 7049 : uint32_t num_activations = static_cast<uint32_t>(activations_.size() - 1);
125 7049 : uint32_t frame_base = thread->ActivationFrameBase(activation_id);
126 : uint32_t frame_limit = activation_id == num_activations
127 6945 : ? thread->GetFrameCount()
128 13994 : : thread->ActivationFrameBase(activation_id + 1);
129 : DCHECK_LE(frame_base, frame_limit);
130 : DCHECK_LE(frame_limit, thread->GetFrameCount());
131 7049 : return {frame_base, frame_limit};
132 : }
133 :
134 366609 : static ModuleWireBytes GetBytes(WasmDebugInfo debug_info) {
135 : // Return raw pointer into heap. The WasmInterpreter will make its own copy
136 : // of this data anyway, and there is no heap allocation in-between.
137 : NativeModule* native_module =
138 366609 : debug_info->wasm_instance()->module_object()->native_module();
139 366609 : return ModuleWireBytes{native_module->wire_bytes()};
140 : }
141 :
142 : public:
143 366609 : InterpreterHandle(Isolate* isolate, Handle<WasmDebugInfo> debug_info)
144 : : isolate_(isolate),
145 733218 : module_(debug_info->wasm_instance()->module_object()->module()),
146 733218 : interpreter_(isolate, module_, GetBytes(*debug_info),
147 1833045 : handle(debug_info->wasm_instance(), isolate)) {}
148 :
149 366609 : ~InterpreterHandle() { DCHECK_EQ(0, activations_.size()); }
150 :
151 424603 : WasmInterpreter* interpreter() { return &interpreter_; }
152 : const WasmModule* module() const { return module_; }
153 :
154 364 : void PrepareStep(StepAction step_action) {
155 364 : next_step_action_ = step_action;
156 364 : last_step_stack_depth_ = CurrentStackDepth();
157 364 : }
158 :
159 552 : void ClearStepping() { next_step_action_ = StepNone; }
160 :
161 : int CurrentStackDepth() {
162 : DCHECK_EQ(1, interpreter()->GetThreadCount());
163 364 : return interpreter()->GetThread(0)->GetFrameCount();
164 : }
165 :
166 : // Returns true if exited regularly, false if a trap/exception occurred and
167 : // was not handled inside this activation. In the latter case, a pending
168 : // exception will have been set on the isolate.
169 37381 : bool Execute(Handle<WasmInstanceObject> instance_object,
170 : Address frame_pointer, uint32_t func_index,
171 : Vector<WasmValue> argument_values,
172 : Vector<WasmValue> return_values) {
173 : DCHECK_GE(module()->functions.size(), func_index);
174 74762 : FunctionSig* sig = module()->functions[func_index].sig;
175 : DCHECK_EQ(sig->parameter_count(), argument_values.size());
176 : DCHECK_EQ(sig->return_count(), return_values.size());
177 :
178 37381 : uint32_t activation_id = StartActivation(frame_pointer);
179 :
180 74762 : WasmCodeRefScope code_ref_scope;
181 37381 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
182 : thread->InitFrame(&module()->functions[func_index],
183 37381 : argument_values.start());
184 : bool finished = false;
185 71964 : while (!finished) {
186 : // TODO(clemensh): Add occasional StackChecks.
187 37957 : WasmInterpreter::State state = ContinueExecution(thread);
188 37957 : switch (state) {
189 : case WasmInterpreter::State::PAUSED:
190 560 : NotifyDebugEventListeners(thread);
191 : break;
192 : case WasmInterpreter::State::FINISHED:
193 : // Perfect, just break the switch and exit the loop.
194 : finished = true;
195 : break;
196 : case WasmInterpreter::State::TRAPPED: {
197 : MessageTemplate message_id =
198 952 : WasmOpcodes::TrapReasonToMessageId(thread->GetTrapReason());
199 : Handle<Object> exception =
200 952 : isolate_->factory()->NewWasmRuntimeError(message_id);
201 952 : auto result = thread->RaiseException(isolate_, exception);
202 952 : if (result == WasmInterpreter::Thread::HANDLED) break;
203 : // If no local handler was found, we fall-thru to {STOPPED}.
204 : DCHECK_EQ(WasmInterpreter::State::STOPPED, thread->state());
205 : V8_FALLTHROUGH;
206 : }
207 : case WasmInterpreter::State::STOPPED:
208 : // An exception happened, and the current activation was unwound
209 : // without hitting a local exception handler. All that remains to be
210 : // done is finish the activation and let the exception propagate.
211 : DCHECK_EQ(thread->ActivationFrameBase(activation_id),
212 : thread->GetFrameCount());
213 : DCHECK(isolate_->has_pending_exception());
214 3374 : FinishActivation(frame_pointer, activation_id);
215 : return false;
216 : // RUNNING should never occur here.
217 : case WasmInterpreter::State::RUNNING:
218 : default:
219 0 : UNREACHABLE();
220 : }
221 : }
222 :
223 : // Copy back the return value.
224 : DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count());
225 : // TODO(wasm): Handle multi-value returns.
226 : DCHECK_EQ(1, kV8MaxWasmFunctionReturns);
227 34007 : if (sig->return_count()) {
228 33515 : return_values[0] = thread->GetReturnValue(0);
229 : }
230 :
231 34007 : FinishActivation(frame_pointer, activation_id);
232 :
233 : return true;
234 : }
235 :
236 37957 : WasmInterpreter::State ContinueExecution(WasmInterpreter::Thread* thread) {
237 37957 : switch (next_step_action_) {
238 : case StepNone:
239 37585 : return thread->Run();
240 : case StepIn:
241 : return thread->Step();
242 : case StepOut:
243 32 : thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterReturn);
244 32 : return thread->Run();
245 : case StepNext: {
246 108 : int stack_depth = thread->GetFrameCount();
247 108 : if (stack_depth == last_step_stack_depth_) return thread->Step();
248 8 : thread->AddBreakFlags(stack_depth > last_step_stack_depth_
249 : ? WasmInterpreter::BreakFlag::AfterReturn
250 8 : : WasmInterpreter::BreakFlag::AfterCall);
251 8 : return thread->Run();
252 : }
253 : default:
254 0 : UNREACHABLE();
255 : }
256 : }
257 :
258 560 : Handle<WasmInstanceObject> GetInstanceObject() {
259 560 : StackTraceFrameIterator it(isolate_);
260 : WasmInterpreterEntryFrame* frame =
261 : WasmInterpreterEntryFrame::cast(it.frame());
262 560 : Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_);
263 : // Check that this is indeed the instance which is connected to this
264 : // interpreter.
265 : DCHECK_EQ(this, Managed<InterpreterHandle>::cast(
266 : instance_obj->debug_info()->interpreter_handle())
267 : ->raw());
268 1120 : return instance_obj;
269 : }
270 :
271 560 : void NotifyDebugEventListeners(WasmInterpreter::Thread* thread) {
272 : // Enter the debugger.
273 896 : DebugScope debug_scope(isolate_->debug());
274 :
275 : // Check whether we hit a breakpoint.
276 560 : if (isolate_->debug()->break_points_active()) {
277 : Handle<WasmModuleObject> module_object(
278 1120 : GetInstanceObject()->module_object(), isolate_);
279 560 : int position = GetTopPosition(module_object);
280 : Handle<FixedArray> breakpoints;
281 1120 : if (WasmModuleObject::CheckBreakPoints(isolate_, module_object, position)
282 : .ToHandle(&breakpoints)) {
283 : // We hit one or several breakpoints. Clear stepping, notify the
284 : // listeners and return.
285 : ClearStepping();
286 216 : isolate_->debug()->OnDebugBreak(breakpoints);
287 216 : return;
288 : }
289 : }
290 :
291 : // We did not hit a breakpoint, so maybe this pause is related to stepping.
292 : bool hit_step = false;
293 344 : switch (next_step_action_) {
294 : case StepNone:
295 : break;
296 : case StepIn:
297 : hit_step = true;
298 216 : break;
299 : case StepOut:
300 24 : hit_step = thread->GetFrameCount() < last_step_stack_depth_;
301 24 : break;
302 : case StepNext: {
303 104 : hit_step = thread->GetFrameCount() == last_step_stack_depth_;
304 104 : break;
305 : }
306 : default:
307 0 : UNREACHABLE();
308 : }
309 344 : if (!hit_step) return;
310 : ClearStepping();
311 672 : isolate_->debug()->OnDebugBreak(isolate_->factory()->empty_fixed_array());
312 : }
313 :
314 560 : int GetTopPosition(Handle<WasmModuleObject> module_object) {
315 : DCHECK_EQ(1, interpreter()->GetThreadCount());
316 560 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
317 : DCHECK_LT(0, thread->GetFrameCount());
318 :
319 560 : auto frame = thread->GetFrame(thread->GetFrameCount() - 1);
320 1680 : return module_object->GetFunctionOffset(frame->function()->func_index) +
321 1120 : frame->pc();
322 : }
323 :
324 5285 : std::vector<std::pair<uint32_t, int>> GetInterpretedStack(
325 : Address frame_pointer) {
326 : DCHECK_EQ(1, interpreter()->GetThreadCount());
327 5285 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
328 :
329 : std::pair<uint32_t, uint32_t> frame_range =
330 5285 : GetActivationFrameRange(thread, frame_pointer);
331 :
332 : std::vector<std::pair<uint32_t, int>> stack;
333 5285 : stack.reserve(frame_range.second - frame_range.first);
334 1361183 : for (uint32_t fp = frame_range.first; fp < frame_range.second; ++fp) {
335 677949 : auto frame = thread->GetFrame(fp);
336 1355898 : stack.emplace_back(frame->function()->func_index, frame->pc());
337 : }
338 5285 : return stack;
339 : }
340 :
341 1764 : WasmInterpreter::FramePtr GetInterpretedFrame(Address frame_pointer,
342 : int idx) {
343 : DCHECK_EQ(1, interpreter()->GetThreadCount());
344 1764 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
345 :
346 : std::pair<uint32_t, uint32_t> frame_range =
347 1764 : GetActivationFrameRange(thread, frame_pointer);
348 : DCHECK_LE(0, idx);
349 : DCHECK_GT(frame_range.second - frame_range.first, idx);
350 :
351 1764 : return thread->GetFrame(frame_range.first + idx);
352 : }
353 :
354 : uint64_t NumInterpretedCalls() {
355 : DCHECK_EQ(1, interpreter()->GetThreadCount());
356 51568 : return interpreter()->GetThread(0)->NumInterpretedCalls();
357 : }
358 :
359 464 : Handle<JSObject> GetGlobalScopeObject(InterpretedFrame* frame,
360 : Handle<WasmDebugInfo> debug_info) {
361 464 : Isolate* isolate = isolate_;
362 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
363 :
364 : // TODO(clemensh): Add globals to the global scope.
365 : Handle<JSObject> global_scope_object =
366 464 : isolate_->factory()->NewJSObjectWithNullProto();
367 464 : if (instance->has_memory_object()) {
368 0 : Handle<String> name = isolate_->factory()->InternalizeOneByteString(
369 0 : StaticCharVector("memory"));
370 : Handle<JSArrayBuffer> memory_buffer(
371 0 : instance->memory_object()->array_buffer(), isolate_);
372 0 : Handle<JSTypedArray> uint8_array = isolate_->factory()->NewJSTypedArray(
373 0 : kExternalUint8Array, memory_buffer, 0, memory_buffer->byte_length());
374 0 : JSObject::SetOwnPropertyIgnoreAttributes(global_scope_object, name,
375 0 : uint8_array, NONE)
376 : .Assert();
377 : }
378 464 : return global_scope_object;
379 : }
380 :
381 464 : Handle<JSObject> GetLocalScopeObject(InterpretedFrame* frame,
382 : Handle<WasmDebugInfo> debug_info) {
383 464 : Isolate* isolate = isolate_;
384 :
385 : Handle<JSObject> local_scope_object =
386 464 : isolate_->factory()->NewJSObjectWithNullProto();
387 : // Fill parameters and locals.
388 464 : int num_params = frame->GetParameterCount();
389 464 : int num_locals = frame->GetLocalCount();
390 : DCHECK_LE(num_params, num_locals);
391 464 : if (num_locals > 0) {
392 : Handle<JSObject> locals_obj =
393 412 : isolate_->factory()->NewJSObjectWithNullProto();
394 : Handle<String> locals_name =
395 412 : isolate_->factory()->InternalizeOneByteString(
396 412 : StaticCharVector("locals"));
397 412 : JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, locals_name,
398 412 : locals_obj, NONE)
399 : .Assert();
400 1596 : for (int i = 0; i < num_locals; ++i) {
401 : MaybeHandle<String> name =
402 592 : GetLocalName(isolate, debug_info, frame->function()->func_index, i);
403 592 : if (name.is_null()) {
404 : // Parameters should come before locals in alphabetical ordering, so
405 : // we name them "args" here.
406 412 : const char* label = i < num_params ? "arg#%d" : "local#%d";
407 412 : name = PrintFToOneByteString<true>(isolate_, label, i);
408 : }
409 592 : WasmValue value = frame->GetLocalValue(i);
410 592 : Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
411 592 : JSObject::SetOwnPropertyIgnoreAttributes(
412 592 : locals_obj, name.ToHandleChecked(), value_obj, NONE)
413 : .Assert();
414 : }
415 : }
416 :
417 : // Fill stack values.
418 464 : int stack_count = frame->GetStackHeight();
419 : // Use an object without prototype instead of an Array, for nicer displaying
420 : // in DevTools. For Arrays, the length field and prototype is displayed,
421 : // which does not make too much sense here.
422 : Handle<JSObject> stack_obj =
423 464 : isolate_->factory()->NewJSObjectWithNullProto();
424 464 : Handle<String> stack_name = isolate_->factory()->InternalizeOneByteString(
425 464 : StaticCharVector("stack"));
426 464 : JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, stack_name,
427 464 : stack_obj, NONE)
428 : .Assert();
429 864 : for (int i = 0; i < stack_count; ++i) {
430 200 : WasmValue value = frame->GetStackValue(i);
431 200 : Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
432 200 : JSObject::SetOwnElementIgnoreAttributes(
433 200 : stack_obj, static_cast<uint32_t>(i), value_obj, NONE)
434 : .Assert();
435 : }
436 464 : return local_scope_object;
437 : }
438 : };
439 :
440 : } // namespace
441 :
442 : } // namespace wasm
443 :
444 : namespace {
445 :
446 37805 : wasm::InterpreterHandle* GetOrCreateInterpreterHandle(
447 : Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
448 37805 : Handle<Object> handle(debug_info->interpreter_handle(), isolate);
449 75610 : if (handle->IsUndefined(isolate)) {
450 : // Use the maximum stack size to estimate the maximum size of the
451 : // interpreter. The interpreter keeps its own stack internally, and the size
452 : // of the stack should dominate the overall size of the interpreter. We
453 : // multiply by '2' to account for the growing strategy for the backing store
454 : // of the stack.
455 1695 : size_t interpreter_size = FLAG_stack_size * KB * 2;
456 : handle = Managed<wasm::InterpreterHandle>::Allocate(
457 1695 : isolate, interpreter_size, isolate, debug_info);
458 1695 : debug_info->set_interpreter_handle(*handle);
459 : }
460 :
461 37805 : return Handle<Managed<wasm::InterpreterHandle>>::cast(handle)->raw();
462 : }
463 :
464 : wasm::InterpreterHandle* GetInterpreterHandle(WasmDebugInfo debug_info) {
465 : Object handle_obj = debug_info->interpreter_handle();
466 : DCHECK(!handle_obj->IsUndefined());
467 : return Managed<wasm::InterpreterHandle>::cast(handle_obj)->raw();
468 : }
469 :
470 51568 : wasm::InterpreterHandle* GetInterpreterHandleOrNull(WasmDebugInfo debug_info) {
471 : Object handle_obj = debug_info->interpreter_handle();
472 51568 : if (handle_obj->IsUndefined()) return nullptr;
473 : return Managed<wasm::InterpreterHandle>::cast(handle_obj)->raw();
474 : }
475 :
476 276 : Handle<FixedArray> GetOrCreateInterpretedFunctions(
477 : Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
478 : Handle<FixedArray> arr(debug_info->interpreted_functions(), isolate);
479 : int num_functions = debug_info->wasm_instance()
480 552 : ->module_object()
481 : ->native_module()
482 552 : ->num_functions();
483 276 : if (arr->length() == 0 && num_functions > 0) {
484 176 : arr = isolate->factory()->NewFixedArray(num_functions);
485 176 : debug_info->set_interpreted_functions(*arr);
486 : }
487 : DCHECK_EQ(num_functions, arr->length());
488 276 : return arr;
489 : }
490 :
491 : } // namespace
492 :
493 366633 : Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<WasmInstanceObject> instance) {
494 : DCHECK(!instance->has_debug_info());
495 : Factory* factory = instance->GetIsolate()->factory();
496 : Handle<WasmDebugInfo> debug_info = Handle<WasmDebugInfo>::cast(
497 366633 : factory->NewStruct(WASM_DEBUG_INFO_TYPE, AllocationType::kOld));
498 366633 : debug_info->set_wasm_instance(*instance);
499 366633 : debug_info->set_interpreted_functions(*factory->empty_fixed_array());
500 366633 : instance->set_debug_info(*debug_info);
501 366633 : return debug_info;
502 : }
503 :
504 364914 : wasm::WasmInterpreter* WasmDebugInfo::SetupForTesting(
505 : Handle<WasmInstanceObject> instance_obj) {
506 364914 : Handle<WasmDebugInfo> debug_info = WasmDebugInfo::New(instance_obj);
507 364914 : Isolate* isolate = instance_obj->GetIsolate();
508 : // Use the maximum stack size to estimate the maximum size of the interpreter.
509 : // The interpreter keeps its own stack internally, and the size of the stack
510 : // should dominate the overall size of the interpreter. We multiply by '2' to
511 : // account for the growing strategy for the backing store of the stack.
512 364914 : size_t interpreter_size = FLAG_stack_size * KB * 2;
513 : auto interp_handle = Managed<wasm::InterpreterHandle>::Allocate(
514 364914 : isolate, interpreter_size, isolate, debug_info);
515 729828 : debug_info->set_interpreter_handle(*interp_handle);
516 364914 : return interp_handle->raw()->interpreter();
517 : }
518 :
519 148 : void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
520 : int func_index, int offset) {
521 : Isolate* isolate = debug_info->GetIsolate();
522 148 : auto* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
523 148 : RedirectToInterpreter(debug_info, Vector<int>(&func_index, 1));
524 148 : const wasm::WasmFunction* func = &handle->module()->functions[func_index];
525 296 : handle->interpreter()->SetBreakpoint(func, offset, true);
526 148 : }
527 :
528 276 : void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
529 : Vector<int> func_indexes) {
530 : Isolate* isolate = debug_info->GetIsolate();
531 : // Ensure that the interpreter is instantiated.
532 276 : GetOrCreateInterpreterHandle(isolate, debug_info);
533 : Handle<FixedArray> interpreted_functions =
534 276 : GetOrCreateInterpretedFunctions(isolate, debug_info);
535 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
536 : wasm::NativeModule* native_module =
537 276 : instance->module_object()->native_module();
538 276 : const wasm::WasmModule* module = instance->module();
539 :
540 : // We may modify the wasm jump table.
541 : wasm::NativeModuleModificationScope native_module_modification_scope(
542 552 : native_module);
543 :
544 828 : for (int func_index : func_indexes) {
545 : DCHECK_LE(0, func_index);
546 : DCHECK_GT(module->functions.size(), func_index);
547 364 : if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) continue;
548 :
549 376 : wasm::WasmCodeRefScope code_ref_scope;
550 : wasm::WasmCompilationResult result = compiler::CompileWasmInterpreterEntry(
551 : isolate->wasm_engine(), native_module->enabled_features(), func_index,
552 752 : module->functions[func_index].sig);
553 : std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode(
554 : func_index, result.code_desc, result.frame_slot_count,
555 : result.tagged_parameter_slots, std::move(result.protected_instructions),
556 : std::move(result.source_positions), wasm::WasmCode::kInterpreterEntry,
557 752 : wasm::ExecutionTier::kInterpreter);
558 : Address instruction_start = wasm_code->instruction_start();
559 188 : native_module->PublishCode(std::move(wasm_code));
560 :
561 : Handle<Foreign> foreign_holder =
562 188 : isolate->factory()->NewForeign(instruction_start, AllocationType::kOld);
563 376 : interpreted_functions->set(func_index, *foreign_holder);
564 : }
565 276 : }
566 :
567 364 : void WasmDebugInfo::PrepareStep(StepAction step_action) {
568 728 : GetInterpreterHandle(*this)->PrepareStep(step_action);
569 364 : }
570 :
571 : // static
572 37381 : bool WasmDebugInfo::RunInterpreter(Isolate* isolate,
573 : Handle<WasmDebugInfo> debug_info,
574 : Address frame_pointer, int func_index,
575 : Vector<wasm::WasmValue> argument_values,
576 : Vector<wasm::WasmValue> return_values) {
577 : DCHECK_LE(0, func_index);
578 37381 : auto* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
579 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
580 37381 : return handle->Execute(instance, frame_pointer,
581 : static_cast<uint32_t>(func_index), argument_values,
582 37381 : return_values);
583 : }
584 :
585 5285 : std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack(
586 : Address frame_pointer) {
587 5285 : return GetInterpreterHandle(*this)->GetInterpretedStack(frame_pointer);
588 : }
589 :
590 836 : wasm::WasmInterpreter::FramePtr WasmDebugInfo::GetInterpretedFrame(
591 : Address frame_pointer, int idx) {
592 836 : return GetInterpreterHandle(*this)->GetInterpretedFrame(frame_pointer, idx);
593 : }
594 :
595 51568 : uint64_t WasmDebugInfo::NumInterpretedCalls() {
596 51568 : auto* handle = GetInterpreterHandleOrNull(*this);
597 103136 : return handle ? handle->NumInterpretedCalls() : 0;
598 : }
599 :
600 : // static
601 464 : Handle<JSObject> WasmDebugInfo::GetGlobalScopeObject(
602 : Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
603 : auto* interp_handle = GetInterpreterHandle(*debug_info);
604 464 : auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
605 928 : return interp_handle->GetGlobalScopeObject(frame.get(), debug_info);
606 : }
607 :
608 : // static
609 464 : Handle<JSObject> WasmDebugInfo::GetLocalScopeObject(
610 : Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
611 : auto* interp_handle = GetInterpreterHandle(*debug_info);
612 464 : auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
613 928 : return interp_handle->GetLocalScopeObject(frame.get(), debug_info);
614 : }
615 :
616 : // static
617 8241 : Handle<JSFunction> WasmDebugInfo::GetCWasmEntry(
618 : Handle<WasmDebugInfo> debug_info, wasm::FunctionSig* sig) {
619 : Isolate* isolate = debug_info->GetIsolate();
620 : DCHECK_EQ(debug_info->has_c_wasm_entries(),
621 : debug_info->has_c_wasm_entry_map());
622 8241 : if (!debug_info->has_c_wasm_entries()) {
623 1539 : auto entries = isolate->factory()->NewFixedArray(4, AllocationType::kOld);
624 1539 : debug_info->set_c_wasm_entries(*entries);
625 : size_t map_size = 0; // size estimate not so important here.
626 1539 : auto managed_map = Managed<wasm::SignatureMap>::Allocate(isolate, map_size);
627 1539 : debug_info->set_c_wasm_entry_map(*managed_map);
628 : }
629 : Handle<FixedArray> entries(debug_info->c_wasm_entries(), isolate);
630 : wasm::SignatureMap* map = debug_info->c_wasm_entry_map()->raw();
631 8241 : int32_t index = map->Find(*sig);
632 8241 : if (index == -1) {
633 1715 : index = static_cast<int32_t>(map->FindOrInsert(*sig));
634 1715 : if (index == entries->length()) {
635 : entries = isolate->factory()->CopyFixedArrayAndGrow(
636 0 : entries, entries->length(), AllocationType::kOld);
637 0 : debug_info->set_c_wasm_entries(*entries);
638 : }
639 : DCHECK(entries->get(index)->IsUndefined(isolate));
640 : Handle<Code> new_entry_code =
641 3430 : compiler::CompileCWasmEntry(isolate, sig).ToHandleChecked();
642 : Handle<WasmExportedFunctionData> function_data =
643 : Handle<WasmExportedFunctionData>::cast(isolate->factory()->NewStruct(
644 1715 : WASM_EXPORTED_FUNCTION_DATA_TYPE, AllocationType::kOld));
645 1715 : function_data->set_wrapper_code(*new_entry_code);
646 1715 : function_data->set_instance(debug_info->wasm_instance());
647 : function_data->set_jump_table_offset(-1);
648 : function_data->set_function_index(-1);
649 : Handle<String> name = isolate->factory()->InternalizeOneByteString(
650 1715 : StaticCharVector("c-wasm-entry"));
651 : NewFunctionArgs args = NewFunctionArgs::ForWasm(
652 1715 : name, function_data, isolate->sloppy_function_map());
653 1715 : Handle<JSFunction> new_entry = isolate->factory()->NewFunction(args);
654 3430 : new_entry->set_context(debug_info->wasm_instance()->native_context());
655 : new_entry->shared()->set_internal_formal_parameter_count(
656 : compiler::CWasmEntryParameters::kNumParameters);
657 3430 : entries->set(index, *new_entry);
658 : }
659 8241 : return handle(JSFunction::cast(entries->get(index)), isolate);
660 : }
661 :
662 : } // namespace internal
663 122004 : } // namespace v8
|