LCOV - code coverage report
Current view: top level - src/wasm - wasm-debug.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 247 261 94.6 %
Date: 2019-04-17 Functions: 35 35 100.0 %

          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

Generated by: LCOV version 1.10