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 570 : 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 570 : int len = SNPrintF(value, format, args...);
39 1140 : CHECK(len > 0 && len < value.length());
40 570 : Vector<uint8_t> name = Vector<uint8_t>::cast(value.SubVector(0, len));
41 : return internal
42 : ? isolate->factory()->InternalizeOneByteString(name)
43 625 : : isolate->factory()->NewStringFromOneByte(name).ToHandleChecked();
44 : }
45 :
46 990 : Handle<Object> WasmValueToValueObject(Isolate* isolate, WasmValue value) {
47 990 : switch (value.type()) {
48 : case kWasmI32:
49 : if (Smi::IsValid(value.to<int32_t>()))
50 805 : 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 85 : int32_t i32 = static_cast<int32_t>(i64);
55 85 : if (i32 == i64 && Smi::IsValid(i32))
56 30 : return handle(Smi::FromIntptr(i32), isolate);
57 55 : return PrintFToOneByteString<false>(isolate, "%" PRId64, i64);
58 : }
59 : case kWasmF32:
60 0 : return isolate->factory()->NewNumber(value.to<float>());
61 : case kWasmF64:
62 100 : return isolate->factory()->NewNumber(value.to<double>());
63 : default:
64 0 : UNIMPLEMENTED();
65 : return isolate->factory()->undefined_value();
66 : }
67 : }
68 :
69 740 : 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 1480 : if (!debug_info->has_locals_names()) {
75 : Handle<WasmModuleObject> module_object(
76 50 : debug_info->wasm_instance()->module_object(), isolate);
77 25 : Handle<FixedArray> locals_names = DecodeLocalNames(isolate, module_object);
78 25 : debug_info->set_locals_names(*locals_names);
79 : }
80 :
81 1480 : Handle<FixedArray> locals_names(debug_info->locals_names(), isolate);
82 1780 : if (func_index >= locals_names->length() ||
83 1040 : locals_names->get(func_index)->IsUndefined(isolate)) {
84 440 : return {};
85 : }
86 :
87 : Handle<FixedArray> func_locals_names(
88 : FixedArray::cast(locals_names->get(func_index)), isolate);
89 900 : if (local_index >= func_locals_names->length() ||
90 600 : func_locals_names->get(local_index)->IsUndefined(isolate)) {
91 75 : return {};
92 : }
93 225 : 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 39248 : uint32_t StartActivation(Address frame_pointer) {
106 39248 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
107 39248 : uint32_t activation_id = thread->StartActivation();
108 : DCHECK_EQ(0, activations_.count(frame_pointer));
109 78496 : activations_.insert(std::make_pair(frame_pointer, activation_id));
110 39248 : return activation_id;
111 : }
112 :
113 39248 : void FinishActivation(Address frame_pointer, uint32_t activation_id) {
114 39248 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
115 39248 : thread->FinishActivation(activation_id);
116 : DCHECK_EQ(1, activations_.count(frame_pointer));
117 : activations_.erase(frame_pointer);
118 39248 : }
119 :
120 6062 : std::pair<uint32_t, uint32_t> GetActivationFrameRange(
121 : WasmInterpreter::Thread* thread, Address frame_pointer) {
122 : DCHECK_EQ(1, activations_.count(frame_pointer));
123 6062 : uint32_t activation_id = activations_.find(frame_pointer)->second;
124 6062 : uint32_t num_activations = static_cast<uint32_t>(activations_.size() - 1);
125 6062 : uint32_t frame_base = thread->ActivationFrameBase(activation_id);
126 : uint32_t frame_limit = activation_id == num_activations
127 5945 : ? thread->GetFrameCount()
128 12007 : : thread->ActivationFrameBase(activation_id + 1);
129 : DCHECK_LE(frame_base, frame_limit);
130 : DCHECK_LE(frame_limit, thread->GetFrameCount());
131 6062 : return {frame_base, frame_limit};
132 : }
133 :
134 456796 : 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 456796 : debug_info->wasm_instance()->module_object()->native_module();
139 456796 : return ModuleWireBytes{native_module->wire_bytes()};
140 : }
141 :
142 : public:
143 456796 : InterpreterHandle(Isolate* isolate, Handle<WasmDebugInfo> debug_info)
144 : : isolate_(isolate),
145 913592 : module_(debug_info->wasm_instance()->module_object()->module()),
146 : interpreter_(isolate, module_, GetBytes(*debug_info),
147 2283980 : handle(debug_info->wasm_instance(), isolate)) {}
148 :
149 913592 : ~InterpreterHandle() { DCHECK_EQ(0, activations_.size()); }
150 :
151 : WasmInterpreter* interpreter() { return &interpreter_; }
152 : const WasmModule* module() const { return module_; }
153 :
154 : void PrepareStep(StepAction step_action) {
155 455 : next_step_action_ = step_action;
156 455 : last_step_stack_depth_ = CurrentStackDepth();
157 : }
158 :
159 685 : void ClearStepping() { next_step_action_ = StepNone; }
160 :
161 455 : int CurrentStackDepth() {
162 : DCHECK_EQ(1, interpreter()->GetThreadCount());
163 455 : 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 39248 : bool Execute(Handle<WasmInstanceObject> instance_object,
170 118439 : Address frame_pointer, uint32_t func_index, Address arg_buffer) {
171 : DCHECK_GE(module()->functions.size(), func_index);
172 248034 : FunctionSig* sig = module()->functions[func_index].sig;
173 : DCHECK_GE(kMaxInt, sig->parameter_count());
174 39248 : int num_params = static_cast<int>(sig->parameter_count());
175 : ScopedVector<WasmValue> wasm_args(num_params);
176 : Address arg_buf_ptr = arg_buffer;
177 54521 : for (int i = 0; i < num_params; ++i) {
178 : uint32_t param_size = static_cast<uint32_t>(
179 109042 : ValueTypes::ElementSizeInBytes(sig->GetParam(i)));
180 : #define CASE_ARG_TYPE(type, ctype) \
181 : case type: \
182 : DCHECK_EQ(param_size, sizeof(ctype)); \
183 : wasm_args[i] = WasmValue(ReadUnalignedValue<ctype>(arg_buf_ptr)); \
184 : break;
185 54521 : switch (sig->GetParam(i)) {
186 8415 : CASE_ARG_TYPE(kWasmI32, uint32_t)
187 18780 : CASE_ARG_TYPE(kWasmI64, uint64_t)
188 1725 : CASE_ARG_TYPE(kWasmF32, float)
189 25601 : CASE_ARG_TYPE(kWasmF64, double)
190 : #undef CASE_ARG_TYPE
191 : default:
192 0 : UNREACHABLE();
193 : }
194 54521 : arg_buf_ptr += param_size;
195 : }
196 :
197 39248 : uint32_t activation_id = StartActivation(frame_pointer);
198 :
199 39248 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
200 78496 : thread->InitFrame(&module()->functions[func_index], wasm_args.start());
201 : bool finished = false;
202 77949 : while (!finished) {
203 : // TODO(clemensh): Add occasional StackChecks.
204 39943 : WasmInterpreter::State state = ContinueExecution(thread);
205 39943 : switch (state) {
206 : case WasmInterpreter::State::PAUSED:
207 695 : NotifyDebugEventListeners(thread);
208 : break;
209 : case WasmInterpreter::State::FINISHED:
210 : // Perfect, just break the switch and exit the loop.
211 : finished = true;
212 : break;
213 : case WasmInterpreter::State::TRAPPED: {
214 : MessageTemplate message_id =
215 81 : WasmOpcodes::TrapReasonToMessageId(thread->GetTrapReason());
216 : Handle<Object> exception =
217 81 : isolate_->factory()->NewWasmRuntimeError(message_id);
218 81 : isolate_->Throw(*exception);
219 : // Handle this exception. Return without trying to read back the
220 : // return value.
221 81 : auto result = thread->HandleException(isolate_);
222 81 : return result == WasmInterpreter::Thread::HANDLED;
223 : } break;
224 : case WasmInterpreter::State::STOPPED:
225 : // An exception happened, and the current activation was unwound.
226 : DCHECK_EQ(thread->ActivationFrameBase(activation_id),
227 : thread->GetFrameCount());
228 : return false;
229 : // RUNNING should never occur here.
230 : case WasmInterpreter::State::RUNNING:
231 : default:
232 0 : UNREACHABLE();
233 : }
234 : }
235 :
236 : // Copy back the return value
237 : DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count());
238 : // TODO(wasm): Handle multi-value returns.
239 : DCHECK_EQ(1, kV8MaxWasmFunctionReturns);
240 38006 : if (sig->return_count()) {
241 37763 : WasmValue ret_val = thread->GetReturnValue(0);
242 : #define CASE_RET_TYPE(type, ctype) \
243 : case type: \
244 : DCHECK_EQ(ValueTypes::ElementSizeInBytes(sig->GetReturn(0)), \
245 : sizeof(ctype)); \
246 : WriteUnalignedValue<ctype>(arg_buffer, ret_val.to<ctype>()); \
247 : break;
248 37763 : switch (sig->GetReturn(0)) {
249 : CASE_RET_TYPE(kWasmI32, uint32_t)
250 : CASE_RET_TYPE(kWasmI64, uint64_t)
251 : CASE_RET_TYPE(kWasmF32, float)
252 : CASE_RET_TYPE(kWasmF64, double)
253 : #undef CASE_RET_TYPE
254 : default:
255 0 : UNREACHABLE();
256 : }
257 : }
258 :
259 38006 : FinishActivation(frame_pointer, activation_id);
260 :
261 : return true;
262 : }
263 :
264 39943 : WasmInterpreter::State ContinueExecution(WasmInterpreter::Thread* thread) {
265 39943 : switch (next_step_action_) {
266 : case StepNone:
267 39478 : return thread->Run();
268 : case StepIn:
269 : return thread->Step();
270 : case StepOut:
271 40 : thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterReturn);
272 40 : return thread->Run();
273 : case StepNext: {
274 135 : int stack_depth = thread->GetFrameCount();
275 135 : if (stack_depth == last_step_stack_depth_) return thread->Step();
276 : thread->AddBreakFlags(stack_depth > last_step_stack_depth_
277 : ? WasmInterpreter::BreakFlag::AfterReturn
278 10 : : WasmInterpreter::BreakFlag::AfterCall);
279 10 : return thread->Run();
280 : }
281 : default:
282 0 : UNREACHABLE();
283 : }
284 : }
285 :
286 695 : Handle<WasmInstanceObject> GetInstanceObject() {
287 695 : StackTraceFrameIterator it(isolate_);
288 : WasmInterpreterEntryFrame* frame =
289 : WasmInterpreterEntryFrame::cast(it.frame());
290 695 : Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_);
291 : // Check that this is indeed the instance which is connected to this
292 : // interpreter.
293 : DCHECK_EQ(this, Managed<InterpreterHandle>::cast(
294 : instance_obj->debug_info()->interpreter_handle())
295 : ->raw());
296 1390 : return instance_obj;
297 : }
298 :
299 695 : void NotifyDebugEventListeners(WasmInterpreter::Thread* thread) {
300 : // Enter the debugger.
301 2075 : DebugScope debug_scope(isolate_->debug());
302 :
303 : // Check whether we hit a breakpoint.
304 1390 : if (isolate_->debug()->break_points_active()) {
305 : Handle<WasmModuleObject> module_object(
306 2085 : GetInstanceObject()->module_object(), isolate_);
307 695 : int position = GetTopPosition(module_object);
308 : Handle<FixedArray> breakpoints;
309 1390 : if (WasmModuleObject::CheckBreakPoints(isolate_, module_object, position)
310 1390 : .ToHandle(&breakpoints)) {
311 : // We hit one or several breakpoints. Clear stepping, notify the
312 : // listeners and return.
313 : ClearStepping();
314 530 : isolate_->debug()->OnDebugBreak(breakpoints);
315 265 : return;
316 : }
317 : }
318 :
319 : // We did not hit a breakpoint, so maybe this pause is related to stepping.
320 : bool hit_step = false;
321 430 : switch (next_step_action_) {
322 : case StepNone:
323 : break;
324 : case StepIn:
325 : hit_step = true;
326 270 : break;
327 : case StepOut:
328 30 : hit_step = thread->GetFrameCount() < last_step_stack_depth_;
329 30 : break;
330 : case StepNext: {
331 130 : hit_step = thread->GetFrameCount() == last_step_stack_depth_;
332 130 : break;
333 : }
334 : default:
335 0 : UNREACHABLE();
336 : }
337 430 : if (!hit_step) return;
338 : ClearStepping();
339 840 : isolate_->debug()->OnDebugBreak(isolate_->factory()->empty_fixed_array());
340 : }
341 :
342 695 : int GetTopPosition(Handle<WasmModuleObject> module_object) {
343 : DCHECK_EQ(1, interpreter()->GetThreadCount());
344 695 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
345 : DCHECK_LT(0, thread->GetFrameCount());
346 :
347 695 : auto frame = thread->GetFrame(thread->GetFrameCount() - 1);
348 2085 : return module_object->GetFunctionOffset(frame->function()->func_index) +
349 1390 : frame->pc();
350 : }
351 :
352 3872 : std::vector<std::pair<uint32_t, int>> GetInterpretedStack(
353 : Address frame_pointer) {
354 : DCHECK_EQ(1, interpreter()->GetThreadCount());
355 3872 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
356 :
357 : std::pair<uint32_t, uint32_t> frame_range =
358 3872 : GetActivationFrameRange(thread, frame_pointer);
359 :
360 : std::vector<std::pair<uint32_t, int>> stack;
361 3872 : stack.reserve(frame_range.second - frame_range.first);
362 764766 : for (uint32_t fp = frame_range.first; fp < frame_range.second; ++fp) {
363 760894 : auto frame = thread->GetFrame(fp);
364 1521788 : stack.emplace_back(frame->function()->func_index, frame->pc());
365 : }
366 3872 : return stack;
367 : }
368 :
369 2190 : WasmInterpreter::FramePtr GetInterpretedFrame(Address frame_pointer,
370 : int idx) {
371 : DCHECK_EQ(1, interpreter()->GetThreadCount());
372 2190 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
373 :
374 : std::pair<uint32_t, uint32_t> frame_range =
375 2190 : GetActivationFrameRange(thread, frame_pointer);
376 : DCHECK_LE(0, idx);
377 : DCHECK_GT(frame_range.second - frame_range.first, idx);
378 :
379 2190 : return thread->GetFrame(frame_range.first + idx);
380 : }
381 :
382 1242 : void Unwind(Address frame_pointer) {
383 : // Find the current activation.
384 : DCHECK_EQ(1, activations_.count(frame_pointer));
385 : // Activations must be properly stacked:
386 : DCHECK_EQ(activations_.size() - 1, activations_[frame_pointer]);
387 1242 : uint32_t activation_id = static_cast<uint32_t>(activations_.size() - 1);
388 :
389 : // Unwind the frames of the current activation if not already unwound.
390 1242 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
391 2484 : if (static_cast<uint32_t>(thread->GetFrameCount()) >
392 1242 : thread->ActivationFrameBase(activation_id)) {
393 : using ExceptionResult = WasmInterpreter::Thread::ExceptionHandlingResult;
394 0 : ExceptionResult result = thread->HandleException(isolate_);
395 : // TODO(wasm): Handle exceptions caught in wasm land.
396 0 : CHECK_EQ(ExceptionResult::UNWOUND, result);
397 : }
398 :
399 1242 : FinishActivation(frame_pointer, activation_id);
400 1242 : }
401 :
402 64488 : uint64_t NumInterpretedCalls() {
403 : DCHECK_EQ(1, interpreter()->GetThreadCount());
404 64488 : return interpreter()->GetThread(0)->NumInterpretedCalls();
405 : }
406 :
407 575 : Handle<JSObject> GetGlobalScopeObject(InterpretedFrame* frame,
408 : Handle<WasmDebugInfo> debug_info) {
409 575 : Isolate* isolate = isolate_;
410 1150 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
411 :
412 : // TODO(clemensh): Add globals to the global scope.
413 : Handle<JSObject> global_scope_object =
414 575 : isolate_->factory()->NewJSObjectWithNullProto();
415 1150 : if (instance->has_memory_object()) {
416 : Handle<String> name = isolate_->factory()->InternalizeOneByteString(
417 0 : StaticCharVector("memory"));
418 : Handle<JSArrayBuffer> memory_buffer(
419 0 : instance->memory_object()->array_buffer(), isolate_);
420 : Handle<JSTypedArray> uint8_array = isolate_->factory()->NewJSTypedArray(
421 0 : kExternalUint8Array, memory_buffer, 0, memory_buffer->byte_length());
422 : JSObject::SetOwnPropertyIgnoreAttributes(global_scope_object, name,
423 0 : uint8_array, NONE)
424 0 : .Assert();
425 : }
426 575 : return global_scope_object;
427 : }
428 :
429 575 : Handle<JSObject> GetLocalScopeObject(InterpretedFrame* frame,
430 : Handle<WasmDebugInfo> debug_info) {
431 575 : Isolate* isolate = isolate_;
432 :
433 : Handle<JSObject> local_scope_object =
434 575 : isolate_->factory()->NewJSObjectWithNullProto();
435 : // Fill parameters and locals.
436 575 : int num_params = frame->GetParameterCount();
437 575 : int num_locals = frame->GetLocalCount();
438 : DCHECK_LE(num_params, num_locals);
439 575 : if (num_locals > 0) {
440 : Handle<JSObject> locals_obj =
441 515 : isolate_->factory()->NewJSObjectWithNullProto();
442 : Handle<String> locals_name =
443 : isolate_->factory()->InternalizeOneByteString(
444 515 : StaticCharVector("locals"));
445 : JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, locals_name,
446 515 : locals_obj, NONE)
447 515 : .Assert();
448 740 : for (int i = 0; i < num_locals; ++i) {
449 : MaybeHandle<String> name =
450 740 : GetLocalName(isolate, debug_info, frame->function()->func_index, i);
451 740 : if (name.is_null()) {
452 : // Parameters should come before locals in alphabetical ordering, so
453 : // we name them "args" here.
454 515 : const char* label = i < num_params ? "arg#%d" : "local#%d";
455 515 : name = PrintFToOneByteString<true>(isolate_, label, i);
456 : }
457 740 : WasmValue value = frame->GetLocalValue(i);
458 740 : Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
459 : JSObject::SetOwnPropertyIgnoreAttributes(
460 740 : locals_obj, name.ToHandleChecked(), value_obj, NONE)
461 740 : .Assert();
462 : }
463 : }
464 :
465 : // Fill stack values.
466 575 : int stack_count = frame->GetStackHeight();
467 : // Use an object without prototype instead of an Array, for nicer displaying
468 : // in DevTools. For Arrays, the length field and prototype is displayed,
469 : // which does not make too much sense here.
470 : Handle<JSObject> stack_obj =
471 575 : isolate_->factory()->NewJSObjectWithNullProto();
472 : Handle<String> stack_name = isolate_->factory()->InternalizeOneByteString(
473 575 : StaticCharVector("stack"));
474 : JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, stack_name,
475 575 : stack_obj, NONE)
476 575 : .Assert();
477 250 : for (int i = 0; i < stack_count; ++i) {
478 250 : WasmValue value = frame->GetStackValue(i);
479 250 : Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
480 : JSObject::SetOwnElementIgnoreAttributes(
481 250 : stack_obj, static_cast<uint32_t>(i), value_obj, NONE)
482 250 : .Assert();
483 : }
484 575 : return local_scope_object;
485 : }
486 :
487 0 : Handle<JSArray> GetScopeDetails(Address frame_pointer, int frame_index,
488 : Handle<WasmDebugInfo> debug_info) {
489 0 : auto frame = GetInterpretedFrame(frame_pointer, frame_index);
490 :
491 : Handle<FixedArray> global_scope =
492 0 : isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
493 : global_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
494 : Smi::FromInt(ScopeIterator::ScopeTypeGlobal));
495 : Handle<JSObject> global_scope_object =
496 0 : GetGlobalScopeObject(frame.get(), debug_info);
497 : global_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
498 0 : *global_scope_object);
499 :
500 : Handle<FixedArray> local_scope =
501 0 : isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
502 : local_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
503 : Smi::FromInt(ScopeIterator::ScopeTypeLocal));
504 : Handle<JSObject> local_scope_object =
505 0 : GetLocalScopeObject(frame.get(), debug_info);
506 : local_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
507 0 : *local_scope_object);
508 :
509 : Handle<JSArray> global_jsarr =
510 0 : isolate_->factory()->NewJSArrayWithElements(global_scope);
511 : Handle<JSArray> local_jsarr =
512 0 : isolate_->factory()->NewJSArrayWithElements(local_scope);
513 0 : Handle<FixedArray> all_scopes = isolate_->factory()->NewFixedArray(2);
514 0 : all_scopes->set(0, *global_jsarr);
515 0 : all_scopes->set(1, *local_jsarr);
516 0 : return isolate_->factory()->NewJSArrayWithElements(all_scopes);
517 : }
518 : };
519 :
520 : } // namespace
521 :
522 : } // namespace wasm
523 :
524 : namespace {
525 :
526 40597 : wasm::InterpreterHandle* GetOrCreateInterpreterHandle(
527 : Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
528 81194 : Handle<Object> handle(debug_info->interpreter_handle(), isolate);
529 81194 : if (handle->IsUndefined(isolate)) {
530 : // Use the maximum stack size to estimate the maximum size of the
531 : // interpreter. The interpreter keeps its own stack internally, and the size
532 : // of the stack should dominate the overall size of the interpreter. We
533 : // multiply by '2' to account for the growing strategy for the backing store
534 : // of the stack.
535 1054 : size_t interpreter_size = FLAG_stack_size * KB * 2;
536 : handle = Managed<wasm::InterpreterHandle>::Allocate(
537 1054 : isolate, interpreter_size, isolate, debug_info);
538 1054 : debug_info->set_interpreter_handle(*handle);
539 : }
540 :
541 81194 : return Handle<Managed<wasm::InterpreterHandle>>::cast(handle)->raw();
542 : }
543 :
544 7759 : wasm::InterpreterHandle* GetInterpreterHandle(WasmDebugInfo debug_info) {
545 7759 : Object handle_obj = debug_info->interpreter_handle();
546 : DCHECK(!handle_obj->IsUndefined());
547 15518 : return Managed<wasm::InterpreterHandle>::cast(handle_obj)->raw();
548 : }
549 :
550 64488 : wasm::InterpreterHandle* GetInterpreterHandleOrNull(WasmDebugInfo debug_info) {
551 64488 : Object handle_obj = debug_info->interpreter_handle();
552 64488 : if (handle_obj->IsUndefined()) return nullptr;
553 128976 : return Managed<wasm::InterpreterHandle>::cast(handle_obj)->raw();
554 : }
555 :
556 1169 : Handle<FixedArray> GetOrCreateInterpretedFunctions(
557 : Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
558 2338 : Handle<FixedArray> arr(debug_info->interpreted_functions(), isolate);
559 2338 : int num_functions = debug_info->wasm_instance()
560 2338 : ->module_object()
561 : ->native_module()
562 2338 : ->num_functions();
563 1169 : if (arr->length() == 0 && num_functions > 0) {
564 1045 : arr = isolate->factory()->NewFixedArray(num_functions);
565 1045 : debug_info->set_interpreted_functions(*arr);
566 : }
567 : DCHECK_EQ(num_functions, arr->length());
568 1169 : return arr;
569 : }
570 :
571 : } // namespace
572 :
573 456826 : Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<WasmInstanceObject> instance) {
574 : DCHECK(!instance->has_debug_info());
575 : Factory* factory = instance->GetIsolate()->factory();
576 : Handle<WasmDebugInfo> debug_info = Handle<WasmDebugInfo>::cast(
577 456826 : factory->NewStruct(WASM_DEBUG_INFO_TYPE, TENURED));
578 456826 : debug_info->set_wasm_instance(*instance);
579 456826 : debug_info->set_interpreted_functions(*factory->empty_fixed_array());
580 456826 : instance->set_debug_info(*debug_info);
581 456826 : return debug_info;
582 : }
583 :
584 455742 : wasm::WasmInterpreter* WasmDebugInfo::SetupForTesting(
585 : Handle<WasmInstanceObject> instance_obj) {
586 455742 : Handle<WasmDebugInfo> debug_info = WasmDebugInfo::New(instance_obj);
587 : Isolate* isolate = instance_obj->GetIsolate();
588 : // Use the maximum stack size to estimate the maximum size of the interpreter.
589 : // The interpreter keeps its own stack internally, and the size of the stack
590 : // should dominate the overall size of the interpreter. We multiply by '2' to
591 : // account for the growing strategy for the backing store of the stack.
592 455742 : size_t interpreter_size = FLAG_stack_size * KB * 2;
593 : auto interp_handle = Managed<wasm::InterpreterHandle>::Allocate(
594 455742 : isolate, interpreter_size, isolate, debug_info);
595 911484 : debug_info->set_interpreter_handle(*interp_handle);
596 911484 : auto ret = interp_handle->raw()->interpreter();
597 455742 : ret->SetCallIndirectTestMode();
598 455742 : return ret;
599 : }
600 :
601 180 : void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
602 : int func_index, int offset) {
603 : Isolate* isolate = debug_info->GetIsolate();
604 360 : auto* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
605 180 : RedirectToInterpreter(debug_info, Vector<int>(&func_index, 1));
606 360 : const wasm::WasmFunction* func = &handle->module()->functions[func_index];
607 180 : handle->interpreter()->SetBreakpoint(func, offset, true);
608 180 : }
609 :
610 1169 : void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
611 : Vector<int> func_indexes) {
612 : Isolate* isolate = debug_info->GetIsolate();
613 : // Ensure that the interpreter is instantiated.
614 1169 : GetOrCreateInterpreterHandle(isolate, debug_info);
615 : Handle<FixedArray> interpreted_functions =
616 1169 : GetOrCreateInterpretedFunctions(isolate, debug_info);
617 2338 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
618 : wasm::NativeModule* native_module =
619 1169 : instance->module_object()->native_module();
620 1169 : const wasm::WasmModule* module = instance->module();
621 :
622 : // We may modify the wasm jump table.
623 : wasm::NativeModuleModificationScope native_module_modification_scope(
624 1169 : native_module);
625 :
626 2493 : for (int func_index : func_indexes) {
627 : DCHECK_LE(0, func_index);
628 : DCHECK_GT(module->functions.size(), func_index);
629 2758 : if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) continue;
630 :
631 : wasm::WasmCode* wasm_new_code = compiler::CompileWasmInterpreterEntry(
632 : isolate->wasm_engine(), native_module, func_index,
633 3642 : module->functions[func_index].sig);
634 1214 : native_module->PublishInterpreterEntry(wasm_new_code, func_index);
635 : Handle<Foreign> foreign_holder = isolate->factory()->NewForeign(
636 1214 : wasm_new_code->instruction_start(), TENURED);
637 2428 : interpreted_functions->set(func_index, *foreign_holder);
638 1169 : }
639 1169 : }
640 :
641 455 : void WasmDebugInfo::PrepareStep(StepAction step_action) {
642 455 : GetInterpreterHandle(*this)->PrepareStep(step_action);
643 455 : }
644 :
645 : // static
646 39248 : bool WasmDebugInfo::RunInterpreter(Isolate* isolate,
647 : Handle<WasmDebugInfo> debug_info,
648 : Address frame_pointer, int func_index,
649 : Address arg_buffer) {
650 : DCHECK_LE(0, func_index);
651 39248 : auto* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
652 78496 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
653 : return handle->Execute(instance, frame_pointer,
654 39248 : static_cast<uint32_t>(func_index), arg_buffer);
655 : }
656 :
657 3872 : std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack(
658 : Address frame_pointer) {
659 3872 : return GetInterpreterHandle(*this)->GetInterpretedStack(frame_pointer);
660 : }
661 :
662 1040 : wasm::WasmInterpreter::FramePtr WasmDebugInfo::GetInterpretedFrame(
663 : Address frame_pointer, int idx) {
664 1040 : return GetInterpreterHandle(*this)->GetInterpretedFrame(frame_pointer, idx);
665 : }
666 :
667 1242 : void WasmDebugInfo::Unwind(Address frame_pointer) {
668 1242 : return GetInterpreterHandle(*this)->Unwind(frame_pointer);
669 : }
670 :
671 64488 : uint64_t WasmDebugInfo::NumInterpretedCalls() {
672 64488 : auto* handle = GetInterpreterHandleOrNull(*this);
673 64488 : return handle ? handle->NumInterpretedCalls() : 0;
674 : }
675 :
676 : // static
677 0 : Handle<JSObject> WasmDebugInfo::GetScopeDetails(
678 : Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
679 0 : auto* interp_handle = GetInterpreterHandle(*debug_info);
680 0 : return interp_handle->GetScopeDetails(frame_pointer, frame_index, debug_info);
681 : }
682 :
683 : // static
684 575 : Handle<JSObject> WasmDebugInfo::GetGlobalScopeObject(
685 : Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
686 575 : auto* interp_handle = GetInterpreterHandle(*debug_info);
687 575 : auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
688 1150 : return interp_handle->GetGlobalScopeObject(frame.get(), debug_info);
689 : }
690 :
691 : // static
692 575 : Handle<JSObject> WasmDebugInfo::GetLocalScopeObject(
693 : Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
694 575 : auto* interp_handle = GetInterpreterHandle(*debug_info);
695 575 : auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
696 1150 : return interp_handle->GetLocalScopeObject(frame.get(), debug_info);
697 : }
698 :
699 : // static
700 6780 : Handle<JSFunction> WasmDebugInfo::GetCWasmEntry(
701 : Handle<WasmDebugInfo> debug_info, wasm::FunctionSig* sig) {
702 : Isolate* isolate = debug_info->GetIsolate();
703 : DCHECK_EQ(debug_info->has_c_wasm_entries(),
704 : debug_info->has_c_wasm_entry_map());
705 13560 : if (!debug_info->has_c_wasm_entries()) {
706 768 : auto entries = isolate->factory()->NewFixedArray(4, TENURED);
707 768 : debug_info->set_c_wasm_entries(*entries);
708 : size_t map_size = 0; // size estimate not so important here.
709 768 : auto managed_map = Managed<wasm::SignatureMap>::Allocate(isolate, map_size);
710 768 : debug_info->set_c_wasm_entry_map(*managed_map);
711 : }
712 13560 : Handle<FixedArray> entries(debug_info->c_wasm_entries(), isolate);
713 13560 : wasm::SignatureMap* map = debug_info->c_wasm_entry_map()->raw();
714 6780 : int32_t index = map->Find(*sig);
715 6780 : if (index == -1) {
716 786 : index = static_cast<int32_t>(map->FindOrInsert(*sig));
717 786 : if (index == entries->length()) {
718 : entries = isolate->factory()->CopyFixedArrayAndGrow(
719 0 : entries, entries->length(), TENURED);
720 0 : debug_info->set_c_wasm_entries(*entries);
721 : }
722 : DCHECK(entries->get(index)->IsUndefined(isolate));
723 : Handle<Code> new_entry_code =
724 1572 : compiler::CompileCWasmEntry(isolate, sig).ToHandleChecked();
725 : Handle<WasmExportedFunctionData> function_data =
726 : Handle<WasmExportedFunctionData>::cast(isolate->factory()->NewStruct(
727 786 : WASM_EXPORTED_FUNCTION_DATA_TYPE, TENURED));
728 786 : function_data->set_wrapper_code(*new_entry_code);
729 1572 : function_data->set_instance(debug_info->wasm_instance());
730 : function_data->set_jump_table_offset(-1);
731 : function_data->set_function_index(-1);
732 : Handle<String> name = isolate->factory()->InternalizeOneByteString(
733 786 : StaticCharVector("c-wasm-entry"));
734 : NewFunctionArgs args = NewFunctionArgs::ForWasm(
735 786 : name, function_data, isolate->sloppy_function_map());
736 786 : Handle<JSFunction> new_entry = isolate->factory()->NewFunction(args);
737 1572 : new_entry->set_context(debug_info->wasm_instance()->native_context());
738 1572 : new_entry->shared()->set_internal_formal_parameter_count(
739 1572 : compiler::CWasmEntryParameters::kNumParameters);
740 1572 : entries->set(index, *new_entry);
741 : }
742 6780 : return handle(JSFunction::cast(entries->get(index)), isolate);
743 : }
744 :
745 : } // namespace internal
746 183867 : } // namespace v8
|