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