Commit 0bed5887 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Support reference types on interpreter entry.

This adds preliminary support for references types as argument or return
values to functions that are redirected to the interpreter. The current
interpreter entry stub remains unchanged, using one buffer area that is
hidden from the GC. The corresponding {Runtime_WasmRunInterpreter} now
correctly boxes/un-boxes reference types into handles. This switch to a
handlified representation happens before any method that potentially
triggers a GC is called.

R=clemensh@chromium.org
TEST=mjsunit/wasm/exceptions-anyref-interpreter
BUG=v8:8091,v8:7581

Change-Id: I41c766ed5ac877042d5964e72f3fd7df390c4e98
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1557147
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60684}
parent f8e3b1d6
......@@ -20,6 +20,7 @@
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-value.h"
namespace v8 {
namespace internal {
......@@ -193,6 +194,47 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
frame_pointer = it.frame()->fp();
}
// Reserve buffers for argument and return values.
DCHECK_GE(instance->module()->functions.size(), func_index);
wasm::FunctionSig* sig = instance->module()->functions[func_index].sig;
DCHECK_GE(kMaxInt, sig->parameter_count());
int num_params = static_cast<int>(sig->parameter_count());
ScopedVector<wasm::WasmValue> wasm_args(num_params);
DCHECK_GE(kMaxInt, sig->return_count());
int num_returns = static_cast<int>(sig->return_count());
ScopedVector<wasm::WasmValue> wasm_rets(num_returns);
// Copy the arguments for the {arg_buffer} into a vector of {WasmValue}. This
// also boxes reference types into handles, which needs to happen before any
// methods that could trigger a GC are being called.
Address arg_buf_ptr = arg_buffer;
for (int i = 0; i < num_params; ++i) {
#define CASE_ARG_TYPE(type, ctype) \
case wasm::type: \
DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetParam(i)), \
sizeof(ctype)); \
wasm_args[i] = wasm::WasmValue(ReadUnalignedValue<ctype>(arg_buf_ptr)); \
arg_buf_ptr += sizeof(ctype); \
break;
switch (sig->GetParam(i)) {
CASE_ARG_TYPE(kWasmI32, uint32_t)
CASE_ARG_TYPE(kWasmI64, uint64_t)
CASE_ARG_TYPE(kWasmF32, float)
CASE_ARG_TYPE(kWasmF64, double)
#undef CASE_ARG_TYPE
case wasm::kWasmAnyRef: {
DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetParam(i)),
kSystemPointerSize);
Handle<Object> ref(ReadUnalignedValue<Object>(arg_buf_ptr), isolate);
wasm_args[i] = wasm::WasmValue(ref);
arg_buf_ptr += kSystemPointerSize;
break;
}
default:
UNREACHABLE();
}
}
// Set the current isolate's context.
DCHECK(isolate->context().is_null());
isolate->set_context(instance->native_context());
......@@ -203,12 +245,43 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
Handle<WasmDebugInfo> debug_info =
WasmInstanceObject::GetOrCreateDebugInfo(instance);
bool success = WasmDebugInfo::RunInterpreter(
isolate, debug_info, frame_pointer, func_index, arg_buffer);
isolate, debug_info, frame_pointer, func_index, wasm_args, wasm_rets);
// Early return on failure.
if (!success) {
DCHECK(isolate->has_pending_exception());
return ReadOnlyRoots(isolate).exception();
}
// Copy return values from the vector of {WasmValue} into {arg_buffer}. This
// also un-boxes reference types from handles into raw pointers.
arg_buf_ptr = arg_buffer;
for (int i = 0; i < num_returns; ++i) {
#define CASE_RET_TYPE(type, ctype) \
case wasm::type: \
DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetReturn(i)), \
sizeof(ctype)); \
WriteUnalignedValue<ctype>(arg_buf_ptr, wasm_rets[i].to<ctype>()); \
arg_buf_ptr += sizeof(ctype); \
break;
switch (sig->GetReturn(i)) {
CASE_RET_TYPE(kWasmI32, uint32_t)
CASE_RET_TYPE(kWasmI64, uint64_t)
CASE_RET_TYPE(kWasmF32, float)
CASE_RET_TYPE(kWasmF64, double)
#undef CASE_RET_TYPE
case wasm::kWasmAnyRef: {
DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetReturn(i)),
kSystemPointerSize);
WriteUnalignedValue<Object>(arg_buf_ptr, *wasm_rets[i].to_anyref());
arg_buf_ptr += kSystemPointerSize;
break;
}
default:
UNREACHABLE();
}
}
return ReadOnlyRoots(isolate).undefined_value();
}
......
......@@ -213,6 +213,8 @@ class V8_EXPORT_PRIVATE ValueTypes {
return 8;
case kWasmS128:
return 16;
case kWasmAnyRef:
return kSystemPointerSize;
default:
UNREACHABLE();
}
......
......@@ -167,38 +167,20 @@ class InterpreterHandle {
// was not handled inside this activation. In the latter case, a pending
// exception will have been set on the isolate.
bool Execute(Handle<WasmInstanceObject> instance_object,
Address frame_pointer, uint32_t func_index, Address arg_buffer) {
Address frame_pointer, uint32_t func_index,
Vector<WasmValue> argument_values,
Vector<WasmValue> return_values) {
DCHECK_GE(module()->functions.size(), func_index);
FunctionSig* sig = module()->functions[func_index].sig;
DCHECK_GE(kMaxInt, sig->parameter_count());
int num_params = static_cast<int>(sig->parameter_count());
ScopedVector<WasmValue> wasm_args(num_params);
Address arg_buf_ptr = arg_buffer;
for (int i = 0; i < num_params; ++i) {
uint32_t param_size = static_cast<uint32_t>(
ValueTypes::ElementSizeInBytes(sig->GetParam(i)));
#define CASE_ARG_TYPE(type, ctype) \
case type: \
DCHECK_EQ(param_size, sizeof(ctype)); \
wasm_args[i] = WasmValue(ReadUnalignedValue<ctype>(arg_buf_ptr)); \
break;
switch (sig->GetParam(i)) {
CASE_ARG_TYPE(kWasmI32, uint32_t)
CASE_ARG_TYPE(kWasmI64, uint64_t)
CASE_ARG_TYPE(kWasmF32, float)
CASE_ARG_TYPE(kWasmF64, double)
#undef CASE_ARG_TYPE
default:
UNREACHABLE();
}
arg_buf_ptr += param_size;
}
DCHECK_EQ(sig->parameter_count(), argument_values.size());
DCHECK_EQ(sig->return_count(), return_values.size());
uint32_t activation_id = StartActivation(frame_pointer);
WasmCodeRefScope code_ref_scope;
WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
thread->InitFrame(&module()->functions[func_index], wasm_args.start());
thread->InitFrame(&module()->functions[func_index],
argument_values.start());
bool finished = false;
while (!finished) {
// TODO(clemensh): Add occasional StackChecks.
......@@ -238,27 +220,12 @@ class InterpreterHandle {
}
}
// Copy back the return value
// Copy back the return value.
DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count());
// TODO(wasm): Handle multi-value returns.
DCHECK_EQ(1, kV8MaxWasmFunctionReturns);
if (sig->return_count()) {
WasmValue ret_val = thread->GetReturnValue(0);
#define CASE_RET_TYPE(type, ctype) \
case type: \
DCHECK_EQ(ValueTypes::ElementSizeInBytes(sig->GetReturn(0)), \
sizeof(ctype)); \
WriteUnalignedValue<ctype>(arg_buffer, ret_val.to<ctype>()); \
break;
switch (sig->GetReturn(0)) {
CASE_RET_TYPE(kWasmI32, uint32_t)
CASE_RET_TYPE(kWasmI64, uint64_t)
CASE_RET_TYPE(kWasmF32, float)
CASE_RET_TYPE(kWasmF64, double)
#undef CASE_RET_TYPE
default:
UNREACHABLE();
}
return_values[0] = thread->GetReturnValue(0);
}
FinishActivation(frame_pointer, activation_id);
......@@ -605,12 +572,14 @@ void WasmDebugInfo::PrepareStep(StepAction step_action) {
bool WasmDebugInfo::RunInterpreter(Isolate* isolate,
Handle<WasmDebugInfo> debug_info,
Address frame_pointer, int func_index,
Address arg_buffer) {
Vector<wasm::WasmValue> argument_values,
Vector<wasm::WasmValue> return_values) {
DCHECK_LE(0, func_index);
auto* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
return handle->Execute(instance, frame_pointer,
static_cast<uint32_t>(func_index), arg_buffer);
static_cast<uint32_t>(func_index), argument_values,
return_values);
}
std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack(
......
......@@ -30,6 +30,7 @@ struct WasmException;
struct WasmFeatures;
class WasmInterpreter;
struct WasmModule;
class WasmValue;
class WireBytesRef;
} // namespace wasm
......@@ -763,15 +764,16 @@ class WasmDebugInfo : public Struct {
void PrepareStep(StepAction);
// Execute the specified function in the interpreter. Read arguments from
// arg_buffer.
// Execute the specified function in the interpreter. Read arguments from the
// {argument_values} vector and write to {return_values} on regular exit.
// The frame_pointer will be used to identify the new activation of the
// interpreter for unwinding and frame inspection.
// Returns true if exited regularly, false if a trap occurred. In the latter
// case, a pending exception will have been set on the isolate.
static bool RunInterpreter(Isolate* isolate, Handle<WasmDebugInfo>,
Address frame_pointer, int func_index,
Address arg_buffer);
Vector<wasm::WasmValue> argument_values,
Vector<wasm::WasmValue> return_values);
// Get the stack of the wasm interpreter as pairs of <function index, byte
// offset>. The list is ordered bottom-to-top, i.e. caller before callee.
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-eh --experimental-wasm-anyref --allow-natives-syntax
// Flags: --wasm-interpret-all
// This is just a wrapper for existing exception handling test cases that runs
// with the --wasm-interpret-all flag added. If we ever decide to add a test
// variant for this, then we can remove this file.
load("test/mjsunit/wasm/exceptions-anyref.js");
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