LCOV - code coverage report
Current view: top level - src/wasm - wasm-debug.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 254 271 93.7 %
Date: 2019-03-21 Functions: 35 36 97.2 %

          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         644 :       if (Smi::IsValid(value.to<int32_t>()))
      50         644 :         return handle(Smi::FromInt(value.to<int32_t>()), isolate);
      51           0 :       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          92 :       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       34373 :   uint32_t StartActivation(Address frame_pointer) {
     106       34373 :     WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
     107       34373 :     uint32_t activation_id = thread->StartActivation();
     108             :     DCHECK_EQ(0, activations_.count(frame_pointer));
     109       68746 :     activations_.insert(std::make_pair(frame_pointer, activation_id));
     110       34373 :     return activation_id;
     111             :   }
     112             : 
     113       34373 :   void FinishActivation(Address frame_pointer, uint32_t activation_id) {
     114       34373 :     WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
     115       34373 :     thread->FinishActivation(activation_id);
     116             :     DCHECK_EQ(1, activations_.count(frame_pointer));
     117             :     activations_.erase(frame_pointer);
     118       34373 :   }
     119             : 
     120        5668 :   std::pair<uint32_t, uint32_t> GetActivationFrameRange(
     121             :       WasmInterpreter::Thread* thread, Address frame_pointer) {
     122             :     DCHECK_EQ(1, activations_.count(frame_pointer));
     123        5668 :     uint32_t activation_id = activations_.find(frame_pointer)->second;
     124        5668 :     uint32_t num_activations = static_cast<uint32_t>(activations_.size() - 1);
     125        5668 :     uint32_t frame_base = thread->ActivationFrameBase(activation_id);
     126             :     uint32_t frame_limit = activation_id == num_activations
     127        5564 :                                ? thread->GetFrameCount()
     128       11232 :                                : thread->ActivationFrameBase(activation_id + 1);
     129             :     DCHECK_LE(frame_base, frame_limit);
     130             :     DCHECK_LE(frame_limit, thread->GetFrameCount());
     131        5668 :     return {frame_base, frame_limit};
     132             :   }
     133             : 
     134      365686 :   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      365686 :         debug_info->wasm_instance()->module_object()->native_module();
     139      365686 :     return ModuleWireBytes{native_module->wire_bytes()};
     140             :   }
     141             : 
     142             :  public:
     143      365686 :   InterpreterHandle(Isolate* isolate, Handle<WasmDebugInfo> debug_info)
     144             :       : isolate_(isolate),
     145      731372 :         module_(debug_info->wasm_instance()->module_object()->module()),
     146      731372 :         interpreter_(isolate, module_, GetBytes(*debug_info),
     147     1828430 :                      handle(debug_info->wasm_instance(), isolate)) {}
     148             : 
     149      365686 :   ~InterpreterHandle() { DCHECK_EQ(0, activations_.size()); }
     150             : 
     151      423074 :   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         548 :   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       34373 :   bool Execute(Handle<WasmInstanceObject> instance_object,
     170             :                Address frame_pointer, uint32_t func_index, Address arg_buffer) {
     171             :     DCHECK_GE(module()->functions.size(), func_index);
     172       68746 :     FunctionSig* sig = module()->functions[func_index].sig;
     173             :     DCHECK_GE(kMaxInt, sig->parameter_count());
     174       34373 :     int num_params = static_cast<int>(sig->parameter_count());
     175             :     ScopedVector<WasmValue> wasm_args(num_params);
     176             :     Address arg_buf_ptr = arg_buffer;
     177      144159 :     for (int i = 0; i < num_params; ++i) {
     178             :       uint32_t param_size = static_cast<uint32_t>(
     179      109786 :           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       54893 :       switch (sig->GetParam(i)) {
     186        9857 :         CASE_ARG_TYPE(kWasmI32, uint32_t)
     187       15024 :         CASE_ARG_TYPE(kWasmI64, uint64_t)
     188        1396 :         CASE_ARG_TYPE(kWasmF32, float)
     189       28616 :         CASE_ARG_TYPE(kWasmF64, double)
     190             : #undef CASE_ARG_TYPE
     191             :         default:
     192           0 :           UNREACHABLE();
     193             :       }
     194       54893 :       arg_buf_ptr += param_size;
     195             :     }
     196             : 
     197       34373 :     uint32_t activation_id = StartActivation(frame_pointer);
     198             : 
     199       34373 :     WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
     200       34373 :     thread->InitFrame(&module()->functions[func_index], wasm_args.start());
     201             :     bool finished = false;
     202       67557 :     while (!finished) {
     203             :       // TODO(clemensh): Add occasional StackChecks.
     204       34945 :       WasmInterpreter::State state = ContinueExecution(thread);
     205       34945 :       switch (state) {
     206             :         case WasmInterpreter::State::PAUSED:
     207         556 :           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         780 :               WasmOpcodes::TrapReasonToMessageId(thread->GetTrapReason());
     216             :           Handle<Object> exception =
     217         780 :               isolate_->factory()->NewWasmRuntimeError(message_id);
     218         780 :           auto result = thread->RaiseException(isolate_, exception);
     219         780 :           if (result == WasmInterpreter::Thread::HANDLED) break;
     220             :           // If no local handler was found, we fall-thru to {STOPPED}.
     221             :           DCHECK_EQ(WasmInterpreter::State::STOPPED, thread->state());
     222             :           V8_FALLTHROUGH;
     223             :         }
     224             :         case WasmInterpreter::State::STOPPED:
     225             :           // An exception happened, and the current activation was unwound
     226             :           // without hitting a local exception handler. All that remains to be
     227             :           // done is finish the activation and let the exception propagate.
     228             :           DCHECK_EQ(thread->ActivationFrameBase(activation_id),
     229             :                     thread->GetFrameCount());
     230             :           DCHECK(isolate_->has_pending_exception());
     231        1761 :           FinishActivation(frame_pointer, activation_id);
     232             :           return false;
     233             :         // RUNNING should never occur here.
     234             :         case WasmInterpreter::State::RUNNING:
     235             :         default:
     236           0 :           UNREACHABLE();
     237             :       }
     238             :     }
     239             : 
     240             :     // Copy back the return value
     241             :     DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count());
     242             :     // TODO(wasm): Handle multi-value returns.
     243             :     DCHECK_EQ(1, kV8MaxWasmFunctionReturns);
     244       32612 :     if (sig->return_count()) {
     245       32396 :       WasmValue ret_val = thread->GetReturnValue(0);
     246             : #define CASE_RET_TYPE(type, ctype)                               \
     247             :   case type:                                                     \
     248             :     DCHECK_EQ(ValueTypes::ElementSizeInBytes(sig->GetReturn(0)), \
     249             :               sizeof(ctype));                                    \
     250             :     WriteUnalignedValue<ctype>(arg_buffer, ret_val.to<ctype>()); \
     251             :     break;
     252       32396 :       switch (sig->GetReturn(0)) {
     253             :         CASE_RET_TYPE(kWasmI32, uint32_t)
     254             :         CASE_RET_TYPE(kWasmI64, uint64_t)
     255             :         CASE_RET_TYPE(kWasmF32, float)
     256             :         CASE_RET_TYPE(kWasmF64, double)
     257             : #undef CASE_RET_TYPE
     258             :         default:
     259           0 :           UNREACHABLE();
     260             :       }
     261             :     }
     262             : 
     263       32612 :     FinishActivation(frame_pointer, activation_id);
     264             : 
     265             :     return true;
     266             :   }
     267             : 
     268       34945 :   WasmInterpreter::State ContinueExecution(WasmInterpreter::Thread* thread) {
     269       34945 :     switch (next_step_action_) {
     270             :       case StepNone:
     271       34573 :         return thread->Run();
     272             :       case StepIn:
     273             :         return thread->Step();
     274             :       case StepOut:
     275          32 :         thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterReturn);
     276          32 :         return thread->Run();
     277             :       case StepNext: {
     278         108 :         int stack_depth = thread->GetFrameCount();
     279         108 :         if (stack_depth == last_step_stack_depth_) return thread->Step();
     280           8 :         thread->AddBreakFlags(stack_depth > last_step_stack_depth_
     281             :                                   ? WasmInterpreter::BreakFlag::AfterReturn
     282           8 :                                   : WasmInterpreter::BreakFlag::AfterCall);
     283           8 :         return thread->Run();
     284             :       }
     285             :       default:
     286           0 :         UNREACHABLE();
     287             :     }
     288             :   }
     289             : 
     290         556 :   Handle<WasmInstanceObject> GetInstanceObject() {
     291         556 :     StackTraceFrameIterator it(isolate_);
     292             :     WasmInterpreterEntryFrame* frame =
     293             :         WasmInterpreterEntryFrame::cast(it.frame());
     294         556 :     Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_);
     295             :     // Check that this is indeed the instance which is connected to this
     296             :     // interpreter.
     297             :     DCHECK_EQ(this, Managed<InterpreterHandle>::cast(
     298             :                         instance_obj->debug_info()->interpreter_handle())
     299             :                         ->raw());
     300        1112 :     return instance_obj;
     301             :   }
     302             : 
     303         556 :   void NotifyDebugEventListeners(WasmInterpreter::Thread* thread) {
     304             :     // Enter the debugger.
     305         892 :     DebugScope debug_scope(isolate_->debug());
     306             : 
     307             :     // Check whether we hit a breakpoint.
     308         556 :     if (isolate_->debug()->break_points_active()) {
     309             :       Handle<WasmModuleObject> module_object(
     310        1112 :           GetInstanceObject()->module_object(), isolate_);
     311         556 :       int position = GetTopPosition(module_object);
     312             :       Handle<FixedArray> breakpoints;
     313        1112 :       if (WasmModuleObject::CheckBreakPoints(isolate_, module_object, position)
     314             :               .ToHandle(&breakpoints)) {
     315             :         // We hit one or several breakpoints. Clear stepping, notify the
     316             :         // listeners and return.
     317             :         ClearStepping();
     318         212 :         isolate_->debug()->OnDebugBreak(breakpoints);
     319         212 :         return;
     320             :       }
     321             :     }
     322             : 
     323             :     // We did not hit a breakpoint, so maybe this pause is related to stepping.
     324             :     bool hit_step = false;
     325         344 :     switch (next_step_action_) {
     326             :       case StepNone:
     327             :         break;
     328             :       case StepIn:
     329             :         hit_step = true;
     330         216 :         break;
     331             :       case StepOut:
     332          24 :         hit_step = thread->GetFrameCount() < last_step_stack_depth_;
     333          24 :         break;
     334             :       case StepNext: {
     335         104 :         hit_step = thread->GetFrameCount() == last_step_stack_depth_;
     336         104 :         break;
     337             :       }
     338             :       default:
     339           0 :         UNREACHABLE();
     340             :     }
     341         344 :     if (!hit_step) return;
     342             :     ClearStepping();
     343         672 :     isolate_->debug()->OnDebugBreak(isolate_->factory()->empty_fixed_array());
     344             :   }
     345             : 
     346         556 :   int GetTopPosition(Handle<WasmModuleObject> module_object) {
     347             :     DCHECK_EQ(1, interpreter()->GetThreadCount());
     348         556 :     WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
     349             :     DCHECK_LT(0, thread->GetFrameCount());
     350             : 
     351         556 :     auto frame = thread->GetFrame(thread->GetFrameCount() - 1);
     352        1668 :     return module_object->GetFunctionOffset(frame->function()->func_index) +
     353        1112 :            frame->pc();
     354             :   }
     355             : 
     356        3916 :   std::vector<std::pair<uint32_t, int>> GetInterpretedStack(
     357             :       Address frame_pointer) {
     358             :     DCHECK_EQ(1, interpreter()->GetThreadCount());
     359        3916 :     WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
     360             : 
     361             :     std::pair<uint32_t, uint32_t> frame_range =
     362        3916 :         GetActivationFrameRange(thread, frame_pointer);
     363             : 
     364             :     std::vector<std::pair<uint32_t, int>> stack;
     365        3916 :     stack.reserve(frame_range.second - frame_range.first);
     366     1356884 :     for (uint32_t fp = frame_range.first; fp < frame_range.second; ++fp) {
     367      676484 :       auto frame = thread->GetFrame(fp);
     368     1352968 :       stack.emplace_back(frame->function()->func_index, frame->pc());
     369             :     }
     370        3916 :     return stack;
     371             :   }
     372             : 
     373        1752 :   WasmInterpreter::FramePtr GetInterpretedFrame(Address frame_pointer,
     374             :                                                 int idx) {
     375             :     DCHECK_EQ(1, interpreter()->GetThreadCount());
     376        1752 :     WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
     377             : 
     378             :     std::pair<uint32_t, uint32_t> frame_range =
     379        1752 :         GetActivationFrameRange(thread, frame_pointer);
     380             :     DCHECK_LE(0, idx);
     381             :     DCHECK_GT(frame_range.second - frame_range.first, idx);
     382             : 
     383        1752 :     return thread->GetFrame(frame_range.first + idx);
     384             :   }
     385             : 
     386             :   uint64_t NumInterpretedCalls() {
     387             :     DCHECK_EQ(1, interpreter()->GetThreadCount());
     388       51568 :     return interpreter()->GetThread(0)->NumInterpretedCalls();
     389             :   }
     390             : 
     391         460 :   Handle<JSObject> GetGlobalScopeObject(InterpretedFrame* frame,
     392             :                                         Handle<WasmDebugInfo> debug_info) {
     393         460 :     Isolate* isolate = isolate_;
     394             :     Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
     395             : 
     396             :     // TODO(clemensh): Add globals to the global scope.
     397             :     Handle<JSObject> global_scope_object =
     398         460 :         isolate_->factory()->NewJSObjectWithNullProto();
     399         460 :     if (instance->has_memory_object()) {
     400           0 :       Handle<String> name = isolate_->factory()->InternalizeOneByteString(
     401           0 :           StaticCharVector("memory"));
     402             :       Handle<JSArrayBuffer> memory_buffer(
     403           0 :           instance->memory_object()->array_buffer(), isolate_);
     404           0 :       Handle<JSTypedArray> uint8_array = isolate_->factory()->NewJSTypedArray(
     405           0 :           kExternalUint8Array, memory_buffer, 0, memory_buffer->byte_length());
     406           0 :       JSObject::SetOwnPropertyIgnoreAttributes(global_scope_object, name,
     407           0 :                                                uint8_array, NONE)
     408             :           .Assert();
     409             :     }
     410         460 :     return global_scope_object;
     411             :   }
     412             : 
     413         460 :   Handle<JSObject> GetLocalScopeObject(InterpretedFrame* frame,
     414             :                                        Handle<WasmDebugInfo> debug_info) {
     415         460 :     Isolate* isolate = isolate_;
     416             : 
     417             :     Handle<JSObject> local_scope_object =
     418         460 :         isolate_->factory()->NewJSObjectWithNullProto();
     419             :     // Fill parameters and locals.
     420         460 :     int num_params = frame->GetParameterCount();
     421         460 :     int num_locals = frame->GetLocalCount();
     422             :     DCHECK_LE(num_params, num_locals);
     423         460 :     if (num_locals > 0) {
     424             :       Handle<JSObject> locals_obj =
     425         412 :           isolate_->factory()->NewJSObjectWithNullProto();
     426             :       Handle<String> locals_name =
     427         412 :           isolate_->factory()->InternalizeOneByteString(
     428         412 :               StaticCharVector("locals"));
     429         412 :       JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, locals_name,
     430         412 :                                                locals_obj, NONE)
     431             :           .Assert();
     432        1596 :       for (int i = 0; i < num_locals; ++i) {
     433             :         MaybeHandle<String> name =
     434         592 :             GetLocalName(isolate, debug_info, frame->function()->func_index, i);
     435         592 :         if (name.is_null()) {
     436             :           // Parameters should come before locals in alphabetical ordering, so
     437             :           // we name them "args" here.
     438         412 :           const char* label = i < num_params ? "arg#%d" : "local#%d";
     439         412 :           name = PrintFToOneByteString<true>(isolate_, label, i);
     440             :         }
     441         592 :         WasmValue value = frame->GetLocalValue(i);
     442         592 :         Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
     443         592 :         JSObject::SetOwnPropertyIgnoreAttributes(
     444         592 :             locals_obj, name.ToHandleChecked(), value_obj, NONE)
     445             :             .Assert();
     446             :       }
     447             :     }
     448             : 
     449             :     // Fill stack values.
     450         460 :     int stack_count = frame->GetStackHeight();
     451             :     // Use an object without prototype instead of an Array, for nicer displaying
     452             :     // in DevTools. For Arrays, the length field and prototype is displayed,
     453             :     // which does not make too much sense here.
     454             :     Handle<JSObject> stack_obj =
     455         460 :         isolate_->factory()->NewJSObjectWithNullProto();
     456         460 :     Handle<String> stack_name = isolate_->factory()->InternalizeOneByteString(
     457         460 :         StaticCharVector("stack"));
     458         460 :     JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, stack_name,
     459         460 :                                              stack_obj, NONE)
     460             :         .Assert();
     461         860 :     for (int i = 0; i < stack_count; ++i) {
     462         200 :       WasmValue value = frame->GetStackValue(i);
     463         200 :       Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
     464         200 :       JSObject::SetOwnElementIgnoreAttributes(
     465         200 :           stack_obj, static_cast<uint32_t>(i), value_obj, NONE)
     466             :           .Assert();
     467             :     }
     468         460 :     return local_scope_object;
     469             :   }
     470             : };
     471             : 
     472             : }  // namespace
     473             : 
     474             : }  // namespace wasm
     475             : 
     476             : namespace {
     477             : 
     478       34789 : wasm::InterpreterHandle* GetOrCreateInterpreterHandle(
     479             :     Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
     480             :   Handle<Object> handle(debug_info->interpreter_handle(), isolate);
     481       34789 :   if (handle->IsUndefined(isolate)) {
     482             :     // Use the maximum stack size to estimate the maximum size of the
     483             :     // interpreter. The interpreter keeps its own stack internally, and the size
     484             :     // of the stack should dominate the overall size of the interpreter. We
     485             :     // multiply by '2' to account for the growing strategy for the backing store
     486             :     // of the stack.
     487         912 :     size_t interpreter_size = FLAG_stack_size * KB * 2;
     488             :     handle = Managed<wasm::InterpreterHandle>::Allocate(
     489         912 :         isolate, interpreter_size, isolate, debug_info);
     490         912 :     debug_info->set_interpreter_handle(*handle);
     491             :   }
     492             : 
     493       34789 :   return Handle<Managed<wasm::InterpreterHandle>>::cast(handle)->raw();
     494             : }
     495             : 
     496             : wasm::InterpreterHandle* GetInterpreterHandle(WasmDebugInfo debug_info) {
     497             :   Object handle_obj = debug_info->interpreter_handle();
     498             :   DCHECK(!handle_obj->IsUndefined());
     499             :   return Managed<wasm::InterpreterHandle>::cast(handle_obj)->raw();
     500             : }
     501             : 
     502       51568 : wasm::InterpreterHandle* GetInterpreterHandleOrNull(WasmDebugInfo debug_info) {
     503             :   Object handle_obj = debug_info->interpreter_handle();
     504       51568 :   if (handle_obj->IsUndefined()) return nullptr;
     505             :   return Managed<wasm::InterpreterHandle>::cast(handle_obj)->raw();
     506             : }
     507             : 
     508         272 : Handle<FixedArray> GetOrCreateInterpretedFunctions(
     509             :     Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
     510             :   Handle<FixedArray> arr(debug_info->interpreted_functions(), isolate);
     511             :   int num_functions = debug_info->wasm_instance()
     512         544 :                           ->module_object()
     513             :                           ->native_module()
     514         544 :                           ->num_functions();
     515         272 :   if (arr->length() == 0 && num_functions > 0) {
     516         172 :     arr = isolate->factory()->NewFixedArray(num_functions);
     517         172 :     debug_info->set_interpreted_functions(*arr);
     518             :   }
     519             :   DCHECK_EQ(num_functions, arr->length());
     520         272 :   return arr;
     521             : }
     522             : 
     523             : }  // namespace
     524             : 
     525      365710 : Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<WasmInstanceObject> instance) {
     526             :   DCHECK(!instance->has_debug_info());
     527             :   Factory* factory = instance->GetIsolate()->factory();
     528             :   Handle<WasmDebugInfo> debug_info = Handle<WasmDebugInfo>::cast(
     529      365710 :       factory->NewStruct(WASM_DEBUG_INFO_TYPE, AllocationType::kOld));
     530      365710 :   debug_info->set_wasm_instance(*instance);
     531      365710 :   debug_info->set_interpreted_functions(*factory->empty_fixed_array());
     532      365710 :   instance->set_debug_info(*debug_info);
     533      365710 :   return debug_info;
     534             : }
     535             : 
     536      364774 : wasm::WasmInterpreter* WasmDebugInfo::SetupForTesting(
     537             :     Handle<WasmInstanceObject> instance_obj) {
     538      364774 :   Handle<WasmDebugInfo> debug_info = WasmDebugInfo::New(instance_obj);
     539             :   Isolate* isolate = instance_obj->GetIsolate();
     540             :   // Use the maximum stack size to estimate the maximum size of the interpreter.
     541             :   // The interpreter keeps its own stack internally, and the size of the stack
     542             :   // should dominate the overall size of the interpreter. We multiply by '2' to
     543             :   // account for the growing strategy for the backing store of the stack.
     544      364774 :   size_t interpreter_size = FLAG_stack_size * KB * 2;
     545             :   auto interp_handle = Managed<wasm::InterpreterHandle>::Allocate(
     546      364774 :       isolate, interpreter_size, isolate, debug_info);
     547      729548 :   debug_info->set_interpreter_handle(*interp_handle);
     548      364774 :   return interp_handle->raw()->interpreter();
     549             : }
     550             : 
     551         144 : void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
     552             :                                   int func_index, int offset) {
     553             :   Isolate* isolate = debug_info->GetIsolate();
     554         144 :   auto* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
     555         144 :   RedirectToInterpreter(debug_info, Vector<int>(&func_index, 1));
     556         144 :   const wasm::WasmFunction* func = &handle->module()->functions[func_index];
     557         288 :   handle->interpreter()->SetBreakpoint(func, offset, true);
     558         144 : }
     559             : 
     560         272 : void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
     561             :                                           Vector<int> func_indexes) {
     562             :   Isolate* isolate = debug_info->GetIsolate();
     563             :   // Ensure that the interpreter is instantiated.
     564         272 :   GetOrCreateInterpreterHandle(isolate, debug_info);
     565             :   Handle<FixedArray> interpreted_functions =
     566         272 :       GetOrCreateInterpretedFunctions(isolate, debug_info);
     567             :   Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
     568             :   wasm::NativeModule* native_module =
     569         272 :       instance->module_object()->native_module();
     570         272 :   const wasm::WasmModule* module = instance->module();
     571             : 
     572             :   // We may modify the wasm jump table.
     573             :   wasm::NativeModuleModificationScope native_module_modification_scope(
     574         544 :       native_module);
     575             : 
     576         816 :   for (int func_index : func_indexes) {
     577             :     DCHECK_LE(0, func_index);
     578             :     DCHECK_GT(module->functions.size(), func_index);
     579         360 :     if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) continue;
     580             : 
     581             :     wasm::WasmCompilationResult result = compiler::CompileWasmInterpreterEntry(
     582             :         isolate->wasm_engine(), native_module->enabled_features(), func_index,
     583         736 :         module->functions[func_index].sig);
     584             :     std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode(
     585             :         func_index, result.code_desc, result.frame_slot_count,
     586             :         result.tagged_parameter_slots, std::move(result.protected_instructions),
     587             :         std::move(result.source_positions), wasm::WasmCode::kInterpreterEntry,
     588         736 :         wasm::WasmCode::kOther);
     589             :     Address instruction_start = wasm_code->instruction_start();
     590         184 :     native_module->PublishCode(std::move(wasm_code));
     591             : 
     592             :     Handle<Foreign> foreign_holder =
     593         184 :         isolate->factory()->NewForeign(instruction_start, AllocationType::kOld);
     594         368 :     interpreted_functions->set(func_index, *foreign_holder);
     595             :   }
     596         272 : }
     597             : 
     598         364 : void WasmDebugInfo::PrepareStep(StepAction step_action) {
     599         728 :   GetInterpreterHandle(*this)->PrepareStep(step_action);
     600         364 : }
     601             : 
     602             : // static
     603       34373 : bool WasmDebugInfo::RunInterpreter(Isolate* isolate,
     604             :                                    Handle<WasmDebugInfo> debug_info,
     605             :                                    Address frame_pointer, int func_index,
     606             :                                    Address arg_buffer) {
     607             :   DCHECK_LE(0, func_index);
     608       34373 :   auto* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
     609             :   Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
     610       34373 :   return handle->Execute(instance, frame_pointer,
     611       34373 :                          static_cast<uint32_t>(func_index), arg_buffer);
     612             : }
     613             : 
     614        3916 : std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack(
     615             :     Address frame_pointer) {
     616        3916 :   return GetInterpreterHandle(*this)->GetInterpretedStack(frame_pointer);
     617             : }
     618             : 
     619         832 : wasm::WasmInterpreter::FramePtr WasmDebugInfo::GetInterpretedFrame(
     620             :     Address frame_pointer, int idx) {
     621         832 :   return GetInterpreterHandle(*this)->GetInterpretedFrame(frame_pointer, idx);
     622             : }
     623             : 
     624       51568 : uint64_t WasmDebugInfo::NumInterpretedCalls() {
     625       51568 :   auto* handle = GetInterpreterHandleOrNull(*this);
     626      103136 :   return handle ? handle->NumInterpretedCalls() : 0;
     627             : }
     628             : 
     629             : // static
     630         460 : Handle<JSObject> WasmDebugInfo::GetGlobalScopeObject(
     631             :     Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
     632             :   auto* interp_handle = GetInterpreterHandle(*debug_info);
     633         460 :   auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
     634         920 :   return interp_handle->GetGlobalScopeObject(frame.get(), debug_info);
     635             : }
     636             : 
     637             : // static
     638         460 : Handle<JSObject> WasmDebugInfo::GetLocalScopeObject(
     639             :     Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
     640             :   auto* interp_handle = GetInterpreterHandle(*debug_info);
     641         460 :   auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
     642         920 :   return interp_handle->GetLocalScopeObject(frame.get(), debug_info);
     643             : }
     644             : 
     645             : // static
     646        6685 : Handle<JSFunction> WasmDebugInfo::GetCWasmEntry(
     647             :     Handle<WasmDebugInfo> debug_info, wasm::FunctionSig* sig) {
     648             :   Isolate* isolate = debug_info->GetIsolate();
     649             :   DCHECK_EQ(debug_info->has_c_wasm_entries(),
     650             :             debug_info->has_c_wasm_entry_map());
     651        6685 :   if (!debug_info->has_c_wasm_entries()) {
     652        1360 :     auto entries = isolate->factory()->NewFixedArray(4, AllocationType::kOld);
     653        1360 :     debug_info->set_c_wasm_entries(*entries);
     654             :     size_t map_size = 0;  // size estimate not so important here.
     655        1360 :     auto managed_map = Managed<wasm::SignatureMap>::Allocate(isolate, map_size);
     656        1360 :     debug_info->set_c_wasm_entry_map(*managed_map);
     657             :   }
     658             :   Handle<FixedArray> entries(debug_info->c_wasm_entries(), isolate);
     659             :   wasm::SignatureMap* map = debug_info->c_wasm_entry_map()->raw();
     660        6685 :   int32_t index = map->Find(*sig);
     661        6685 :   if (index == -1) {
     662        1376 :     index = static_cast<int32_t>(map->FindOrInsert(*sig));
     663        1376 :     if (index == entries->length()) {
     664             :       entries = isolate->factory()->CopyFixedArrayAndGrow(
     665           0 :           entries, entries->length(), AllocationType::kOld);
     666           0 :       debug_info->set_c_wasm_entries(*entries);
     667             :     }
     668             :     DCHECK(entries->get(index)->IsUndefined(isolate));
     669             :     Handle<Code> new_entry_code =
     670        2752 :         compiler::CompileCWasmEntry(isolate, sig).ToHandleChecked();
     671             :     Handle<WasmExportedFunctionData> function_data =
     672             :         Handle<WasmExportedFunctionData>::cast(isolate->factory()->NewStruct(
     673        1376 :             WASM_EXPORTED_FUNCTION_DATA_TYPE, AllocationType::kOld));
     674        1376 :     function_data->set_wrapper_code(*new_entry_code);
     675        1376 :     function_data->set_instance(debug_info->wasm_instance());
     676             :     function_data->set_jump_table_offset(-1);
     677             :     function_data->set_function_index(-1);
     678             :     Handle<String> name = isolate->factory()->InternalizeOneByteString(
     679        1376 :         StaticCharVector("c-wasm-entry"));
     680             :     NewFunctionArgs args = NewFunctionArgs::ForWasm(
     681        1376 :         name, function_data, isolate->sloppy_function_map());
     682        1376 :     Handle<JSFunction> new_entry = isolate->factory()->NewFunction(args);
     683        2752 :     new_entry->set_context(debug_info->wasm_instance()->native_context());
     684             :     new_entry->shared()->set_internal_formal_parameter_count(
     685             :         compiler::CWasmEntryParameters::kNumParameters);
     686        2752 :     entries->set(index, *new_entry);
     687             :   }
     688        6685 :   return handle(JSFunction::cast(entries->get(index)), isolate);
     689             : }
     690             : 
     691             : }  // namespace internal
     692      120216 : }  // namespace v8

Generated by: LCOV version 1.10