Commit ae3f94bd authored by Philip Pfaffe's avatar Philip Pfaffe Committed by Commit Bot

Expose a proxy object to evaluateOnCallFrame for WebAssembly

When debugging WebAssembly, calls to evaluateOnCallFrame always return
undefined. This CL enables evaluateOnCallFrame for WebAssembly and
creates a proxy object that is injected into the evaluation context.

Bug: chromium:1127914
Change-Id: I3f5cff3be2c9de45c7b1f3f7ed4fc2e1cc545ac6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2429265
Commit-Queue: Philip Pfaffe <pfaffe@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarSimon Zünd <szuend@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70315}
parent a5024f9b
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "src/objects/contexts.h" #include "src/objects/contexts.h"
#include "src/snapshot/snapshot.h" #include "src/snapshot/snapshot.h"
#include "src/wasm/wasm-debug.h" #include "src/wasm/wasm-debug.h"
#include "src/wasm/wasm-js.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -106,6 +107,9 @@ V8_EXPORT MaybeHandle<Object> DebugEvaluate::WebAssembly( ...@@ -106,6 +107,9 @@ V8_EXPORT MaybeHandle<Object> DebugEvaluate::WebAssembly(
StackTraceFrameIterator it(isolate, frame_id); StackTraceFrameIterator it(isolate, frame_id);
if (!it.is_wasm()) return isolate->factory()->undefined_value(); if (!it.is_wasm()) return isolate->factory()->undefined_value();
WasmFrame* frame = WasmFrame::cast(it.frame());
Handle<JSProxy> context_extension = WasmJs::GetJSDebugProxy(frame);
DisableBreak disable_break_scope(isolate->debug(), /*disable=*/true); DisableBreak disable_break_scope(isolate->debug(), /*disable=*/true);
...@@ -114,12 +118,14 @@ V8_EXPORT MaybeHandle<Object> DebugEvaluate::WebAssembly( ...@@ -114,12 +118,14 @@ V8_EXPORT MaybeHandle<Object> DebugEvaluate::WebAssembly(
return {}; return {};
} }
Handle<Context> context = isolate->native_context(); Handle<ScopeInfo> scope_info =
Handle<JSObject> receiver(context->global_proxy(), isolate); ScopeInfo::CreateForWithScope(isolate, Handle<ScopeInfo>::null());
Handle<Context> context = isolate->factory()->NewWithContext(
isolate->native_context(), scope_info, context_extension);
Handle<Object> result; Handle<Object> result;
if (!DebugEvaluate::Evaluate(isolate, shared_info, context, receiver, source, if (!DebugEvaluate::Evaluate(isolate, shared_info, context, context_extension,
throw_on_side_effect) source, throw_on_side_effect)
.ToHandle(&result)) { .ToHandle(&result)) {
return {}; return {};
} }
......
...@@ -340,6 +340,12 @@ class DebugInfoImpl { ...@@ -340,6 +340,12 @@ class DebugInfoImpl {
debug_break_fp); debug_break_fp);
} }
const WasmFunction& GetFunctionAtAddress(Address pc) {
FrameInspectionScope scope(this, pc);
auto* module = native_module_->module();
return module->functions[scope.code->index()];
}
Handle<JSObject> GetLocalScopeObject(Isolate* isolate, Address pc, Address fp, Handle<JSObject> GetLocalScopeObject(Isolate* isolate, Address pc, Address fp,
Address debug_break_fp) { Address debug_break_fp) {
FrameInspectionScope scope(this, pc); FrameInspectionScope scope(this, pc);
...@@ -909,6 +915,10 @@ WasmValue DebugInfo::GetStackValue(int index, Address pc, Address fp, ...@@ -909,6 +915,10 @@ WasmValue DebugInfo::GetStackValue(int index, Address pc, Address fp,
return impl_->GetStackValue(index, pc, fp, debug_break_fp); return impl_->GetStackValue(index, pc, fp, debug_break_fp);
} }
const wasm::WasmFunction& DebugInfo::GetFunctionAtAddress(Address pc) {
return impl_->GetFunctionAtAddress(pc);
}
Handle<JSObject> DebugInfo::GetLocalScopeObject(Isolate* isolate, Address pc, Handle<JSObject> DebugInfo::GetLocalScopeObject(Isolate* isolate, Address pc,
Address fp, Address fp,
Address debug_break_fp) { Address debug_break_fp) {
......
...@@ -34,6 +34,7 @@ class NativeModule; ...@@ -34,6 +34,7 @@ class NativeModule;
class WasmCode; class WasmCode;
class WireBytesRef; class WireBytesRef;
class WasmValue; class WasmValue;
struct WasmFunction;
// Side table storing information used to inspect Liftoff frames at runtime. // Side table storing information used to inspect Liftoff frames at runtime.
// This table is only created on demand for debugging, so it is not optimized // This table is only created on demand for debugging, so it is not optimized
...@@ -153,6 +154,9 @@ class V8_EXPORT_PRIVATE DebugInfo { ...@@ -153,6 +154,9 @@ class V8_EXPORT_PRIVATE DebugInfo {
WasmValue GetLocalValue(int local, Address pc, Address fp, WasmValue GetLocalValue(int local, Address pc, Address fp,
Address debug_break_fp); Address debug_break_fp);
int GetStackDepth(Address pc); int GetStackDepth(Address pc);
const wasm::WasmFunction& GetFunctionAtAddress(Address pc);
WasmValue GetStackValue(int index, Address pc, Address fp, WasmValue GetStackValue(int index, Address pc, Address fp,
Address debug_break_fp); Address debug_break_fp);
......
This diff is collapsed.
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class JSProxy;
class WasmFrame;
namespace wasm { namespace wasm {
class StreamingDecoder; class StreamingDecoder;
...@@ -19,6 +21,8 @@ class WasmJs { ...@@ -19,6 +21,8 @@ class WasmJs {
public: public:
V8_EXPORT_PRIVATE static void Install(Isolate* isolate, V8_EXPORT_PRIVATE static void Install(Isolate* isolate,
bool exposed_on_global_object); bool exposed_on_global_object);
V8_EXPORT_PRIVATE static Handle<JSProxy> GetJSDebugProxy(WasmFrame* frame);
}; };
} // namespace internal } // namespace internal
......
...@@ -525,15 +525,37 @@ WASM_COMPILED_EXEC_TEST(WasmDebugEvaluate_JavaScript) { ...@@ -525,15 +525,37 @@ WASM_COMPILED_EXEC_TEST(WasmDebugEvaluate_JavaScript) {
uint16_t index = 0; uint16_t index = 0;
runner.builder().AddIndirectFunctionTable(&index, 1); runner.builder().AddIndirectFunctionTable(&index, 1);
TestCode<int> code( TestCode<int64_t> code(
&runner, &runner,
{WASM_SET_GLOBAL(0, WASM_I32V_2('B')), {WASM_SET_GLOBAL(0, WASM_I32V_2('B')),
WASM_SET_LOCAL(0, WASM_I32V_2('A')), WASM_RETURN1(WASM_GET_LOCAL(0))}, WASM_SET_LOCAL(0, WASM_I64V_2('A')), WASM_RETURN1(WASM_GET_LOCAL(0))},
{ValueType::kI32}); {ValueType::kI64});
code.BreakOnReturn(&runner); code.BreakOnReturn(&runner);
Isolate* isolate = runner.main_isolate(); Isolate* isolate = runner.main_isolate();
Handle<String> snippet = V8String(isolate, "213"); Handle<String> snippet =
V8String(isolate,
"JSON.stringify(["
//"$global0, "
//"$table0, "
"$var0, "
//"$main, "
//"$memory0, "
//"globals[0], "
//"tables[0], "
"locals[0], "
//"functions[0], "
//"memories[0], "
//"memories, "
//"tables, "
//"stack, "
//"imports, "
//"exports, "
//"globals, "
"locals, "
//"functions, "
"], (k, v) => k === 'at' || typeof v === 'undefined' || typeof "
"v === 'object' ? v : v.toString())");
WasmJSBreakHandler break_handler(isolate, snippet); WasmJSBreakHandler break_handler(isolate, snippet);
CHECK(!code.Run(&runner).is_null()); CHECK(!code.Run(&runner).is_null());
...@@ -541,7 +563,10 @@ WASM_COMPILED_EXEC_TEST(WasmDebugEvaluate_JavaScript) { ...@@ -541,7 +563,10 @@ WASM_COMPILED_EXEC_TEST(WasmDebugEvaluate_JavaScript) {
WasmJSBreakHandler::EvaluationResult result = WasmJSBreakHandler::EvaluationResult result =
break_handler.result().ToChecked(); break_handler.result().ToChecked();
CHECK_WITH_MSG(result.error.IsNothing(), result.error.ToChecked().c_str()); CHECK_WITH_MSG(result.error.IsNothing(), result.error.ToChecked().c_str());
CHECK_EQ(result.result.ToChecked(), "213"); CHECK_EQ(result.result.ToChecked(), "[\"65\",\"65\",{}]");
//"[\"66\",{},\"65\",\"function 0() { [native code] }\",{},"
//"\"66\",{},\"65\",\"function 0() { [native code] }\",{},"
//"{},{},{\"0\":\"65\"},{},{},{},{},{}]");
} }
} // namespace } // namespace
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment