Commit 4a20fe38 authored by Philip Pfaffe's avatar Philip Pfaffe Committed by Commit Bot

Enable evaluateOnCallFrame for wasm frames

This is the first step to support debug evaluate on wasm call frames.
This CL enables calling evaluateOnCallFrame when a wasm frame is
selected, which before always returned undefined. The CL mirrors global
evaluation, and actually enabling inspecting the wasm frame will be part
of a second change.

Bug: chromium:1127914
Change-Id: If0ad0be7c402d85ab2a8e95376398f4f4ef94948
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2436338
Commit-Queue: Philip Pfaffe <pfaffe@chromium.org>
Reviewed-by: 's avatarSimon Zünd <szuend@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70198}
parent 8d389204
...@@ -17,10 +17,25 @@ ...@@ -17,10 +17,25 @@
#include "src/interpreter/bytecodes.h" #include "src/interpreter/bytecodes.h"
#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"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace {
static MaybeHandle<SharedFunctionInfo> GetFunctionInfo(Isolate* isolate,
Handle<String> source,
REPLMode repl_mode) {
Compiler::ScriptDetails script_details(isolate->factory()->empty_string());
script_details.repl_mode = repl_mode;
ScriptOriginOptions origin_options(false, true);
return Compiler::GetSharedFunctionInfoForScript(
isolate, source, script_details, origin_options, nullptr, nullptr,
ScriptCompiler::kNoCompileOptions, ScriptCompiler::kNoCacheNoReason,
NOT_NATIVES_CODE);
}
} // namespace
MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate, MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
Handle<String> source, Handle<String> source,
debug::EvaluateGlobalMode mode, debug::EvaluateGlobalMode mode,
...@@ -32,19 +47,12 @@ MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate, ...@@ -32,19 +47,12 @@ MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
mode == mode ==
debug::EvaluateGlobalMode::kDisableBreaksAndThrowOnSideEffect); debug::EvaluateGlobalMode::kDisableBreaksAndThrowOnSideEffect);
Handle<Context> context = isolate->native_context();
Compiler::ScriptDetails script_details(isolate->factory()->empty_string());
script_details.repl_mode = repl_mode;
ScriptOriginOptions origin_options(false, true);
MaybeHandle<SharedFunctionInfo> maybe_function_info =
Compiler::GetSharedFunctionInfoForScript(
isolate, source, script_details, origin_options, nullptr, nullptr,
ScriptCompiler::kNoCompileOptions, ScriptCompiler::kNoCacheNoReason,
NOT_NATIVES_CODE);
Handle<SharedFunctionInfo> shared_info; Handle<SharedFunctionInfo> shared_info;
if (!maybe_function_info.ToHandle(&shared_info)) return MaybeHandle<Object>(); if (!GetFunctionInfo(isolate, source, repl_mode).ToHandle(&shared_info)) {
return MaybeHandle<Object>();
}
Handle<Context> context = isolate->native_context();
Handle<JSFunction> fun = Handle<JSFunction> fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(shared_info, isolate->factory()->NewFunctionFromSharedFunctionInfo(shared_info,
context); context);
...@@ -91,6 +99,34 @@ MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate, ...@@ -91,6 +99,34 @@ MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate,
return maybe_result; return maybe_result;
} }
V8_EXPORT MaybeHandle<Object> DebugEvaluate::WebAssembly(
Handle<WasmInstanceObject> instance, StackFrameId frame_id,
Handle<String> source, bool throw_on_side_effect) {
Isolate* isolate = instance->GetIsolate();
StackTraceFrameIterator it(isolate, frame_id);
if (!it.is_wasm()) return isolate->factory()->undefined_value();
DisableBreak disable_break_scope(isolate->debug(), /*disable=*/true);
Handle<SharedFunctionInfo> shared_info;
if (!GetFunctionInfo(isolate, source, REPLMode::kNo).ToHandle(&shared_info)) {
return {};
}
Handle<Context> context = isolate->native_context();
Handle<JSObject> receiver(context->global_proxy(), isolate);
Handle<Object> result;
if (!DebugEvaluate::Evaluate(isolate, shared_info, context, receiver, source,
throw_on_side_effect)
.ToHandle(&result)) {
return {};
}
return result;
}
MaybeHandle<Object> DebugEvaluate::WithTopmostArguments(Isolate* isolate, MaybeHandle<Object> DebugEvaluate::WithTopmostArguments(Isolate* isolate,
Handle<String> source) { Handle<String> source) {
// Handle the processing of break. // Handle the processing of break.
......
...@@ -37,6 +37,10 @@ class DebugEvaluate : public AllStatic { ...@@ -37,6 +37,10 @@ class DebugEvaluate : public AllStatic {
Handle<String> source, Handle<String> source,
bool throw_on_side_effect); bool throw_on_side_effect);
static V8_EXPORT MaybeHandle<Object> WebAssembly(
Handle<WasmInstanceObject> instance, StackFrameId frame_id,
Handle<String> source, bool throw_on_side_effect);
// This is used for break-at-entry for builtins and API functions. // This is used for break-at-entry for builtins and API functions.
// Evaluate a piece of JavaScript in the native context, but with the // Evaluate a piece of JavaScript in the native context, but with the
// materialized arguments object and receiver of the current call. // materialized arguments object and receiver of the current call.
...@@ -102,7 +106,6 @@ class DebugEvaluate : public AllStatic { ...@@ -102,7 +106,6 @@ class DebugEvaluate : public AllStatic {
bool throw_on_side_effect); bool throw_on_side_effect);
}; };
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -184,11 +184,25 @@ v8::MaybeLocal<v8::Value> DebugStackTraceIterator::Evaluate( ...@@ -184,11 +184,25 @@ v8::MaybeLocal<v8::Value> DebugStackTraceIterator::Evaluate(
v8::Local<v8::String> source, bool throw_on_side_effect) { v8::Local<v8::String> source, bool throw_on_side_effect) {
DCHECK(!Done()); DCHECK(!Done());
Handle<Object> value; Handle<Object> value;
i::SafeForInterruptsScope safe_for_interrupt_scope(isolate_); i::SafeForInterruptsScope safe_for_interrupt_scope(isolate_);
if (!DebugEvaluate::Local(isolate_, iterator_.frame()->id(), bool success = false;
inlined_frame_index_, Utils::OpenHandle(*source), if (iterator_.is_wasm()) {
throw_on_side_effect) FrameSummary summary = FrameSummary::Get(iterator_.frame(), 0);
.ToHandle(&value)) { const FrameSummary::WasmFrameSummary& wasmSummary = summary.AsWasm();
Handle<WasmInstanceObject> instance = wasmSummary.wasm_instance();
success = DebugEvaluate::WebAssembly(instance, iterator_.frame()->id(),
Utils::OpenHandle(*source),
throw_on_side_effect)
.ToHandle(&value);
} else {
success = DebugEvaluate::Local(
isolate_, iterator_.frame()->id(), inlined_frame_index_,
Utils::OpenHandle(*source), throw_on_side_effect)
.ToHandle(&value);
}
if (!success) {
isolate_->OptionalRescheduleException(false); isolate_->OptionalRescheduleException(false);
return v8::MaybeLocal<v8::Value>(); return v8::MaybeLocal<v8::Value>();
} }
......
...@@ -38,6 +38,10 @@ namespace v8 { ...@@ -38,6 +38,10 @@ namespace v8 {
namespace internal { namespace internal {
namespace wasm { namespace wasm {
static Handle<String> V8String(Isolate* isolate, const char* str) {
return isolate->factory()->NewStringFromAsciiChecked(str);
}
namespace { namespace {
template <typename... FunctionArgsT> template <typename... FunctionArgsT>
class TestCode { class TestCode {
...@@ -246,6 +250,71 @@ class WasmBreakHandler : public debug::DebugDelegate { ...@@ -246,6 +250,71 @@ class WasmBreakHandler : public debug::DebugDelegate {
} }
}; };
class WasmJSBreakHandler : public debug::DebugDelegate {
public:
struct EvaluationResult {
Maybe<std::string> result = Nothing<std::string>();
Maybe<std::string> error = Nothing<std::string>();
};
WasmJSBreakHandler(Isolate* isolate, Handle<String> snippet)
: isolate_(isolate),
snippet_(snippet),
result_(Nothing<EvaluationResult>()) {
v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_), this);
}
~WasmJSBreakHandler() override {
v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_),
nullptr);
}
const Maybe<EvaluationResult>& result() const { return result_; }
private:
Isolate* isolate_;
Handle<String> snippet_;
Maybe<EvaluationResult> result_;
Maybe<std::string> GetPendingExceptionAsString() const {
if (!isolate_->has_pending_exception()) return Nothing<std::string>();
Handle<Object> exception(isolate_->pending_exception(), isolate_);
isolate_->clear_pending_exception();
Handle<String> exception_string;
if (!Object::ToString(isolate_, exception).ToHandle(&exception_string)) {
return Just<std::string>("");
}
return Just<std::string>(exception_string->ToCString().get());
}
Maybe<std::string> GetResultAsString(MaybeHandle<Object> result) const {
Handle<Object> just_result;
if (!result.ToHandle(&just_result)) return Nothing<std::string>();
MaybeHandle<String> maybe_string = Object::ToString(isolate_, just_result);
Handle<String> just_string;
if (!maybe_string.ToHandle(&just_string)) return Nothing<std::string>();
return Just<std::string>(just_string->ToCString().get());
}
void BreakProgramRequested(v8::Local<v8::Context> paused_context,
const std::vector<int>&) override {
StackTraceFrameIterator frame_it(isolate_);
WasmFrame* frame = WasmFrame::cast(frame_it.frame());
Handle<WasmInstanceObject> instance{frame->wasm_instance(), isolate_};
MaybeHandle<Object> result_handle = DebugEvaluate::WebAssembly(
instance, frame_it.frame()->id(), snippet_, false);
Maybe<std::string> error_message = GetPendingExceptionAsString();
Maybe<std::string> result_message = GetResultAsString(result_handle);
isolate_->clear_pending_exception();
result_ = Just<EvaluationResult>({result_message, error_message});
}
};
WASM_COMPILED_EXEC_TEST(WasmDebugEvaluate_CompileFailed) { WASM_COMPILED_EXEC_TEST(WasmDebugEvaluate_CompileFailed) {
WasmRunner<int> runner(execution_tier); WasmRunner<int> runner(execution_tier);
...@@ -449,6 +518,32 @@ WASM_COMPILED_EXEC_TEST(WasmDebugEvaluate_Operands) { ...@@ -449,6 +518,32 @@ WASM_COMPILED_EXEC_TEST(WasmDebugEvaluate_Operands) {
CHECK_EQ(result.result.ToChecked(), "45"); CHECK_EQ(result.result.ToChecked(), "45");
} }
WASM_COMPILED_EXEC_TEST(WasmDebugEvaluate_JavaScript) {
WasmRunner<int> runner(execution_tier);
runner.builder().AddGlobal<int32_t>();
runner.builder().AddMemoryElems<int32_t>(64);
uint16_t index = 0;
runner.builder().AddIndirectFunctionTable(&index, 1);
TestCode<int> code(
&runner,
{WASM_SET_GLOBAL(0, WASM_I32V_2('B')),
WASM_SET_LOCAL(0, WASM_I32V_2('A')), WASM_RETURN1(WASM_GET_LOCAL(0))},
{ValueType::kI32});
code.BreakOnReturn(&runner);
Isolate* isolate = runner.main_isolate();
Handle<String> snippet = V8String(isolate, "213");
WasmJSBreakHandler break_handler(isolate, snippet);
CHECK(!code.Run(&runner).is_null());
WasmJSBreakHandler::EvaluationResult result =
break_handler.result().ToChecked();
CHECK_WITH_MSG(result.error.IsNothing(), result.error.ToChecked().c_str());
CHECK_EQ(result.result.ToChecked(), "213");
}
} // namespace } // namespace
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
......
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