LCOV - code coverage report
Current view: top level - src/wasm - wasm-debug.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 268 313 85.6 %
Date: 2017-10-20 Functions: 41 46 89.1 %

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

Generated by: LCOV version 1.10