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-inl.h"
21 : #include "src/zone/accounting-allocator.h"
22 :
23 : namespace v8 {
24 : namespace internal {
25 : namespace wasm {
26 :
27 : namespace {
28 :
29 : template <bool internal, typename... Args>
30 250 : Handle<String> PrintFToOneByteString(Isolate* isolate, const char* format,
31 : Args... args) {
32 : // Maximum length of a formatted value name ("param#%d", "local#%d",
33 : // "global#%d").
34 : constexpr int kMaxStrLen = 18;
35 : EmbeddedVector<char, kMaxStrLen> value;
36 250 : int len = SNPrintF(value, format, args...);
37 500 : CHECK(len > 0 && len < value.length());
38 250 : Vector<uint8_t> name = Vector<uint8_t>::cast(value.SubVector(0, len));
39 : return internal
40 : ? isolate->factory()->InternalizeOneByteString(name)
41 250 : : isolate->factory()->NewStringFromOneByte(name).ToHandleChecked();
42 : }
43 :
44 455 : Handle<Object> WasmValueToValueObject(Isolate* isolate, WasmValue value) {
45 455 : switch (value.type()) {
46 : case kWasmI32:
47 : if (Smi::IsValid(value.to<int32_t>()))
48 375 : return handle(Smi::FromInt(value.to<int32_t>()), isolate);
49 : return PrintFToOneByteString<false>(isolate, "%d", value.to<int32_t>());
50 : case kWasmI64:
51 0 : if (Smi::IsValid(value.to<int64_t>()))
52 0 : return handle(Smi::FromIntptr(value.to<int64_t>()), isolate);
53 : return PrintFToOneByteString<false>(isolate, "%" PRId64,
54 0 : value.to<int64_t>());
55 : case kWasmF32:
56 0 : return isolate->factory()->NewNumber(value.to<float>());
57 : case kWasmF64:
58 80 : return isolate->factory()->NewNumber(value.to<double>());
59 : default:
60 0 : UNIMPLEMENTED();
61 : return isolate->factory()->undefined_value();
62 : }
63 : }
64 :
65 360 : MaybeHandle<String> GetLocalName(Isolate* isolate,
66 : Handle<WasmDebugInfo> debug_info,
67 : int func_index, int local_index) {
68 : DCHECK_LE(0, func_index);
69 : DCHECK_LE(0, local_index);
70 360 : if (!debug_info->has_locals_names()) {
71 : Handle<WasmCompiledModule> compiled_module(
72 : debug_info->wasm_instance()->compiled_module(), isolate);
73 : Handle<FixedArray> locals_names =
74 15 : wasm::DecodeLocalNames(isolate, compiled_module);
75 15 : debug_info->set_locals_names(*locals_names);
76 : }
77 :
78 : Handle<FixedArray> locals_names(debug_info->locals_names(), isolate);
79 525 : if (func_index >= locals_names->length() ||
80 : locals_names->get(func_index)->IsUndefined(isolate)) {
81 195 : return {};
82 : }
83 :
84 : Handle<FixedArray> func_locals_names(
85 : FixedArray::cast(locals_names->get(func_index)), isolate);
86 330 : if (local_index >= func_locals_names->length() ||
87 : func_locals_names->get(local_index)->IsUndefined(isolate)) {
88 55 : return {};
89 : }
90 110 : return handle(String::cast(func_locals_names->get(local_index)));
91 : }
92 :
93 : class InterpreterHandle {
94 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(InterpreterHandle);
95 : Isolate* isolate_;
96 : const WasmModule* module_;
97 : WasmInterpreter interpreter_;
98 : StepAction next_step_action_ = StepNone;
99 : int last_step_stack_depth_ = 0;
100 : std::unordered_map<Address, uint32_t> activations_;
101 :
102 45144 : uint32_t StartActivation(Address frame_pointer) {
103 45144 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
104 45144 : uint32_t activation_id = thread->StartActivation();
105 : DCHECK_EQ(0, activations_.count(frame_pointer));
106 90288 : activations_.insert(std::make_pair(frame_pointer, activation_id));
107 45144 : return activation_id;
108 : }
109 :
110 45144 : void FinishActivation(Address frame_pointer, uint32_t activation_id) {
111 45144 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
112 45144 : thread->FinishActivation(activation_id);
113 : DCHECK_EQ(1, activations_.count(frame_pointer));
114 : activations_.erase(frame_pointer);
115 45144 : }
116 :
117 3800 : std::pair<uint32_t, uint32_t> GetActivationFrameRange(
118 : WasmInterpreter::Thread* thread, Address frame_pointer) {
119 : DCHECK_EQ(1, activations_.count(frame_pointer));
120 3800 : uint32_t activation_id = activations_.find(frame_pointer)->second;
121 3800 : uint32_t num_activations = static_cast<uint32_t>(activations_.size() - 1);
122 3800 : uint32_t frame_base = thread->ActivationFrameBase(activation_id);
123 : uint32_t frame_limit = activation_id == num_activations
124 3710 : ? thread->GetFrameCount()
125 7510 : : thread->ActivationFrameBase(activation_id + 1);
126 : DCHECK_LE(frame_base, frame_limit);
127 : DCHECK_LE(frame_limit, thread->GetFrameCount());
128 3800 : return {frame_base, frame_limit};
129 : }
130 :
131 18637 : static Vector<const byte> GetBytes(WasmDebugInfo* debug_info) {
132 : // Return raw pointer into heap. The WasmInterpreter will make its own copy
133 : // of this data anyway, and there is no heap allocation in-between.
134 : SeqOneByteString* bytes_str =
135 : debug_info->wasm_instance()->compiled_module()->module_bytes();
136 18637 : return {bytes_str->GetChars(), static_cast<size_t>(bytes_str->length())};
137 : }
138 :
139 : public:
140 18637 : InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info)
141 : : isolate_(isolate),
142 18637 : module_(debug_info->wasm_instance()->compiled_module()->module()),
143 : interpreter_(isolate, module_, GetBytes(debug_info),
144 93185 : debug_info->wasm_instance()->wasm_context()->get()) {}
145 :
146 37234 : ~InterpreterHandle() { DCHECK_EQ(0, activations_.size()); }
147 :
148 : WasmInterpreter* interpreter() { return &interpreter_; }
149 : const WasmModule* module() const { return module_; }
150 :
151 : void PrepareStep(StepAction step_action) {
152 261 : next_step_action_ = step_action;
153 261 : last_step_stack_depth_ = CurrentStackDepth();
154 : }
155 :
156 349 : void ClearStepping() { next_step_action_ = StepNone; }
157 :
158 261 : int CurrentStackDepth() {
159 : DCHECK_EQ(1, interpreter()->GetThreadCount());
160 261 : return interpreter()->GetThread(0)->GetFrameCount();
161 : }
162 :
163 : // Returns true if exited regularly, false if a trap/exception occurred and
164 : // was not handled inside this activation. In the latter case, a pending
165 : // exception will have been set on the isolate.
166 45144 : bool Execute(Handle<WasmInstanceObject> instance_object,
167 : Address frame_pointer, uint32_t func_index,
168 135786 : uint8_t* arg_buffer) {
169 : DCHECK_GE(module()->functions.size(), func_index);
170 288643 : FunctionSig* sig = module()->functions[func_index].sig;
171 : DCHECK_GE(kMaxInt, sig->parameter_count());
172 45144 : int num_params = static_cast<int>(sig->parameter_count());
173 : ScopedVector<WasmValue> wasm_args(num_params);
174 : uint8_t* arg_buf_ptr = arg_buffer;
175 108733 : for (int i = 0; i < num_params; ++i) {
176 127178 : uint32_t param_size = 1 << ElementSizeLog2Of(sig->GetParam(i));
177 : #define CASE_ARG_TYPE(type, ctype) \
178 : case type: \
179 : DCHECK_EQ(param_size, sizeof(ctype)); \
180 : wasm_args[i] = WasmValue(ReadUnalignedValue<ctype>(arg_buf_ptr)); \
181 : break;
182 63589 : switch (sig->GetParam(i)) {
183 8265 : CASE_ARG_TYPE(kWasmI32, uint32_t)
184 22536 : CASE_ARG_TYPE(kWasmI64, uint64_t)
185 2070 : CASE_ARG_TYPE(kWasmF32, float)
186 30718 : CASE_ARG_TYPE(kWasmF64, double)
187 : #undef CASE_ARG_TYPE
188 : default:
189 0 : UNREACHABLE();
190 : }
191 63589 : arg_buf_ptr += param_size;
192 : }
193 :
194 45144 : uint32_t activation_id = StartActivation(frame_pointer);
195 :
196 : WasmInterpreter::HeapObjectsScope heap_objects_scope(&interpreter_,
197 45144 : instance_object);
198 45144 : WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
199 90288 : thread->InitFrame(&module()->functions[func_index], wasm_args.start());
200 : bool finished = false;
201 45144 : while (!finished) {
202 : // TODO(clemensh): Add occasional StackChecks.
203 45498 : WasmInterpreter::State state = ContinueExecution(thread);
204 45498 : switch (state) {
205 : case WasmInterpreter::State::PAUSED:
206 354 : NotifyDebugEventListeners(thread);
207 354 : break;
208 : case WasmInterpreter::State::FINISHED:
209 : // Perfect, just break the switch and exit the loop.
210 : finished = true;
211 : break;
212 : case WasmInterpreter::State::TRAPPED: {
213 : int message_id =
214 100 : WasmOpcodes::TrapReasonToMessageId(thread->GetTrapReason());
215 : Handle<Object> exception = isolate_->factory()->NewWasmRuntimeError(
216 100 : static_cast<MessageTemplate::Template>(message_id));
217 100 : isolate_->Throw(*exception);
218 : // Handle this exception. Return without trying to read back the
219 : // return value.
220 100 : auto result = thread->HandleException(isolate_);
221 100 : return result == WasmInterpreter::Thread::HANDLED;
222 : } break;
223 : case WasmInterpreter::State::STOPPED:
224 : // An exception happened, and the current activation was unwound.
225 : DCHECK_EQ(thread->ActivationFrameBase(activation_id),
226 : thread->GetFrameCount());
227 : return false;
228 : // RUNNING should never occur here.
229 : case WasmInterpreter::State::RUNNING:
230 : default:
231 0 : UNREACHABLE();
232 : }
233 : }
234 :
235 : // Copy back the return value
236 : DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count());
237 : // TODO(wasm): Handle multi-value returns.
238 : DCHECK_EQ(1, kV8MaxWasmFunctionReturns);
239 44934 : if (sig->return_count()) {
240 44688 : WasmValue ret_val = thread->GetReturnValue(0);
241 : #define CASE_RET_TYPE(type, ctype) \
242 : case type: \
243 : DCHECK_EQ(1 << ElementSizeLog2Of(sig->GetReturn(0)), sizeof(ctype)); \
244 : WriteUnalignedValue<ctype>(arg_buffer, ret_val.to<ctype>()); \
245 : break;
246 44688 : switch (sig->GetReturn(0)) {
247 : CASE_RET_TYPE(kWasmI32, uint32_t)
248 : CASE_RET_TYPE(kWasmI64, uint64_t)
249 : CASE_RET_TYPE(kWasmF32, float)
250 : CASE_RET_TYPE(kWasmF64, double)
251 : #undef CASE_RET_TYPE
252 : default:
253 0 : UNREACHABLE();
254 : }
255 : }
256 :
257 44934 : FinishActivation(frame_pointer, activation_id);
258 :
259 44934 : return true;
260 : }
261 :
262 45498 : WasmInterpreter::State ContinueExecution(WasmInterpreter::Thread* thread) {
263 45498 : switch (next_step_action_) {
264 : case StepNone:
265 45232 : return thread->Run();
266 : case StepIn:
267 : return thread->Step();
268 : case StepOut:
269 21 : thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterReturn);
270 21 : return thread->Run();
271 : case StepNext: {
272 87 : int stack_depth = thread->GetFrameCount();
273 87 : if (stack_depth == last_step_stack_depth_) return thread->Step();
274 : thread->AddBreakFlags(stack_depth > last_step_stack_depth_
275 : ? WasmInterpreter::BreakFlag::AfterReturn
276 5 : : WasmInterpreter::BreakFlag::AfterCall);
277 5 : return thread->Run();
278 : }
279 : default:
280 0 : UNREACHABLE();
281 : }
282 : }
283 :
284 354 : Handle<WasmInstanceObject> GetInstanceObject() {
285 354 : StackTraceFrameIterator it(isolate_);
286 : WasmInterpreterEntryFrame* frame =
287 : WasmInterpreterEntryFrame::cast(it.frame());
288 354 : Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_);
289 : // Check that this is indeed the instance which is connected to this
290 : // interpreter.
291 : DCHECK_EQ(this, Managed<wasm::InterpreterHandle>::cast(
292 : instance_obj->debug_info()->get(
293 : WasmDebugInfo::kInterpreterHandleIndex))
294 : ->get());
295 708 : return instance_obj;
296 : }
297 :
298 354 : void NotifyDebugEventListeners(WasmInterpreter::Thread* thread) {
299 : // Enter the debugger.
300 1057 : DebugScope debug_scope(isolate_->debug());
301 468 : if (debug_scope.failed()) return;
302 :
303 : // Postpone interrupt during breakpoint processing.
304 354 : PostponeInterruptsScope postpone(isolate_);
305 :
306 : // Check whether we hit a breakpoint.
307 708 : if (isolate_->debug()->break_points_active()) {
308 : Handle<WasmCompiledModule> compiled_module(
309 708 : GetInstanceObject()->compiled_module(), isolate_);
310 354 : int position = GetTopPosition(compiled_module);
311 : Handle<FixedArray> breakpoints;
312 708 : if (compiled_module->CheckBreakPoints(position).ToHandle(&breakpoints)) {
313 : // We hit one or several breakpoints. Clear stepping, notify the
314 : // listeners and return.
315 : ClearStepping();
316 218 : isolate_->debug()->OnDebugBreak(breakpoints);
317 109 : return;
318 : }
319 : }
320 :
321 : // We did not hit a breakpoint, so maybe this pause is related to stepping.
322 : bool hit_step = false;
323 245 : switch (next_step_action_) {
324 : case StepNone:
325 : break;
326 : case StepIn:
327 : hit_step = true;
328 147 : break;
329 : case StepOut:
330 16 : hit_step = thread->GetFrameCount() < last_step_stack_depth_;
331 16 : break;
332 : case StepNext: {
333 82 : hit_step = thread->GetFrameCount() == last_step_stack_depth_;
334 82 : break;
335 : }
336 : default:
337 0 : UNREACHABLE();
338 : }
339 245 : if (!hit_step) return;
340 : ClearStepping();
341 720 : isolate_->debug()->OnDebugBreak(isolate_->factory()->empty_fixed_array());
342 : }
343 :
344 354 : int GetTopPosition(Handle<WasmCompiledModule> compiled_module) {
345 : DCHECK_EQ(1, interpreter()->GetThreadCount());
346 354 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
347 : DCHECK_LT(0, thread->GetFrameCount());
348 :
349 354 : auto frame = thread->GetFrame(thread->GetFrameCount() - 1);
350 708 : return compiled_module->GetFunctionOffset(frame->function()->func_index) +
351 708 : frame->pc();
352 : }
353 :
354 2879 : std::vector<std::pair<uint32_t, int>> GetInterpretedStack(
355 : Address frame_pointer) {
356 : DCHECK_EQ(1, interpreter()->GetThreadCount());
357 2879 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
358 :
359 : std::pair<uint32_t, uint32_t> frame_range =
360 2879 : GetActivationFrameRange(thread, frame_pointer);
361 :
362 : std::vector<std::pair<uint32_t, int>> stack;
363 2879 : stack.reserve(frame_range.second - frame_range.first);
364 1317324 : for (uint32_t fp = frame_range.first; fp < frame_range.second; ++fp) {
365 1314445 : auto frame = thread->GetFrame(fp);
366 2628890 : stack.emplace_back(frame->function()->func_index, frame->pc());
367 : }
368 2879 : return stack;
369 : }
370 :
371 921 : std::unique_ptr<wasm::InterpretedFrame> GetInterpretedFrame(
372 : Address frame_pointer, int idx) {
373 : DCHECK_EQ(1, interpreter()->GetThreadCount());
374 921 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
375 :
376 : std::pair<uint32_t, uint32_t> frame_range =
377 921 : GetActivationFrameRange(thread, frame_pointer);
378 : DCHECK_LE(0, idx);
379 : DCHECK_GT(frame_range.second - frame_range.first, idx);
380 :
381 921 : return thread->GetFrame(frame_range.first + idx);
382 : }
383 :
384 210 : void Unwind(Address frame_pointer) {
385 : // Find the current activation.
386 : DCHECK_EQ(1, activations_.count(frame_pointer));
387 : // Activations must be properly stacked:
388 : DCHECK_EQ(activations_.size() - 1, activations_[frame_pointer]);
389 210 : uint32_t activation_id = static_cast<uint32_t>(activations_.size() - 1);
390 :
391 : // Unwind the frames of the current activation if not already unwound.
392 210 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
393 420 : if (static_cast<uint32_t>(thread->GetFrameCount()) >
394 210 : thread->ActivationFrameBase(activation_id)) {
395 : using ExceptionResult = WasmInterpreter::Thread::ExceptionHandlingResult;
396 0 : ExceptionResult result = thread->HandleException(isolate_);
397 : // TODO(wasm): Handle exceptions caught in wasm land.
398 0 : CHECK_EQ(ExceptionResult::UNWOUND, result);
399 : }
400 :
401 210 : FinishActivation(frame_pointer, activation_id);
402 210 : }
403 :
404 77252 : uint64_t NumInterpretedCalls() {
405 : DCHECK_EQ(1, interpreter()->GetThreadCount());
406 77252 : return interpreter()->GetThread(0)->NumInterpretedCalls();
407 : }
408 :
409 285 : Handle<JSObject> GetGlobalScopeObject(wasm::InterpretedFrame* frame,
410 : Handle<WasmDebugInfo> debug_info) {
411 : Isolate* isolate = debug_info->GetIsolate();
412 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
413 :
414 : // TODO(clemensh): Add globals to the global scope.
415 : Handle<JSObject> global_scope_object =
416 285 : isolate_->factory()->NewJSObjectWithNullProto();
417 285 : if (instance->has_memory_buffer()) {
418 : Handle<String> name = isolate_->factory()->InternalizeOneByteString(
419 0 : STATIC_CHAR_VECTOR("memory"));
420 0 : Handle<JSArrayBuffer> memory_buffer(instance->memory_buffer(), isolate_);
421 : uint32_t byte_length;
422 0 : CHECK(memory_buffer->byte_length()->ToUint32(&byte_length));
423 : Handle<JSTypedArray> uint8_array = isolate_->factory()->NewJSTypedArray(
424 0 : kExternalUint8Array, memory_buffer, 0, byte_length);
425 : JSObject::SetOwnPropertyIgnoreAttributes(global_scope_object, name,
426 0 : uint8_array, NONE)
427 0 : .Assert();
428 : }
429 285 : return global_scope_object;
430 : }
431 :
432 285 : Handle<JSObject> GetLocalScopeObject(wasm::InterpretedFrame* frame,
433 : Handle<WasmDebugInfo> debug_info) {
434 : Isolate* isolate = debug_info->GetIsolate();
435 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
436 :
437 : Handle<JSObject> local_scope_object =
438 285 : isolate_->factory()->NewJSObjectWithNullProto();
439 : // Fill parameters and locals.
440 285 : int num_params = frame->GetParameterCount();
441 285 : int num_locals = frame->GetLocalCount();
442 : DCHECK_LE(num_params, num_locals);
443 285 : if (num_locals > 0) {
444 : Handle<JSObject> locals_obj =
445 250 : isolate_->factory()->NewJSObjectWithNullProto();
446 : Handle<String> locals_name =
447 : isolate_->factory()->InternalizeOneByteString(
448 250 : STATIC_CHAR_VECTOR("locals"));
449 : JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, locals_name,
450 250 : locals_obj, NONE)
451 250 : .Assert();
452 360 : for (int i = 0; i < num_locals; ++i) {
453 : MaybeHandle<String> name =
454 360 : GetLocalName(isolate, debug_info, frame->function()->func_index, i);
455 360 : if (name.is_null()) {
456 : // Parameters should come before locals in alphabetical ordering, so
457 : // we name them "args" here.
458 250 : const char* label = i < num_params ? "arg#%d" : "local#%d";
459 250 : name = PrintFToOneByteString<true>(isolate_, label, i);
460 : }
461 360 : WasmValue value = frame->GetLocalValue(i);
462 360 : Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
463 : JSObject::SetOwnPropertyIgnoreAttributes(
464 360 : locals_obj, name.ToHandleChecked(), value_obj, NONE)
465 360 : .Assert();
466 : }
467 : }
468 :
469 : // Fill stack values.
470 285 : int stack_count = frame->GetStackHeight();
471 : // Use an object without prototype instead of an Array, for nicer displaying
472 : // in DevTools. For Arrays, the length field and prototype is displayed,
473 : // which does not make too much sense here.
474 : Handle<JSObject> stack_obj =
475 285 : isolate_->factory()->NewJSObjectWithNullProto();
476 : Handle<String> stack_name = isolate_->factory()->InternalizeOneByteString(
477 285 : STATIC_CHAR_VECTOR("stack"));
478 : JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, stack_name,
479 285 : stack_obj, NONE)
480 285 : .Assert();
481 95 : for (int i = 0; i < stack_count; ++i) {
482 95 : WasmValue value = frame->GetStackValue(i);
483 95 : Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
484 : JSObject::SetOwnElementIgnoreAttributes(
485 95 : stack_obj, static_cast<uint32_t>(i), value_obj, NONE)
486 95 : .Assert();
487 : }
488 285 : return local_scope_object;
489 : }
490 :
491 0 : Handle<JSArray> GetScopeDetails(Address frame_pointer, int frame_index,
492 : Handle<WasmDebugInfo> debug_info) {
493 0 : auto frame = GetInterpretedFrame(frame_pointer, frame_index);
494 : Isolate* isolate = debug_info->GetIsolate();
495 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
496 :
497 : Handle<FixedArray> global_scope =
498 0 : isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
499 : global_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
500 : Smi::FromInt(ScopeIterator::ScopeTypeGlobal));
501 : Handle<JSObject> global_scope_object =
502 0 : GetGlobalScopeObject(frame.get(), debug_info);
503 : global_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
504 0 : *global_scope_object);
505 :
506 : Handle<FixedArray> local_scope =
507 0 : isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
508 : local_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
509 : Smi::FromInt(ScopeIterator::ScopeTypeLocal));
510 : Handle<JSObject> local_scope_object =
511 0 : GetLocalScopeObject(frame.get(), debug_info);
512 : local_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
513 0 : *local_scope_object);
514 :
515 : Handle<JSArray> global_jsarr =
516 0 : isolate_->factory()->NewJSArrayWithElements(global_scope);
517 : Handle<JSArray> local_jsarr =
518 0 : isolate_->factory()->NewJSArrayWithElements(local_scope);
519 0 : Handle<FixedArray> all_scopes = isolate_->factory()->NewFixedArray(2);
520 0 : all_scopes->set(0, *global_jsarr);
521 0 : all_scopes->set(1, *local_jsarr);
522 0 : return isolate_->factory()->NewJSArrayWithElements(all_scopes);
523 : }
524 : };
525 :
526 : } // namespace
527 :
528 : } // namespace wasm
529 :
530 : namespace {
531 :
532 1100 : wasm::InterpreterHandle* GetOrCreateInterpreterHandle(
533 : Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
534 : Handle<Object> handle(debug_info->get(WasmDebugInfo::kInterpreterHandleIndex),
535 : isolate);
536 1100 : if (handle->IsUndefined(isolate)) {
537 : handle = Managed<wasm::InterpreterHandle>::Allocate(isolate, isolate,
538 946 : *debug_info);
539 946 : debug_info->set(WasmDebugInfo::kInterpreterHandleIndex, *handle);
540 : }
541 :
542 1100 : return Handle<Managed<wasm::InterpreterHandle>>::cast(handle)->get();
543 : }
544 :
545 49415 : wasm::InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info) {
546 : Object* handle_obj = debug_info->get(WasmDebugInfo::kInterpreterHandleIndex);
547 : DCHECK(!handle_obj->IsUndefined(debug_info->GetIsolate()));
548 49415 : return Managed<wasm::InterpreterHandle>::cast(handle_obj)->get();
549 : }
550 :
551 77252 : wasm::InterpreterHandle* GetInterpreterHandleOrNull(WasmDebugInfo* debug_info) {
552 : Object* handle_obj = debug_info->get(WasmDebugInfo::kInterpreterHandleIndex);
553 77252 : if (handle_obj->IsUndefined(debug_info->GetIsolate())) return nullptr;
554 77252 : return Managed<wasm::InterpreterHandle>::cast(handle_obj)->get();
555 : }
556 :
557 : int GetNumFunctions(WasmInstanceObject* instance) {
558 : size_t num_functions =
559 1952 : instance->compiled_module()->module()->functions.size();
560 : DCHECK_GE(kMaxInt, num_functions);
561 1952 : return static_cast<int>(num_functions);
562 : }
563 :
564 1006 : Handle<FixedArray> GetOrCreateInterpretedFunctions(
565 : Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
566 : Handle<Object> obj(debug_info->get(WasmDebugInfo::kInterpretedFunctionsIndex),
567 : isolate);
568 1006 : if (!obj->IsUndefined(isolate)) return Handle<FixedArray>::cast(obj);
569 :
570 : Handle<FixedArray> new_arr = isolate->factory()->NewFixedArray(
571 946 : GetNumFunctions(debug_info->wasm_instance()));
572 946 : debug_info->set(WasmDebugInfo::kInterpretedFunctionsIndex, *new_arr);
573 946 : return new_arr;
574 : }
575 :
576 : using CodeRelocationMap = IdentityMap<Handle<Code>, FreeStoreAllocationPolicy>;
577 :
578 3306 : void RedirectCallsitesInCode(Code* code, CodeRelocationMap& map) {
579 : DisallowHeapAllocation no_gc;
580 13489 : for (RelocIterator it(code, RelocInfo::kCodeTargetMask); !it.done();
581 6877 : it.next()) {
582 : DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode()));
583 13754 : Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
584 : Handle<Code>* new_target = map.Find(target);
585 6877 : if (!new_target) continue;
586 : it.rinfo()->set_target_address(code->GetIsolate(),
587 2170 : (*new_target)->instruction_start());
588 : }
589 3306 : }
590 :
591 1006 : void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance,
592 : CodeRelocationMap& map) {
593 : DisallowHeapAllocation no_gc;
594 : // Redirect all calls in wasm functions.
595 : FixedArray* code_table = instance->compiled_module()->ptr_to_code_table();
596 2152 : for (int i = 0, e = GetNumFunctions(instance); i < e; ++i) {
597 2152 : RedirectCallsitesInCode(Code::cast(code_table->get(i)), map);
598 : }
599 : // TODO(6668): Find instances that imported our code and also patch those.
600 :
601 : // Redirect all calls in exported functions.
602 : FixedArray* weak_exported_functions =
603 : instance->compiled_module()->ptr_to_weak_exported_functions();
604 1154 : for (int i = 0, e = weak_exported_functions->length(); i != e; ++i) {
605 : WeakCell* weak_function = WeakCell::cast(weak_exported_functions->get(i));
606 1154 : if (weak_function->cleared()) continue;
607 : Code* code = JSFunction::cast(weak_function->value())->code();
608 1154 : RedirectCallsitesInCode(code, map);
609 : }
610 1006 : }
611 :
612 : } // namespace
613 :
614 18673 : Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<WasmInstanceObject> instance) {
615 : DCHECK(!instance->has_debug_info());
616 : Factory* factory = instance->GetIsolate()->factory();
617 18673 : Handle<FixedArray> arr = factory->NewFixedArray(kFieldCount, TENURED);
618 18673 : arr->set(kInstanceIndex, *instance);
619 : Handle<WasmDebugInfo> debug_info = Handle<WasmDebugInfo>::cast(arr);
620 18673 : instance->set_debug_info(*debug_info);
621 18673 : return debug_info;
622 : }
623 :
624 17691 : wasm::WasmInterpreter* WasmDebugInfo::SetupForTesting(
625 : Handle<WasmInstanceObject> instance_obj) {
626 17691 : Handle<WasmDebugInfo> debug_info = WasmDebugInfo::New(instance_obj);
627 : Isolate* isolate = instance_obj->GetIsolate();
628 : auto interp_handle =
629 17691 : Managed<wasm::InterpreterHandle>::Allocate(isolate, isolate, *debug_info);
630 17691 : debug_info->set(kInterpreterHandleIndex, *interp_handle);
631 17691 : return interp_handle->get()->interpreter();
632 : }
633 :
634 0 : bool WasmDebugInfo::IsWasmDebugInfo(Object* object) {
635 0 : if (!object->IsFixedArray()) return false;
636 : FixedArray* arr = FixedArray::cast(object);
637 0 : if (arr->length() != kFieldCount) return false;
638 0 : if (!arr->get(kInstanceIndex)->IsWasmInstanceObject()) return false;
639 : Isolate* isolate = arr->GetIsolate();
640 0 : if (!arr->get(kInterpreterHandleIndex)->IsUndefined(isolate) &&
641 : !arr->get(kInterpreterHandleIndex)->IsForeign())
642 : return false;
643 0 : return true;
644 : }
645 :
646 49855 : WasmDebugInfo* WasmDebugInfo::cast(Object* object) {
647 : DCHECK(IsWasmDebugInfo(object));
648 49855 : return reinterpret_cast<WasmDebugInfo*>(object);
649 : }
650 :
651 0 : WasmInstanceObject* WasmDebugInfo::wasm_instance() {
652 0 : return WasmInstanceObject::cast(get(kInstanceIndex));
653 : }
654 :
655 94 : void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
656 : int func_index, int offset) {
657 : Isolate* isolate = debug_info->GetIsolate();
658 188 : auto* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
659 94 : RedirectToInterpreter(debug_info, Vector<int>(&func_index, 1));
660 188 : const wasm::WasmFunction* func = &handle->module()->functions[func_index];
661 94 : handle->interpreter()->SetBreakpoint(func, offset, true);
662 94 : }
663 :
664 1006 : void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
665 : Vector<int> func_indexes) {
666 : Isolate* isolate = debug_info->GetIsolate();
667 : // Ensure that the interpreter is instantiated.
668 1006 : GetOrCreateInterpreterHandle(isolate, debug_info);
669 : Handle<FixedArray> interpreted_functions =
670 1006 : GetOrCreateInterpretedFunctions(isolate, debug_info);
671 : Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
672 1006 : Handle<FixedArray> code_table = instance->compiled_module()->code_table();
673 1006 : CodeRelocationMap code_to_relocate(isolate->heap());
674 2176 : for (int func_index : func_indexes) {
675 : DCHECK_LE(0, func_index);
676 : DCHECK_GT(debug_info->wasm_instance()->module()->functions.size(),
677 : func_index);
678 1215 : if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) continue;
679 :
680 : Handle<Code> new_code = compiler::CompileWasmInterpreterEntry(
681 : isolate, func_index,
682 2250 : instance->compiled_module()->module()->functions[func_index].sig,
683 1125 : instance);
684 :
685 : Code* old_code = Code::cast(code_table->get(func_index));
686 1125 : interpreted_functions->set(func_index, *new_code);
687 : DCHECK_NULL(code_to_relocate.Find(old_code));
688 : code_to_relocate.Set(old_code, new_code);
689 : }
690 1006 : RedirectCallsitesInInstance(isolate, *instance, code_to_relocate);
691 1006 : }
692 :
693 261 : void WasmDebugInfo::PrepareStep(StepAction step_action) {
694 261 : GetInterpreterHandle(this)->PrepareStep(step_action);
695 261 : }
696 :
697 45144 : bool WasmDebugInfo::RunInterpreter(Address frame_pointer, int func_index,
698 : uint8_t* arg_buffer) {
699 : DCHECK_LE(0, func_index);
700 : Handle<WasmInstanceObject> instance(wasm_instance());
701 : return GetInterpreterHandle(this)->Execute(
702 45144 : instance, frame_pointer, static_cast<uint32_t>(func_index), arg_buffer);
703 : }
704 :
705 2879 : std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack(
706 : Address frame_pointer) {
707 2879 : return GetInterpreterHandle(this)->GetInterpretedStack(frame_pointer);
708 : }
709 :
710 351 : std::unique_ptr<wasm::InterpretedFrame> WasmDebugInfo::GetInterpretedFrame(
711 : Address frame_pointer, int idx) {
712 351 : return GetInterpreterHandle(this)->GetInterpretedFrame(frame_pointer, idx);
713 : }
714 :
715 210 : void WasmDebugInfo::Unwind(Address frame_pointer) {
716 210 : return GetInterpreterHandle(this)->Unwind(frame_pointer);
717 : }
718 :
719 77252 : uint64_t WasmDebugInfo::NumInterpretedCalls() {
720 77252 : auto* handle = GetInterpreterHandleOrNull(this);
721 77252 : return handle ? handle->NumInterpretedCalls() : 0;
722 : }
723 :
724 : // static
725 0 : Handle<JSObject> WasmDebugInfo::GetScopeDetails(
726 : Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
727 0 : auto* interp_handle = GetInterpreterHandle(*debug_info);
728 0 : return interp_handle->GetScopeDetails(frame_pointer, frame_index, debug_info);
729 : }
730 :
731 : // static
732 285 : Handle<JSObject> WasmDebugInfo::GetGlobalScopeObject(
733 : Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
734 285 : auto* interp_handle = GetInterpreterHandle(*debug_info);
735 285 : auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
736 570 : return interp_handle->GetGlobalScopeObject(frame.get(), debug_info);
737 : }
738 :
739 : // static
740 285 : Handle<JSObject> WasmDebugInfo::GetLocalScopeObject(
741 : Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
742 285 : auto* interp_handle = GetInterpreterHandle(*debug_info);
743 285 : auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
744 570 : return interp_handle->GetLocalScopeObject(frame.get(), debug_info);
745 : }
746 :
747 : // static
748 96 : Handle<JSFunction> WasmDebugInfo::GetCWasmEntry(
749 : Handle<WasmDebugInfo> debug_info, wasm::FunctionSig* sig) {
750 : Isolate* isolate = debug_info->GetIsolate();
751 : DCHECK_EQ(debug_info->has_c_wasm_entries(),
752 : debug_info->has_c_wasm_entry_map());
753 96 : if (!debug_info->has_c_wasm_entries()) {
754 96 : auto entries = isolate->factory()->NewFixedArray(4, TENURED);
755 96 : debug_info->set_c_wasm_entries(*entries);
756 96 : auto managed_map = Managed<wasm::SignatureMap>::Allocate(isolate);
757 96 : debug_info->set_c_wasm_entry_map(*managed_map);
758 : }
759 : Handle<FixedArray> entries(debug_info->c_wasm_entries(), isolate);
760 : wasm::SignatureMap* map = debug_info->c_wasm_entry_map()->get();
761 96 : int32_t index = map->Find(sig);
762 96 : if (index == -1) {
763 96 : index = static_cast<int32_t>(map->FindOrInsert(sig));
764 96 : if (index == entries->length()) {
765 : entries = isolate->factory()->CopyFixedArrayAndGrow(
766 0 : entries, entries->length(), TENURED);
767 0 : debug_info->set_c_wasm_entries(*entries);
768 : }
769 : DCHECK(entries->get(index)->IsUndefined(isolate));
770 : Address context_address = reinterpret_cast<Address>(
771 : debug_info->wasm_instance()->has_memory_object()
772 : ? debug_info->wasm_instance()->wasm_context()
773 96 : : nullptr);
774 : Handle<Code> new_entry_code =
775 96 : compiler::CompileCWasmEntry(isolate, sig, context_address);
776 : Handle<String> name = isolate->factory()->InternalizeOneByteString(
777 96 : STATIC_CHAR_VECTOR("c-wasm-entry"));
778 : Handle<SharedFunctionInfo> shared =
779 96 : isolate->factory()->NewSharedFunctionInfo(name, new_entry_code, false);
780 : shared->set_internal_formal_parameter_count(
781 : compiler::CWasmEntryParameters::kNumParameters);
782 : Handle<JSFunction> new_entry = isolate->factory()->NewFunction(
783 96 : isolate->sloppy_function_map(), name, new_entry_code);
784 : new_entry->set_context(
785 192 : *debug_info->wasm_instance()->compiled_module()->native_context());
786 96 : new_entry->set_shared(*shared);
787 96 : entries->set(index, *new_entry);
788 : }
789 96 : return handle(JSFunction::cast(entries->get(index)));
790 : }
791 :
792 : } // namespace internal
793 : } // namespace v8
|