Commit 1bf5ac8c authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Extract WasmVal to own header and rename to WasmValue

This allows to reuse the class e.g. in the baseline compiler.

R=titzer@chromium.org

Change-Id: I7251af16e8c74f267834a9cefb676edf3c9f3a07
Reviewed-on: https://chromium-review.googlesource.com/570020Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46735}
parent 10c6fb56
......@@ -2011,6 +2011,7 @@ v8_source_set("v8_base") {
"src/wasm/wasm-result.h",
"src/wasm/wasm-text.cc",
"src/wasm/wasm-text.h",
"src/wasm/wasm-value.h",
"src/zone/accounting-allocator.cc",
"src/zone/accounting-allocator.h",
"src/zone/zone-allocator.h",
......
......@@ -1452,6 +1452,7 @@
'wasm/wasm-result.h',
'wasm/wasm-text.cc',
'wasm/wasm-text.h',
'wasm/wasm-value.h',
'zone/accounting-allocator.cc',
'zone/accounting-allocator.h',
'zone/zone-segment.cc',
......
......@@ -40,8 +40,8 @@ Handle<String> PrintFToOneByteString(Isolate* isolate, const char* format,
: isolate->factory()->NewStringFromOneByte(name).ToHandleChecked();
}
Handle<Object> WasmValToValueObject(Isolate* isolate, WasmVal value) {
switch (value.type) {
Handle<Object> WasmValueToValueObject(Isolate* isolate, WasmValue value) {
switch (value.type()) {
case kWasmI32:
if (Smi::IsValid(value.to<int32_t>()))
return handle(Smi::FromInt(value.to<int32_t>()), isolate);
......@@ -197,14 +197,14 @@ class InterpreterHandle {
FunctionSig* sig = module()->functions[func_index].sig;
DCHECK_GE(kMaxInt, sig->parameter_count());
int num_params = static_cast<int>(sig->parameter_count());
ScopedVector<WasmVal> wasm_args(num_params);
ScopedVector<WasmValue> wasm_args(num_params);
uint8_t* arg_buf_ptr = arg_buffer;
for (int i = 0; i < num_params; ++i) {
uint32_t param_size = 1 << ElementSizeLog2Of(sig->GetParam(i));
#define CASE_ARG_TYPE(type, ctype) \
case type: \
DCHECK_EQ(param_size, sizeof(ctype)); \
wasm_args[i] = WasmVal(ReadUnalignedValue<ctype>(arg_buf_ptr)); \
#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)
......@@ -264,7 +264,7 @@ class InterpreterHandle {
// TODO(wasm): Handle multi-value returns.
DCHECK_EQ(1, kV8MaxWasmFunctionReturns);
if (sig->return_count()) {
WasmVal ret_val = thread->GetReturnValue(0);
WasmValue ret_val = thread->GetReturnValue(0);
#define CASE_RET_TYPE(type, ctype) \
case type: \
DCHECK_EQ(1 << ElementSizeLog2Of(sig->GetReturn(0)), sizeof(ctype)); \
......@@ -498,8 +498,8 @@ class InterpreterHandle {
const char* label = i < num_params ? "arg#%d" : "local#%d";
name = PrintFToOneByteString<true>(isolate_, label, i);
}
WasmVal value = frame->GetLocalValue(i);
Handle<Object> value_obj = WasmValToValueObject(isolate_, value);
WasmValue value = frame->GetLocalValue(i);
Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
JSObject::SetOwnPropertyIgnoreAttributes(
locals_obj, name.ToHandleChecked(), value_obj, NONE)
.Assert();
......@@ -519,8 +519,8 @@ class InterpreterHandle {
stack_obj, NONE)
.Assert();
for (int i = 0; i < stack_count; ++i) {
WasmVal value = frame->GetStackValue(i);
Handle<Object> value_obj = WasmValToValueObject(isolate_, value);
WasmValue value = frame->GetStackValue(i);
Handle<Object> value_obj = WasmValueToValueObject(isolate_, value);
JSObject::SetOwnElementIgnoreAttributes(
stack_obj, static_cast<uint32_t>(i), value_obj, NONE)
.Assert();
......
This diff is collapsed.
......@@ -6,6 +6,7 @@
#define V8_WASM_INTERPRETER_H_
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-value.h"
#include "src/zone/zone-containers.h"
namespace v8 {
......@@ -43,66 +44,6 @@ struct ControlTransferEntry {
using ControlTransferMap = ZoneMap<pc_t, ControlTransferEntry>;
// Macro for defining union members.
#define FOREACH_UNION_MEMBER(V) \
V(i32, kWasmI32, int32_t) \
V(u32, kWasmI32, uint32_t) \
V(i64, kWasmI64, int64_t) \
V(u64, kWasmI64, uint64_t) \
V(f32, kWasmF32, float) \
V(f64, kWasmF64, double)
// Representation of values within the interpreter.
struct WasmVal {
ValueType type;
union {
#define DECLARE_FIELD(field, localtype, ctype) ctype field;
FOREACH_UNION_MEMBER(DECLARE_FIELD)
#undef DECLARE_FIELD
} val;
WasmVal() : type(kWasmStmt) {}
#define DECLARE_CONSTRUCTOR(field, localtype, ctype) \
explicit WasmVal(ctype v) : type(localtype) { val.field = v; }
FOREACH_UNION_MEMBER(DECLARE_CONSTRUCTOR)
#undef DECLARE_CONSTRUCTOR
bool operator==(const WasmVal& other) const {
if (type != other.type) return false;
#define CHECK_VAL_EQ(field, localtype, ctype) \
if (type == localtype) { \
return val.field == other.val.field; \
}
FOREACH_UNION_MEMBER(CHECK_VAL_EQ)
#undef CHECK_VAL_EQ
UNREACHABLE();
}
template <typename T>
inline T to() const {
UNREACHABLE();
}
template <typename T>
inline T to_unchecked() const {
UNREACHABLE();
}
};
#define DECLARE_CASTS(field, localtype, ctype) \
template <> \
inline ctype WasmVal::to_unchecked() const { \
return val.field; \
} \
template <> \
inline ctype WasmVal::to() const { \
CHECK_EQ(localtype, type); \
return val.field; \
}
FOREACH_UNION_MEMBER(DECLARE_CASTS)
#undef DECLARE_CAST
// Representation of frames within the interpreter.
//
// Layout of a frame:
......@@ -126,8 +67,8 @@ class InterpretedFrame {
int GetParameterCount() const;
int GetLocalCount() const;
int GetStackHeight() const;
WasmVal GetLocalValue(int index) const;
WasmVal GetStackValue(int index) const;
WasmValue GetLocalValue(int index) const;
WasmValue GetStackValue(int index) const;
private:
friend class WasmInterpreter;
......@@ -182,7 +123,7 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
// Execution control.
State state();
void InitFrame(const WasmFunction* function, WasmVal* args);
void InitFrame(const WasmFunction* function, WasmValue* args);
// Pass -1 as num_steps to run till completion, pause or breakpoint.
State Run(int num_steps = -1);
State Step() { return Run(1); }
......@@ -198,7 +139,7 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
int GetFrameCount();
// The InterpretedFrame is only valid as long as the Thread is paused.
std::unique_ptr<InterpretedFrame> GetFrame(int index);
WasmVal GetReturnValue(int index = 0);
WasmValue GetReturnValue(int index = 0);
TrapReason GetTrapReason();
// Returns true if the thread executed an instruction which may produce
......@@ -259,8 +200,8 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
// Memory access.
//==========================================================================
size_t GetMemorySize();
WasmVal ReadMemory(size_t offset);
void WriteMemory(size_t offset, WasmVal val);
WasmValue ReadMemory(size_t offset);
void WriteMemory(size_t offset, WasmValue val);
// Update the memory region, e.g. after external GrowMemory.
void UpdateMemory(byte* mem_start, uint32_t mem_size);
......
// Copyright 2017 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.
#ifndef V8_WASM_VALUE_H_
#define V8_WASM_VALUE_H_
#include "src/wasm/wasm-opcodes.h"
#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
namespace wasm {
// Macro for defining WasmValue union members.
#define FOREACH_WASMVAL_UNION_MEMBER(V) \
V(i32, kWasmI32, int32_t) \
V(u32, kWasmI32, uint32_t) \
V(i64, kWasmI64, int64_t) \
V(u64, kWasmI64, uint64_t) \
V(f32, kWasmF32, float) \
V(f64, kWasmF64, double)
// A wasm value with type information.
class WasmValue {
public:
WasmValue() : type_(kWasmStmt) {}
#define DEFINE_TYPE_SPECIFIC_METHODS(field, localtype, ctype) \
explicit WasmValue(ctype v) : type_(localtype) { value_.field = v; } \
ctype to_##field() const { \
DCHECK_EQ(localtype, type_); \
return value_.field; \
}
FOREACH_WASMVAL_UNION_MEMBER(DEFINE_TYPE_SPECIFIC_METHODS)
#undef DEFINE_TYPE_SPECIFIC_METHODS
ValueType type() const { return type_; }
bool operator==(const WasmValue& other) const {
if (type_ != other.type_) return false;
#define CHECK_VALUE_EQ(field, localtype, ctype) \
if (type_ == localtype) { \
return value_.field == other.value_.field; \
}
FOREACH_WASMVAL_UNION_MEMBER(CHECK_VALUE_EQ)
#undef CHECK_VALUE_EQ
UNREACHABLE();
}
template <typename T>
inline T to() const {
static_assert(sizeof(T) == -1, "Do only use this method with valid types");
}
template <typename T>
inline T to_unchecked() const {
static_assert(sizeof(T) == -1, "Do only use this method with valid types");
}
private:
ValueType type_;
union {
#define DECLARE_FIELD(field, localtype, ctype) ctype field;
FOREACH_WASMVAL_UNION_MEMBER(DECLARE_FIELD)
#undef DECLARE_FIELD
} value_;
};
#define DECLARE_CAST(field, localtype, ctype) \
template <> \
inline ctype WasmValue::to_unchecked() const { \
return value_.field; \
} \
template <> \
inline ctype WasmValue::to() const { \
return to_##field(); \
}
FOREACH_WASMVAL_UNION_MEMBER(DECLARE_CAST)
#undef DECLARE_CAST
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_VALUE_H_
......@@ -196,7 +196,7 @@ TEST(Breakpoint_I32Add) {
FOR_UINT32_INPUTS(a) {
for (uint32_t b = 11; b < 3000000000u; b += 1000000000u) {
thread->Reset();
WasmVal args[] = {WasmVal(*a), WasmVal(b)};
WasmValue args[] = {WasmValue(*a), WasmValue(b)};
thread->InitFrame(r.function(), args);
for (int i = 0; i < kNumBreakpoints; i++) {
......@@ -231,7 +231,7 @@ TEST(Step_I32Mul) {
FOR_UINT32_INPUTS(a) {
for (uint32_t b = 33; b < 3000000000u; b += 1000000000u) {
thread->Reset();
WasmVal args[] = {WasmVal(*a), WasmVal(b)};
WasmValue args[] = {WasmValue(*a), WasmValue(b)};
thread->InitFrame(r.function(), args);
// Run instructions one by one.
......@@ -273,7 +273,7 @@ TEST(Breakpoint_I32And_disable) {
interpreter->SetBreakpoint(r.function(), kLocalsDeclSize + offsets[0],
do_break);
thread->Reset();
WasmVal args[] = {WasmVal(*a), WasmVal(b)};
WasmValue args[] = {WasmValue(*a), WasmValue(b)};
thread->InitFrame(r.function(), args);
if (do_break) {
......
......@@ -160,7 +160,7 @@ void SetBreakpoint(WasmRunnerBase& runner, int function_index, int byte_offset,
// Wrapper with operator<<.
struct WasmValWrapper {
WasmVal val;
WasmValue val;
bool operator==(const WasmValWrapper& other) const {
return val == other.val;
......@@ -170,7 +170,7 @@ struct WasmValWrapper {
// Only needed in debug builds. Avoid unused warning otherwise.
#ifdef DEBUG
std::ostream& operator<<(std::ostream& out, const WasmValWrapper& wrapper) {
switch (wrapper.val.type) {
switch (wrapper.val.type()) {
case kWasmI32:
out << "i32: " << wrapper.val.to<int32_t>();
break;
......@@ -193,8 +193,8 @@ std::ostream& operator<<(std::ostream& out, const WasmValWrapper& wrapper) {
class CollectValuesBreakHandler : public debug::DebugDelegate {
public:
struct BreakpointValues {
std::vector<WasmVal> locals;
std::vector<WasmVal> stack;
std::vector<WasmValue> locals;
std::vector<WasmValue> stack;
};
explicit CollectValuesBreakHandler(
......@@ -244,21 +244,21 @@ class CollectValuesBreakHandler : public debug::DebugDelegate {
}
};
// Special template to explicitly cast to WasmVal.
// Special template to explicitly cast to WasmValue.
template <typename Arg>
WasmVal MakeWasmVal(Arg arg) {
return WasmVal(arg);
WasmValue MakeWasmVal(Arg arg) {
return WasmValue(arg);
}
// Translate long to i64 (ambiguous otherwise).
template <>
WasmVal MakeWasmVal(long arg) { // NOLINT: allow long parameter
return WasmVal(static_cast<int64_t>(arg));
WasmValue MakeWasmVal(long arg) { // NOLINT: allow long parameter
return WasmValue(static_cast<int64_t>(arg));
}
template <typename... Args>
std::vector<WasmVal> wasmVec(Args... args) {
std::array<WasmVal, sizeof...(args)> arr{{MakeWasmVal(args)...}};
return std::vector<WasmVal>{arr.begin(), arr.end()};
std::vector<WasmValue> wasmVec(Args... args) {
std::array<WasmValue, sizeof...(args)> arr{{MakeWasmVal(args)...}};
return std::vector<WasmValue>{arr.begin(), arr.end()};
}
} // namespace
......
......@@ -797,12 +797,12 @@ class WasmRunner : public WasmRunnerBase {
ReturnType CallInterpreter(ParamTypes... p) {
WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
thread->Reset();
std::array<WasmVal, sizeof...(p)> args{{WasmVal(p)...}};
std::array<WasmValue, sizeof...(p)> args{{WasmValue(p)...}};
thread->InitFrame(function(), args.data());
WasmInterpreter::HeapObjectsScope heap_objects_scope(
interpreter(), module().instance_object());
if (thread->Run() == WasmInterpreter::FINISHED) {
WasmVal val = thread->GetReturnValue();
WasmValue val = thread->GetReturnValue();
possible_nondeterminism_ |= thread->PossibleNondeterminism();
return val.to<ReturnType>();
} else if (thread->state() == WasmInterpreter::TRAPPED) {
......
......@@ -84,7 +84,7 @@ int32_t CompileAndRunAsmWasmModule(Isolate* isolate, const byte* module_start,
int32_t InterpretWasmModule(Isolate* isolate,
Handle<WasmInstanceObject> instance,
ErrorThrower* thrower, int32_t function_index,
WasmVal* args, bool* possible_nondeterminism) {
WasmValue* args, bool* possible_nondeterminism) {
// Don't execute more than 16k steps.
constexpr int kMaxNumSteps = 16 * 1024;
......@@ -101,7 +101,7 @@ int32_t InterpretWasmModule(Isolate* isolate,
*possible_nondeterminism = thread->PossibleNondeterminism();
if (interpreter_result == WasmInterpreter::FINISHED) {
WasmVal val = thread->GetReturnValue();
WasmValue val = thread->GetReturnValue();
return val.to<int32_t>();
} else if (thread->state() == WasmInterpreter::TRAPPED) {
return 0xdeadbeef;
......
......@@ -45,7 +45,7 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
int32_t InterpretWasmModule(Isolate* isolate,
Handle<WasmInstanceObject> instance,
ErrorThrower* thrower, int32_t function_index,
WasmVal* args, bool* possible_nondeterminism);
WasmValue* args, bool* possible_nondeterminism);
// Runs the module instance with arguments.
int32_t RunWasmModuleForTesting(Isolate* isolate, Handle<JSObject> instance,
......
......@@ -39,27 +39,28 @@ class WasmCallFuzzer : public WasmExecutionFuzzer {
}
static void add_argument(
v8::internal::Isolate* isolate, ValueType type, WasmVal* interpreter_args,
v8::internal::Isolate* isolate, ValueType type,
WasmValue* interpreter_args,
v8::internal::Handle<v8::internal::Object>* compiler_args, int* argc,
const uint8_t** data, size_t* size, bool* ok) {
if (!(*ok)) return;
switch (type) {
case kWasmF32: {
float value = read_value<float>(data, size, ok);
interpreter_args[*argc] = WasmVal(value);
interpreter_args[*argc] = WasmValue(value);
compiler_args[*argc] =
isolate->factory()->NewNumber(static_cast<double>(value));
break;
}
case kWasmF64: {
double value = read_value<double>(data, size, ok);
interpreter_args[*argc] = WasmVal(value);
interpreter_args[*argc] = WasmValue(value);
compiler_args[*argc] = isolate->factory()->NewNumber(value);
break;
}
case kWasmI32: {
int32_t value = read_value<int32_t>(data, size, ok);
interpreter_args[*argc] = WasmVal(value);
interpreter_args[*argc] = WasmValue(value);
compiler_args[*argc] =
isolate->factory()->NewNumber(static_cast<double>(value));
break;
......@@ -73,7 +74,7 @@ class WasmCallFuzzer : public WasmExecutionFuzzer {
virtual bool GenerateModule(
Isolate* isolate, Zone* zone, const uint8_t* data, size_t size,
ZoneBuffer& buffer, int32_t& num_args,
std::unique_ptr<WasmVal[]>& interpreter_args,
std::unique_ptr<WasmValue[]>& interpreter_args,
std::unique_ptr<Handle<Object>[]>& compiler_args) override {
bool ok = true;
uint8_t num_functions =
......@@ -81,7 +82,7 @@ class WasmCallFuzzer : public WasmExecutionFuzzer {
ValueType types[] = {kWasmF32, kWasmF64, kWasmI32, kWasmI64};
interpreter_args.reset(new WasmVal[3]);
interpreter_args.reset(new WasmValue[3]);
compiler_args.reset(new Handle<Object>[3]);
WasmModuleBuilder builder(zone);
......
......@@ -21,7 +21,7 @@ class WasmCodeFuzzer : public WasmExecutionFuzzer {
virtual bool GenerateModule(
Isolate* isolate, Zone* zone, const uint8_t* data, size_t size,
ZoneBuffer& buffer, int32_t& num_args,
std::unique_ptr<WasmVal[]>& interpreter_args,
std::unique_ptr<WasmValue[]>& interpreter_args,
std::unique_ptr<Handle<Object>[]>& compiler_args) override {
TestSignatures sigs;
WasmModuleBuilder builder(zone);
......@@ -33,7 +33,8 @@ class WasmCodeFuzzer : public WasmExecutionFuzzer {
builder.WriteTo(buffer);
num_args = 3;
interpreter_args.reset(new WasmVal[3]{WasmVal(1), WasmVal(2), WasmVal(3)});
interpreter_args.reset(
new WasmValue[3]{WasmValue(1), WasmValue(2), WasmValue(3)});
compiler_args.reset(new Handle<Object>[3]{
handle(Smi::FromInt(1), isolate), handle(Smi::FromInt(2), isolate),
......
......@@ -302,7 +302,7 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
virtual bool GenerateModule(
Isolate* isolate, Zone* zone, const uint8_t* data, size_t size,
ZoneBuffer& buffer, int32_t& num_args,
std::unique_ptr<WasmVal[]>& interpreter_args,
std::unique_ptr<WasmValue[]>& interpreter_args,
std::unique_ptr<Handle<Object>[]>& compiler_args) override {
TestSignatures sigs;
......@@ -321,7 +321,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
builder.WriteTo(buffer);
num_args = 3;
interpreter_args.reset(new WasmVal[3]{WasmVal(1), WasmVal(2), WasmVal(3)});
interpreter_args.reset(
new WasmValue[3]{WasmValue(1), WasmValue(2), WasmValue(3)});
compiler_args.reset(new Handle<Object>[3]{
handle(Smi::FromInt(1), isolate), handle(Smi::FromInt(1), isolate),
......
......@@ -111,7 +111,7 @@ int WasmExecutionFuzzer::FuzzWasmModule(
ZoneBuffer buffer(&zone);
int32_t num_args = 0;
std::unique_ptr<WasmVal[]> interpreter_args;
std::unique_ptr<WasmValue[]> interpreter_args;
std::unique_ptr<Handle<Object>[]> compiler_args;
if (!GenerateModule(i_isolate, &zone, data, size, buffer, num_args,
interpreter_args, compiler_args)) {
......
......@@ -29,7 +29,7 @@ class WasmExecutionFuzzer {
virtual bool GenerateModule(
Isolate* isolate, Zone* zone, const uint8_t* data, size_t size,
ZoneBuffer& buffer, int32_t& num_args,
std::unique_ptr<WasmVal[]>& interpreter_args,
std::unique_ptr<WasmValue[]>& interpreter_args,
std::unique_ptr<Handle<Object>[]>& compiler_args) = 0;
};
......
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