LCOV - code coverage report
Current view: top level - src/wasm - wasm-debug.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 281 314 89.5 %
Date: 2019-01-20 Functions: 41 43 95.3 %

          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

Generated by: LCOV version 1.10