LCOV - code coverage report
Current view: top level - src/wasm - wasm-debug.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 252 276 91.3 %
Date: 2017-04-26 Functions: 40 42 95.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/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.h"
      21             : #include "src/zone/accounting-allocator.h"
      22             : 
      23             : using namespace v8::internal;
      24             : using namespace v8::internal::wasm;
      25             : 
      26             : namespace {
      27             : 
      28             : template <bool internal, typename... Args>
      29         234 : Handle<String> PrintFToOneByteString(Isolate* isolate, const char* format,
      30             :                                      Args... args) {
      31             :   // Maximum length of a formatted value name ("param#%d", "local#%d",
      32             :   // "global#%d").
      33             :   constexpr int kMaxStrLen = 18;
      34             :   EmbeddedVector<char, kMaxStrLen> value;
      35         234 :   int len = SNPrintF(value, format, args...);
      36         234 :   CHECK(len > 0 && len < value.length());
      37             :   Vector<uint8_t> name = Vector<uint8_t>::cast(value.SubVector(0, len));
      38             :   return internal
      39             :              ? isolate->factory()->InternalizeOneByteString(name)
      40         234 :              : isolate->factory()->NewStringFromOneByte(name).ToHandleChecked();
      41             : }
      42             : 
      43         294 : Handle<Object> WasmValToValueObject(Isolate* isolate, WasmVal value) {
      44         294 :   switch (value.type) {
      45             :     case kWasmI32:
      46             :       if (Smi::IsValid(value.to<int32_t>()))
      47         294 :         return handle(Smi::FromInt(value.to<int32_t>()), isolate);
      48             :       return PrintFToOneByteString<false>(isolate, "%d", value.to<int32_t>());
      49             :     case kWasmI64:
      50           0 :       if (Smi::IsValid(value.to<int64_t>()))
      51           0 :         return handle(Smi::FromIntptr(value.to<int64_t>()), isolate);
      52             :       return PrintFToOneByteString<false>(isolate, "%" PRId64,
      53           0 :                                           value.to<int64_t>());
      54             :     case kWasmF32:
      55           0 :       return isolate->factory()->NewNumber(value.to<float>());
      56             :     case kWasmF64:
      57           0 :       return isolate->factory()->NewNumber(value.to<double>());
      58             :     default:
      59           0 :       UNIMPLEMENTED();
      60             :       return isolate->factory()->undefined_value();
      61             :   }
      62             : }
      63             : 
      64             : // Forward declaration.
      65             : class InterpreterHandle;
      66             : InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info);
      67             : 
      68             : class InterpreterHandle {
      69             :   WasmInstance instance_;
      70             :   WasmInterpreter interpreter_;
      71             :   Isolate* isolate_;
      72             :   StepAction next_step_action_ = StepNone;
      73             :   int last_step_stack_depth_ = 0;
      74             :   std::unordered_map<Address, uint32_t> activations_;
      75             : 
      76       51425 :   uint32_t StartActivation(Address frame_pointer) {
      77       51425 :     WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
      78       51425 :     uint32_t activation_id = thread->StartActivation();
      79             :     DCHECK_EQ(0, activations_.count(frame_pointer));
      80      102850 :     activations_.insert(std::make_pair(frame_pointer, activation_id));
      81       51425 :     return activation_id;
      82             :   }
      83             : 
      84       51425 :   void FinishActivation(Address frame_pointer, uint32_t activation_id) {
      85       51425 :     WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
      86       51425 :     thread->FinishActivation(activation_id);
      87             :     DCHECK_EQ(1, activations_.count(frame_pointer));
      88             :     activations_.erase(frame_pointer);
      89       51425 :   }
      90             : 
      91        3630 :   std::pair<uint32_t, uint32_t> GetActivationFrameRange(
      92             :       WasmInterpreter::Thread* thread, Address frame_pointer) {
      93             :     DCHECK_EQ(1, activations_.count(frame_pointer));
      94        3630 :     uint32_t activation_id = activations_.find(frame_pointer)->second;
      95        3630 :     uint32_t num_activations = static_cast<uint32_t>(activations_.size() - 1);
      96        3630 :     uint32_t frame_base = thread->ActivationFrameBase(activation_id);
      97             :     uint32_t frame_limit = activation_id == num_activations
      98        3495 :                                ? thread->GetFrameCount()
      99        7125 :                                : thread->ActivationFrameBase(activation_id + 1);
     100             :     DCHECK_LE(frame_base, frame_limit);
     101             :     DCHECK_LE(frame_limit, thread->GetFrameCount());
     102        3630 :     return {frame_base, frame_limit};
     103             :   }
     104             : 
     105             :  public:
     106             :   // Initialize in the right order, using helper methods to make this possible.
     107             :   // WasmInterpreter has to be allocated in place, since it is not movable.
     108        1153 :   InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info)
     109        1153 :       : instance_(debug_info->wasm_instance()->compiled_module()->module()),
     110             :         interpreter_(isolate, GetBytesEnv(&instance_, debug_info)),
     111        2306 :         isolate_(isolate) {
     112             :     DisallowHeapAllocation no_gc;
     113             : 
     114        1153 :     WasmInstanceObject* instance = debug_info->wasm_instance();
     115             : 
     116             :     // Store a global handle to the wasm instance in the interpreter.
     117        1153 :     interpreter_.SetInstanceObject(instance);
     118             : 
     119             :     // Set memory start pointer and size.
     120        1153 :     instance_.mem_start = nullptr;
     121        1153 :     instance_.mem_size = 0;
     122        1153 :     if (instance->has_memory_buffer()) {
     123          15 :       UpdateMemory(instance->memory_buffer());
     124             :     } else {
     125             :       DCHECK_EQ(0, instance_.module->min_mem_pages);
     126             :     }
     127             : 
     128             :     // Set pointer to globals storage.
     129             :     instance_.globals_start =
     130        1153 :         debug_info->wasm_instance()->compiled_module()->GetGlobalsStartOrNull();
     131        1153 :   }
     132             : 
     133        2270 :   ~InterpreterHandle() {
     134             :     DCHECK_EQ(0, activations_.size());
     135        1135 :   }
     136             : 
     137        1153 :   static ModuleBytesEnv GetBytesEnv(WasmInstance* instance,
     138             :                                     WasmDebugInfo* debug_info) {
     139             :     // Return raw pointer into heap. The WasmInterpreter will make its own copy
     140             :     // of this data anyway, and there is no heap allocation in-between.
     141             :     SeqOneByteString* bytes_str =
     142        1153 :         debug_info->wasm_instance()->compiled_module()->module_bytes();
     143        1153 :     Vector<const byte> bytes(bytes_str->GetChars(), bytes_str->length());
     144        2306 :     return ModuleBytesEnv(instance->module, instance, bytes);
     145             :   }
     146             : 
     147             :   WasmInterpreter* interpreter() { return &interpreter_; }
     148             :   const WasmModule* module() { return instance_.module; }
     149             : 
     150             :   void PrepareStep(StepAction step_action) {
     151         244 :     next_step_action_ = step_action;
     152         244 :     last_step_stack_depth_ = CurrentStackDepth();
     153             :   }
     154             : 
     155         349 :   void ClearStepping() { next_step_action_ = StepNone; }
     156             : 
     157         244 :   int CurrentStackDepth() {
     158             :     DCHECK_EQ(1, interpreter()->GetThreadCount());
     159         244 :     return interpreter()->GetThread(0)->GetFrameCount();
     160             :   }
     161             : 
     162             :   // Returns true if exited regularly, false if a trap/exception occured and was
     163             :   // not handled inside this activation. In the latter case, a pending exception
     164             :   // will have been set on the isolate.
     165       51425 :   bool Execute(Address frame_pointer, uint32_t func_index,
     166      154630 :                uint8_t* arg_buffer) {
     167             :     DCHECK_GE(module()->functions.size(), func_index);
     168      329303 :     FunctionSig* sig = module()->functions[func_index].sig;
     169             :     DCHECK_GE(kMaxInt, sig->parameter_count());
     170       51425 :     int num_params = static_cast<int>(sig->parameter_count());
     171             :     ScopedVector<WasmVal> wasm_args(num_params);
     172             :     uint8_t* arg_buf_ptr = arg_buffer;
     173      124325 :     for (int i = 0; i < num_params; ++i) {
     174      145800 :       uint32_t param_size = 1 << ElementSizeLog2Of(sig->GetParam(i));
     175             : #define CASE_ARG_TYPE(type, ctype)                                  \
     176             :   case type:                                                        \
     177             :     DCHECK_EQ(param_size, sizeof(ctype));                           \
     178             :     wasm_args[i] = WasmVal(ReadUnalignedValue<ctype>(arg_buf_ptr)); \
     179             :     break;
     180       72900 :       switch (sig->GetParam(i)) {
     181       11562 :         CASE_ARG_TYPE(kWasmI32, uint32_t)
     182       23100 :         CASE_ARG_TYPE(kWasmI64, uint64_t)
     183        2415 :         CASE_ARG_TYPE(kWasmF32, float)
     184       35823 :         CASE_ARG_TYPE(kWasmF64, double)
     185             : #undef CASE_ARG_TYPE
     186             :         default:
     187           0 :           UNREACHABLE();
     188             :       }
     189       72900 :       arg_buf_ptr += param_size;
     190             :     }
     191             : 
     192       51425 :     uint32_t activation_id = StartActivation(frame_pointer);
     193             : 
     194       51425 :     WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
     195      102850 :     thread->InitFrame(&module()->functions[func_index], wasm_args.start());
     196             :     bool finished = false;
     197       51425 :     while (!finished) {
     198             :       // TODO(clemensh): Add occasional StackChecks.
     199       51780 :       WasmInterpreter::State state = ContinueExecution(thread);
     200       51780 :       switch (state) {
     201             :         case WasmInterpreter::State::PAUSED:
     202         355 :           NotifyDebugEventListeners(thread);
     203         355 :           break;
     204             :         case WasmInterpreter::State::FINISHED:
     205             :           // Perfect, just break the switch and exit the loop.
     206             :           finished = true;
     207             :           break;
     208             :         case WasmInterpreter::State::TRAPPED: {
     209             :           int message_id =
     210         120 :               WasmOpcodes::TrapReasonToMessageId(thread->GetTrapReason());
     211             :           Handle<Object> exception = isolate_->factory()->NewWasmRuntimeError(
     212         120 :               static_cast<MessageTemplate::Template>(message_id));
     213         120 :           isolate_->Throw(*exception);
     214             :           // Handle this exception. Return without trying to read back the
     215             :           // return value.
     216         120 :           auto result = thread->HandleException(isolate_);
     217         120 :           return result == WasmInterpreter::Thread::HANDLED;
     218             :         } break;
     219             :         case WasmInterpreter::State::STOPPED:
     220             :           // An exception happened, and the current activation was unwound.
     221             :           DCHECK_EQ(thread->ActivationFrameBase(activation_id),
     222             :                     thread->GetFrameCount());
     223             :           return false;
     224             :         // RUNNING should never occur here.
     225             :         case WasmInterpreter::State::RUNNING:
     226             :         default:
     227           0 :           UNREACHABLE();
     228             :       }
     229             :     }
     230             : 
     231             :     // Copy back the return value
     232             :     DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count());
     233             :     // TODO(wasm): Handle multi-value returns.
     234             :     DCHECK_EQ(1, kV8MaxWasmFunctionReturns);
     235       51200 :     if (sig->return_count()) {
     236       50928 :       WasmVal ret_val = thread->GetReturnValue(0);
     237             : #define CASE_RET_TYPE(type, ctype)                                       \
     238             :   case type:                                                             \
     239             :     DCHECK_EQ(1 << ElementSizeLog2Of(sig->GetReturn(0)), sizeof(ctype)); \
     240             :     WriteUnalignedValue<ctype>(arg_buffer, ret_val.to<ctype>());         \
     241             :     break;
     242       50928 :       switch (sig->GetReturn(0)) {
     243             :         CASE_RET_TYPE(kWasmI32, uint32_t)
     244             :         CASE_RET_TYPE(kWasmI64, uint64_t)
     245             :         CASE_RET_TYPE(kWasmF32, float)
     246             :         CASE_RET_TYPE(kWasmF64, double)
     247             : #undef CASE_RET_TYPE
     248             :         default:
     249           0 :           UNREACHABLE();
     250             :       }
     251             :     }
     252             : 
     253       51200 :     FinishActivation(frame_pointer, activation_id);
     254             : 
     255       51200 :     return true;
     256             :   }
     257             : 
     258       51780 :   WasmInterpreter::State ContinueExecution(WasmInterpreter::Thread* thread) {
     259       51780 :     switch (next_step_action_) {
     260             :       case StepNone:
     261       51530 :         return thread->Run();
     262             :       case StepIn:
     263             :         return thread->Step();
     264             :       case StepOut:
     265          25 :         thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterReturn);
     266          25 :         return thread->Run();
     267             :       case StepNext: {
     268          38 :         int stack_depth = thread->GetFrameCount();
     269          38 :         if (stack_depth == last_step_stack_depth_) return thread->Step();
     270             :         thread->AddBreakFlags(stack_depth > last_step_stack_depth_
     271             :                                   ? WasmInterpreter::BreakFlag::AfterReturn
     272           6 :                                   : WasmInterpreter::BreakFlag::AfterCall);
     273           6 :         return thread->Run();
     274             :       }
     275             :       default:
     276           0 :         UNREACHABLE();
     277             :         return WasmInterpreter::STOPPED;
     278             :     }
     279             :   }
     280             : 
     281         355 :   Handle<WasmInstanceObject> GetInstanceObject() {
     282         355 :     StackTraceFrameIterator it(isolate_);
     283             :     WasmInterpreterEntryFrame* frame =
     284             :         WasmInterpreterEntryFrame::cast(it.frame());
     285         355 :     Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_);
     286             :     DCHECK_EQ(this, GetInterpreterHandle(instance_obj->debug_info()));
     287         710 :     return instance_obj;
     288             :   }
     289             : 
     290         355 :   void NotifyDebugEventListeners(WasmInterpreter::Thread* thread) {
     291             :     // Enter the debugger.
     292        1059 :     DebugScope debug_scope(isolate_->debug());
     293         485 :     if (debug_scope.failed()) return;
     294             : 
     295             :     // Postpone interrupt during breakpoint processing.
     296         355 :     PostponeInterruptsScope postpone(isolate_);
     297             : 
     298             :     // Check whether we hit a breakpoint.
     299         710 :     if (isolate_->debug()->break_points_active()) {
     300             :       Handle<WasmCompiledModule> compiled_module(
     301        1065 :           GetInstanceObject()->compiled_module(), isolate_);
     302         355 :       int position = GetTopPosition(compiled_module);
     303             :       Handle<FixedArray> breakpoints;
     304         710 :       if (compiled_module->CheckBreakPoints(position).ToHandle(&breakpoints)) {
     305             :         // We hit one or several breakpoints. Clear stepping, notify the
     306             :         // listeners and return.
     307             :         ClearStepping();
     308             :         Handle<Object> hit_breakpoints_js =
     309         124 :             isolate_->factory()->NewJSArrayWithElements(breakpoints);
     310         248 :         isolate_->debug()->OnDebugBreak(hit_breakpoints_js);
     311             :         return;
     312             :       }
     313             :     }
     314             : 
     315             :     // We did not hit a breakpoint, so maybe this pause is related to stepping.
     316             :     bool hit_step = false;
     317         231 :     switch (next_step_action_) {
     318             :       case StepNone:
     319             :         break;
     320             :       case StepIn:
     321             :         hit_step = true;
     322         174 :         break;
     323             :       case StepOut:
     324          19 :         hit_step = thread->GetFrameCount() < last_step_stack_depth_;
     325          19 :         break;
     326             :       case StepNext: {
     327          38 :         hit_step = thread->GetFrameCount() == last_step_stack_depth_;
     328          38 :         break;
     329             :       }
     330             :       default:
     331           0 :         UNREACHABLE();
     332             :     }
     333         231 :     if (!hit_step) return;
     334             :     ClearStepping();
     335         675 :     isolate_->debug()->OnDebugBreak(isolate_->factory()->undefined_value());
     336             :   }
     337             : 
     338         355 :   int GetTopPosition(Handle<WasmCompiledModule> compiled_module) {
     339             :     DCHECK_EQ(1, interpreter()->GetThreadCount());
     340         355 :     WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
     341             :     DCHECK_LT(0, thread->GetFrameCount());
     342             : 
     343         355 :     auto frame = thread->GetFrame(thread->GetFrameCount() - 1);
     344         710 :     return compiled_module->GetFunctionOffset(frame->function()->func_index) +
     345         710 :            frame->pc();
     346             :   }
     347             : 
     348        3001 :   std::vector<std::pair<uint32_t, int>> GetInterpretedStack(
     349             :       Address frame_pointer) {
     350             :     DCHECK_EQ(1, interpreter()->GetThreadCount());
     351        3001 :     WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
     352             : 
     353             :     std::pair<uint32_t, uint32_t> frame_range =
     354        3001 :         GetActivationFrameRange(thread, frame_pointer);
     355             : 
     356             :     std::vector<std::pair<uint32_t, int>> stack;
     357        3001 :     stack.reserve(frame_range.second - frame_range.first);
     358     1973031 :     for (uint32_t fp = frame_range.first; fp < frame_range.second; ++fp) {
     359     1970030 :       auto frame = thread->GetFrame(fp);
     360     3940060 :       stack.emplace_back(frame->function()->func_index, frame->pc());
     361             :     }
     362        3001 :     return stack;
     363             :   }
     364             : 
     365         629 :   std::unique_ptr<wasm::InterpretedFrame> GetInterpretedFrame(
     366             :       Address frame_pointer, int idx) {
     367             :     DCHECK_EQ(1, interpreter()->GetThreadCount());
     368         629 :     WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
     369             : 
     370             :     std::pair<uint32_t, uint32_t> frame_range =
     371         629 :         GetActivationFrameRange(thread, frame_pointer);
     372             :     DCHECK_LE(0, idx);
     373             :     DCHECK_GT(frame_range.second - frame_range.first, idx);
     374             : 
     375         629 :     return thread->GetFrame(frame_range.first + idx);
     376             :   }
     377             : 
     378         225 :   void Unwind(Address frame_pointer) {
     379             :     // Find the current activation.
     380             :     DCHECK_EQ(1, activations_.count(frame_pointer));
     381             :     // Activations must be properly stacked:
     382             :     DCHECK_EQ(activations_.size() - 1, activations_[frame_pointer]);
     383         225 :     uint32_t activation_id = static_cast<uint32_t>(activations_.size() - 1);
     384             : 
     385             :     // Unwind the frames of the current activation if not already unwound.
     386         225 :     WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
     387         450 :     if (static_cast<uint32_t>(thread->GetFrameCount()) >
     388         225 :         thread->ActivationFrameBase(activation_id)) {
     389             :       using ExceptionResult = WasmInterpreter::Thread::ExceptionHandlingResult;
     390           0 :       ExceptionResult result = thread->HandleException(isolate_);
     391             :       // TODO(wasm): Handle exceptions caught in wasm land.
     392           0 :       CHECK_EQ(ExceptionResult::UNWOUND, result);
     393             :     }
     394             : 
     395         225 :     FinishActivation(frame_pointer, activation_id);
     396         225 :   }
     397             : 
     398       83708 :   uint64_t NumInterpretedCalls() {
     399             :     DCHECK_EQ(1, interpreter()->GetThreadCount());
     400       83708 :     return interpreter()->GetThread(0)->NumInterpretedCalls();
     401             :   }
     402             : 
     403          45 :   void UpdateMemory(JSArrayBuffer* new_memory) {
     404          45 :     instance_.mem_start = reinterpret_cast<byte*>(new_memory->backing_store());
     405          90 :     CHECK(new_memory->byte_length()->ToUint32(&instance_.mem_size));
     406          45 :   }
     407             : 
     408         276 :   Handle<JSArray> GetScopeDetails(Address frame_pointer, int frame_index,
     409             :                                   Handle<WasmInstanceObject> instance) {
     410         276 :     auto frame = GetInterpretedFrame(frame_pointer, frame_index);
     411             : 
     412             :     Handle<FixedArray> global_scope =
     413         276 :         isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
     414             :     global_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
     415             :                       Smi::FromInt(ScopeIterator::ScopeTypeGlobal));
     416             :     Handle<JSObject> global_scope_object =
     417         276 :         isolate_->factory()->NewJSObjectWithNullProto();
     418             :     global_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
     419         276 :                       *global_scope_object);
     420             : 
     421             :     // TODO(clemensh): Add globals to the global scope.
     422             : 
     423         276 :     if (instance->has_memory_buffer()) {
     424             :       Handle<String> name = isolate_->factory()->InternalizeOneByteString(
     425           0 :           STATIC_CHAR_VECTOR("memory"));
     426           0 :       Handle<JSArrayBuffer> memory_buffer(instance->memory_buffer(), isolate_);
     427             :       uint32_t byte_length;
     428           0 :       CHECK(memory_buffer->byte_length()->ToUint32(&byte_length));
     429             :       Handle<JSTypedArray> uint8_array = isolate_->factory()->NewJSTypedArray(
     430           0 :           kExternalUint8Array, memory_buffer, 0, byte_length);
     431             :       JSObject::SetOwnPropertyIgnoreAttributes(global_scope_object, name,
     432             :                                                uint8_array, NONE)
     433           0 :           .Check();
     434             :     }
     435             : 
     436             :     Handle<FixedArray> local_scope =
     437         276 :         isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
     438             :     local_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
     439             :                      Smi::FromInt(ScopeIterator::ScopeTypeLocal));
     440             :     Handle<JSObject> local_scope_object =
     441         276 :         isolate_->factory()->NewJSObjectWithNullProto();
     442             :     local_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
     443         276 :                      *local_scope_object);
     444             : 
     445             :     // Fill parameters and locals.
     446         276 :     int num_params = frame->GetParameterCount();
     447         276 :     int num_locals = frame->GetLocalCount();
     448             :     DCHECK_LE(num_params, num_locals);
     449         510 :     for (int i = 0; i < num_locals; ++i) {
     450             :       // TODO(clemensh): Use names from name section if present.
     451         234 :       const char* label = i < num_params ? "param#%d" : "local#%d";
     452         234 :       Handle<String> name = PrintFToOneByteString<true>(isolate_, label, i);
     453         234 :       WasmVal value = frame->GetLocalValue(i);
     454         234 :       Handle<Object> value_obj = WasmValToValueObject(isolate_, value);
     455             :       JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, name,
     456             :                                                value_obj, NONE)
     457         468 :           .Check();
     458             :     }
     459             : 
     460             :     // Fill stack values.
     461         276 :     int stack_count = frame->GetStackHeight();
     462             :     // Use an object without prototype instead of an Array, for nicer displaying
     463             :     // in DevTools. For Arrays, the length field and prototype is displayed,
     464             :     // which does not make too much sense here.
     465             :     Handle<JSObject> stack_obj =
     466         276 :         isolate_->factory()->NewJSObjectWithNullProto();
     467         336 :     for (int i = 0; i < stack_count; ++i) {
     468          60 :       WasmVal value = frame->GetStackValue(i);
     469          60 :       Handle<Object> value_obj = WasmValToValueObject(isolate_, value);
     470             :       JSObject::SetOwnElementIgnoreAttributes(
     471             :           stack_obj, static_cast<uint32_t>(i), value_obj, NONE)
     472         120 :           .Check();
     473             :     }
     474             :     Handle<String> stack_name = isolate_->factory()->InternalizeOneByteString(
     475         276 :         STATIC_CHAR_VECTOR("stack"));
     476             :     JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, stack_name,
     477             :                                              stack_obj, NONE)
     478         552 :         .Check();
     479             : 
     480             :     Handle<JSArray> global_jsarr =
     481         276 :         isolate_->factory()->NewJSArrayWithElements(global_scope);
     482             :     Handle<JSArray> local_jsarr =
     483         276 :         isolate_->factory()->NewJSArrayWithElements(local_scope);
     484         276 :     Handle<FixedArray> all_scopes = isolate_->factory()->NewFixedArray(2);
     485         276 :     all_scopes->set(0, *global_jsarr);
     486         276 :     all_scopes->set(1, *local_jsarr);
     487         552 :     return isolate_->factory()->NewJSArrayWithElements(all_scopes);
     488             :   }
     489             : };
     490             : 
     491        1334 : InterpreterHandle* GetOrCreateInterpreterHandle(
     492             :     Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
     493             :   Handle<Object> handle(debug_info->get(WasmDebugInfo::kInterpreterHandle),
     494             :                         isolate);
     495        1334 :   if (handle->IsUndefined(isolate)) {
     496        1153 :     InterpreterHandle* cpp_handle = new InterpreterHandle(isolate, *debug_info);
     497        1153 :     handle = Managed<InterpreterHandle>::New(isolate, cpp_handle);
     498        1153 :     debug_info->set(WasmDebugInfo::kInterpreterHandle, *handle);
     499             :   }
     500             : 
     501        1334 :   return Handle<Managed<InterpreterHandle>>::cast(handle)->get();
     502             : }
     503             : 
     504       55524 : InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info) {
     505             :   Object* handle_obj = debug_info->get(WasmDebugInfo::kInterpreterHandle);
     506             :   DCHECK(!handle_obj->IsUndefined(debug_info->GetIsolate()));
     507       55524 :   return Managed<InterpreterHandle>::cast(handle_obj)->get();
     508             : }
     509             : 
     510       83738 : InterpreterHandle* GetInterpreterHandleOrNull(WasmDebugInfo* debug_info) {
     511             :   Object* handle_obj = debug_info->get(WasmDebugInfo::kInterpreterHandle);
     512       83738 :   if (handle_obj->IsUndefined(debug_info->GetIsolate())) return nullptr;
     513       83738 :   return Managed<InterpreterHandle>::cast(handle_obj)->get();
     514             : }
     515             : 
     516        2381 : int GetNumFunctions(WasmInstanceObject* instance) {
     517             :   size_t num_functions =
     518        2381 :       instance->compiled_module()->module()->functions.size();
     519             :   DCHECK_GE(kMaxInt, num_functions);
     520        2381 :   return static_cast<int>(num_functions);
     521             : }
     522             : 
     523        1228 : Handle<FixedArray> GetOrCreateInterpretedFunctions(
     524             :     Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
     525             :   Handle<Object> obj(debug_info->get(WasmDebugInfo::kInterpretedFunctions),
     526             :                      isolate);
     527        1228 :   if (!obj->IsUndefined(isolate)) return Handle<FixedArray>::cast(obj);
     528             : 
     529             :   Handle<FixedArray> new_arr = isolate->factory()->NewFixedArray(
     530        1153 :       GetNumFunctions(debug_info->wasm_instance()));
     531        1153 :   debug_info->set(WasmDebugInfo::kInterpretedFunctions, *new_arr);
     532        1153 :   return new_arr;
     533             : }
     534             : 
     535             : using CodeRelocationMap = IdentityMap<Handle<Code>, FreeStoreAllocationPolicy>;
     536             : 
     537        4140 : void RedirectCallsitesInCode(Code* code, CodeRelocationMap& map) {
     538             :   DisallowHeapAllocation no_gc;
     539       17644 :   for (RelocIterator it(code, RelocInfo::kCodeTargetMask); !it.done();
     540        9364 :        it.next()) {
     541             :     DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode()));
     542       18728 :     Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
     543             :     Handle<Code>* new_target = map.Find(target);
     544        9364 :     if (!new_target) continue;
     545             :     it.rinfo()->set_target_address(code->GetIsolate(),
     546        2678 :                                    (*new_target)->instruction_start());
     547             :   }
     548        4140 : }
     549             : 
     550        1228 : void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance,
     551             :                                  CodeRelocationMap& map) {
     552             :   DisallowHeapAllocation no_gc;
     553             :   // Redirect all calls in wasm functions.
     554        1228 :   FixedArray* code_table = instance->compiled_module()->ptr_to_code_table();
     555        3927 :   for (int i = 0, e = GetNumFunctions(instance); i < e; ++i) {
     556        2699 :     RedirectCallsitesInCode(Code::cast(code_table->get(i)), map);
     557             :   }
     558             : 
     559             :   // Redirect all calls in exported functions.
     560             :   FixedArray* weak_exported_functions =
     561        1228 :       instance->compiled_module()->ptr_to_weak_exported_functions();
     562        1441 :   for (int i = 0, e = weak_exported_functions->length(); i != e; ++i) {
     563             :     WeakCell* weak_function = WeakCell::cast(weak_exported_functions->get(i));
     564        1441 :     if (weak_function->cleared()) continue;
     565        1441 :     Code* code = JSFunction::cast(weak_function->value())->code();
     566        1441 :     RedirectCallsitesInCode(code, map);
     567             :   }
     568        1228 : }
     569             : 
     570             : }  // namespace
     571             : 
     572        1153 : Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<WasmInstanceObject> instance) {
     573             :   Isolate* isolate = instance->GetIsolate();
     574             :   Factory* factory = isolate->factory();
     575        1153 :   Handle<FixedArray> arr = factory->NewFixedArray(kFieldCount, TENURED);
     576             :   arr->set(kWrapperTracerHeader, Smi::kZero);
     577        1153 :   arr->set(kInstance, *instance);
     578        1153 :   return Handle<WasmDebugInfo>::cast(arr);
     579             : }
     580             : 
     581           0 : bool WasmDebugInfo::IsDebugInfo(Object* object) {
     582           0 :   if (!object->IsFixedArray()) return false;
     583             :   FixedArray* arr = FixedArray::cast(object);
     584           0 :   if (arr->length() != kFieldCount) return false;
     585           0 :   if (!IsWasmInstance(arr->get(kInstance))) return false;
     586             :   Isolate* isolate = arr->GetIsolate();
     587           0 :   if (!arr->get(kInterpreterHandle)->IsUndefined(isolate) &&
     588             :       !arr->get(kInterpreterHandle)->IsForeign())
     589             :     return false;
     590           0 :   return true;
     591             : }
     592             : 
     593       56079 : WasmDebugInfo* WasmDebugInfo::cast(Object* object) {
     594             :   DCHECK(IsDebugInfo(object));
     595       56079 :   return reinterpret_cast<WasmDebugInfo*>(object);
     596             : }
     597             : 
     598        7269 : WasmInstanceObject* WasmDebugInfo::wasm_instance() {
     599        7269 :   return WasmInstanceObject::cast(get(kInstance));
     600             : }
     601             : 
     602         106 : void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
     603             :                                   int func_index, int offset) {
     604             :   Isolate* isolate = debug_info->GetIsolate();
     605         212 :   InterpreterHandle* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
     606         106 :   RedirectToInterpreter(debug_info, Vector<int>(&func_index, 1));
     607         212 :   const WasmFunction* func = &handle->module()->functions[func_index];
     608         106 :   handle->interpreter()->SetBreakpoint(func, offset, true);
     609         106 : }
     610             : 
     611        1228 : void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
     612             :                                           Vector<int> func_indexes) {
     613             :   Isolate* isolate = debug_info->GetIsolate();
     614             :   // Ensure that the interpreter is instantiated.
     615        1228 :   GetOrCreateInterpreterHandle(isolate, debug_info);
     616             :   Handle<FixedArray> interpreted_functions =
     617        1228 :       GetOrCreateInterpretedFunctions(isolate, debug_info);
     618        1228 :   Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
     619        1228 :   Handle<FixedArray> code_table = instance->compiled_module()->code_table();
     620        1228 :   CodeRelocationMap code_to_relocate(isolate->heap());
     621        3879 :   for (int func_index : func_indexes) {
     622             :     DCHECK_LE(0, func_index);
     623             :     DCHECK_GT(debug_info->wasm_instance()->module()->functions.size(),
     624             :               func_index);
     625        1477 :     if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) continue;
     626             : 
     627             :     Handle<Code> new_code = compiler::CompileWasmInterpreterEntry(
     628             :         isolate, func_index,
     629        2738 :         instance->compiled_module()->module()->functions[func_index].sig,
     630        1369 :         instance);
     631             : 
     632             :     Code* old_code = Code::cast(code_table->get(func_index));
     633        1369 :     interpreted_functions->set(func_index, *new_code);
     634             :     DCHECK_NULL(code_to_relocate.Find(old_code));
     635             :     code_to_relocate.Set(old_code, new_code);
     636             :   }
     637        1228 :   RedirectCallsitesInInstance(isolate, *instance, code_to_relocate);
     638        1228 : }
     639             : 
     640         244 : void WasmDebugInfo::PrepareStep(StepAction step_action) {
     641         244 :   GetInterpreterHandle(this)->PrepareStep(step_action);
     642         244 : }
     643             : 
     644       51425 : bool WasmDebugInfo::RunInterpreter(Address frame_pointer, int func_index,
     645             :                                    uint8_t* arg_buffer) {
     646             :   DCHECK_LE(0, func_index);
     647             :   return GetInterpreterHandle(this)->Execute(
     648       51425 :       frame_pointer, static_cast<uint32_t>(func_index), arg_buffer);
     649             : }
     650             : 
     651        3001 : std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack(
     652             :     Address frame_pointer) {
     653        3001 :   return GetInterpreterHandle(this)->GetInterpretedStack(frame_pointer);
     654             : }
     655             : 
     656         353 : std::unique_ptr<wasm::InterpretedFrame> WasmDebugInfo::GetInterpretedFrame(
     657             :     Address frame_pointer, int idx) {
     658         353 :   return GetInterpreterHandle(this)->GetInterpretedFrame(frame_pointer, idx);
     659             : }
     660             : 
     661         225 : void WasmDebugInfo::Unwind(Address frame_pointer) {
     662         225 :   return GetInterpreterHandle(this)->Unwind(frame_pointer);
     663             : }
     664             : 
     665       83708 : uint64_t WasmDebugInfo::NumInterpretedCalls() {
     666       83708 :   auto handle = GetInterpreterHandleOrNull(this);
     667       83708 :   return handle ? handle->NumInterpretedCalls() : 0;
     668             : }
     669             : 
     670          30 : void WasmDebugInfo::UpdateMemory(JSArrayBuffer* new_memory) {
     671          30 :   InterpreterHandle* interp_handle = GetInterpreterHandleOrNull(this);
     672          60 :   if (!interp_handle) return;
     673          30 :   interp_handle->UpdateMemory(new_memory);
     674             : }
     675             : 
     676             : // static
     677         276 : Handle<JSArray> WasmDebugInfo::GetScopeDetails(Handle<WasmDebugInfo> debug_info,
     678             :                                                Address frame_pointer,
     679             :                                                int frame_index) {
     680         276 :   InterpreterHandle* interp_handle = GetInterpreterHandle(*debug_info);
     681         276 :   Handle<WasmInstanceObject> instance(debug_info->wasm_instance());
     682         276 :   return interp_handle->GetScopeDetails(frame_pointer, frame_index, instance);
     683             : }

Generated by: LCOV version 1.10