diff options
Diffstat (limited to 'deps/v8/src/wasm/wasm-debug.cc')
-rw-r--r-- | deps/v8/src/wasm/wasm-debug.cc | 174 |
1 files changed, 159 insertions, 15 deletions
diff --git a/deps/v8/src/wasm/wasm-debug.cc b/deps/v8/src/wasm/wasm-debug.cc index adfbd0c168..f942c92127 100644 --- a/deps/v8/src/wasm/wasm-debug.cc +++ b/deps/v8/src/wasm/wasm-debug.cc @@ -7,6 +7,7 @@ #include "src/assembler-inl.h" #include "src/assert-scope.h" #include "src/compiler/wasm-compiler.h" +#include "src/debug/debug-scopes.h" #include "src/debug/debug.h" #include "src/factory.h" #include "src/frames-inl.h" @@ -24,6 +25,42 @@ using namespace v8::internal::wasm; namespace { +template <bool internal, typename... Args> +Handle<String> PrintFToOneByteString(Isolate* isolate, const char* format, + Args... args) { + // Maximum length of a formatted value name ("param#%d", "local#%d", + // "global#%d"). + constexpr int kMaxStrLen = 18; + EmbeddedVector<char, kMaxStrLen> value; + int len = SNPrintF(value, format, args...); + CHECK(len > 0 && len < value.length()); + Vector<uint8_t> name = Vector<uint8_t>::cast(value.SubVector(0, len)); + return internal + ? isolate->factory()->InternalizeOneByteString(name) + : isolate->factory()->NewStringFromOneByte(name).ToHandleChecked(); +} + +Handle<Object> WasmValToValueObject(Isolate* isolate, WasmVal value) { + switch (value.type) { + case kWasmI32: + if (Smi::IsValid(value.to<int32_t>())) + return handle(Smi::FromInt(value.to<int32_t>()), isolate); + return PrintFToOneByteString<false>(isolate, "%d", value.to<int32_t>()); + case kWasmI64: + if (Smi::IsValid(value.to<int64_t>())) + return handle(Smi::FromIntptr(value.to<int64_t>()), isolate); + return PrintFToOneByteString<false>(isolate, "%" PRId64, + value.to<int64_t>()); + case kWasmF32: + return isolate->factory()->NewNumber(value.to<float>()); + case kWasmF64: + return isolate->factory()->NewNumber(value.to<double>()); + default: + UNIMPLEMENTED(); + return isolate->factory()->undefined_value(); + } +} + // Forward declaration. class InterpreterHandle; InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info); @@ -68,9 +105,12 @@ class InterpreterHandle { public: // Initialize in the right order, using helper methods to make this possible. // WasmInterpreter has to be allocated in place, since it is not movable. - InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info) + InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info, + WasmInstance* external_instance = nullptr) : instance_(debug_info->wasm_instance()->compiled_module()->module()), - interpreter_(isolate, GetBytesEnv(&instance_, debug_info)), + interpreter_(isolate, GetBytesEnv(external_instance ? external_instance + : &instance_, + debug_info)), isolate_(isolate) { DisallowHeapAllocation no_gc; @@ -303,10 +343,9 @@ class InterpreterHandle { WasmInterpreter::Thread* thread = interpreter()->GetThread(0); DCHECK_LT(0, thread->GetFrameCount()); - wasm::InterpretedFrame frame = - thread->GetFrame(thread->GetFrameCount() - 1); - return compiled_module->GetFunctionOffset(frame.function()->func_index) + - frame.pc(); + auto frame = thread->GetFrame(thread->GetFrameCount() - 1); + return compiled_module->GetFunctionOffset(frame->function()->func_index) + + frame->pc(); } std::vector<std::pair<uint32_t, int>> GetInterpretedStack( @@ -320,8 +359,8 @@ class InterpreterHandle { std::vector<std::pair<uint32_t, int>> stack; stack.reserve(frame_range.second - frame_range.first); for (uint32_t fp = frame_range.first; fp < frame_range.second; ++fp) { - wasm::InterpretedFrame frame = thread->GetFrame(fp); - stack.emplace_back(frame.function()->func_index, frame.pc()); + auto frame = thread->GetFrame(fp); + stack.emplace_back(frame->function()->func_index, frame->pc()); } return stack; } @@ -336,8 +375,7 @@ class InterpreterHandle { DCHECK_LE(0, idx); DCHECK_GT(frame_range.second - frame_range.first, idx); - return std::unique_ptr<wasm::InterpretedFrame>(new wasm::InterpretedFrame( - thread->GetMutableFrame(frame_range.first + idx))); + return thread->GetFrame(frame_range.first + idx); } void Unwind(Address frame_pointer) { @@ -366,8 +404,92 @@ class InterpreterHandle { } void UpdateMemory(JSArrayBuffer* new_memory) { - instance_.mem_start = reinterpret_cast<byte*>(new_memory->backing_store()); - CHECK(new_memory->byte_length()->ToUint32(&instance_.mem_size)); + byte* mem_start = reinterpret_cast<byte*>(new_memory->backing_store()); + uint32_t mem_size; + CHECK(new_memory->byte_length()->ToUint32(&mem_size)); + interpreter()->UpdateMemory(mem_start, mem_size); + } + + Handle<JSArray> GetScopeDetails(Address frame_pointer, int frame_index, + Handle<WasmInstanceObject> instance) { + auto frame = GetInterpretedFrame(frame_pointer, frame_index); + + Handle<FixedArray> global_scope = + isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize); + global_scope->set(ScopeIterator::kScopeDetailsTypeIndex, + Smi::FromInt(ScopeIterator::ScopeTypeGlobal)); + Handle<JSObject> global_scope_object = + isolate_->factory()->NewJSObjectWithNullProto(); + global_scope->set(ScopeIterator::kScopeDetailsObjectIndex, + *global_scope_object); + + // TODO(clemensh): Add globals to the global scope. + + if (instance->has_memory_buffer()) { + Handle<String> name = isolate_->factory()->InternalizeOneByteString( + STATIC_CHAR_VECTOR("memory")); + Handle<JSArrayBuffer> memory_buffer(instance->memory_buffer(), isolate_); + uint32_t byte_length; + CHECK(memory_buffer->byte_length()->ToUint32(&byte_length)); + Handle<JSTypedArray> uint8_array = isolate_->factory()->NewJSTypedArray( + kExternalUint8Array, memory_buffer, 0, byte_length); + JSObject::SetOwnPropertyIgnoreAttributes(global_scope_object, name, + uint8_array, NONE) + .Check(); + } + + Handle<FixedArray> local_scope = + isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize); + local_scope->set(ScopeIterator::kScopeDetailsTypeIndex, + Smi::FromInt(ScopeIterator::ScopeTypeLocal)); + Handle<JSObject> local_scope_object = + isolate_->factory()->NewJSObjectWithNullProto(); + local_scope->set(ScopeIterator::kScopeDetailsObjectIndex, + *local_scope_object); + + // Fill parameters and locals. + int num_params = frame->GetParameterCount(); + int num_locals = frame->GetLocalCount(); + DCHECK_LE(num_params, num_locals); + for (int i = 0; i < num_locals; ++i) { + // TODO(clemensh): Use names from name section if present. + const char* label = i < num_params ? "param#%d" : "local#%d"; + Handle<String> name = PrintFToOneByteString<true>(isolate_, label, i); + WasmVal value = frame->GetLocalValue(i); + Handle<Object> value_obj = WasmValToValueObject(isolate_, value); + JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, name, + value_obj, NONE) + .Check(); + } + + // Fill stack values. + int stack_count = frame->GetStackHeight(); + // Use an object without prototype instead of an Array, for nicer displaying + // in DevTools. For Arrays, the length field and prototype is displayed, + // which does not make too much sense here. + Handle<JSObject> stack_obj = + isolate_->factory()->NewJSObjectWithNullProto(); + for (int i = 0; i < stack_count; ++i) { + WasmVal value = frame->GetStackValue(i); + Handle<Object> value_obj = WasmValToValueObject(isolate_, value); + JSObject::SetOwnElementIgnoreAttributes( + stack_obj, static_cast<uint32_t>(i), value_obj, NONE) + .Check(); + } + Handle<String> stack_name = isolate_->factory()->InternalizeOneByteString( + STATIC_CHAR_VECTOR("stack")); + JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, stack_name, + stack_obj, NONE) + .Check(); + + Handle<JSArray> global_jsarr = + isolate_->factory()->NewJSArrayWithElements(global_scope); + Handle<JSArray> local_jsarr = + isolate_->factory()->NewJSArrayWithElements(local_scope); + Handle<FixedArray> all_scopes = isolate_->factory()->NewFixedArray(2); + all_scopes->set(0, *global_jsarr); + all_scopes->set(1, *local_jsarr); + return isolate_->factory()->NewJSArrayWithElements(all_scopes); } }; @@ -453,12 +575,25 @@ void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance, } // namespace Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<WasmInstanceObject> instance) { - Isolate* isolate = instance->GetIsolate(); - Factory* factory = isolate->factory(); + DCHECK(!instance->has_debug_info()); + Factory* factory = instance->GetIsolate()->factory(); Handle<FixedArray> arr = factory->NewFixedArray(kFieldCount, TENURED); arr->set(kWrapperTracerHeader, Smi::kZero); arr->set(kInstance, *instance); - return Handle<WasmDebugInfo>::cast(arr); + Handle<WasmDebugInfo> debug_info = Handle<WasmDebugInfo>::cast(arr); + instance->set_debug_info(*debug_info); + return debug_info; +} + +WasmInterpreter* WasmDebugInfo::SetupForTesting( + Handle<WasmInstanceObject> instance_obj, WasmInstance* instance) { + Handle<WasmDebugInfo> debug_info = WasmDebugInfo::New(instance_obj); + Isolate* isolate = instance_obj->GetIsolate(); + InterpreterHandle* cpp_handle = + new InterpreterHandle(isolate, *debug_info, instance); + Handle<Object> handle = Managed<InterpreterHandle>::New(isolate, cpp_handle); + debug_info->set(kInterpreterHandle, *handle); + return cpp_handle->interpreter(); } bool WasmDebugInfo::IsDebugInfo(Object* object) { @@ -555,3 +690,12 @@ void WasmDebugInfo::UpdateMemory(JSArrayBuffer* new_memory) { if (!interp_handle) return; interp_handle->UpdateMemory(new_memory); } + +// static +Handle<JSArray> WasmDebugInfo::GetScopeDetails(Handle<WasmDebugInfo> debug_info, + Address frame_pointer, + int frame_index) { + InterpreterHandle* interp_handle = GetInterpreterHandle(*debug_info); + Handle<WasmInstanceObject> instance(debug_info->wasm_instance()); + return interp_handle->GetScopeDetails(frame_pointer, frame_index, instance); +} |