Commit e4bb7ff9 authored by titzer's avatar titzer Committed by Commit bot

[wasm] Implement an interpreter for WASM.

This interpreter directly decodes and executes WASM binary code for
the purpose of supporting low-level debugging. It is not currently
integrated into the main WASM implementation.

R=ahaas@chromium.org,clemensh@chromium.org,rossberg@chromium.org,binji@chromium.org
BUG=

Review-Url: https://codereview.chromium.org/1972153002
Cr-Commit-Position: refs/heads/master@{#36497}
parent 39d08198
...@@ -1492,6 +1492,8 @@ v8_source_set("v8_base") { ...@@ -1492,6 +1492,8 @@ v8_source_set("v8_base") {
"src/wasm/wasm-external-refs.h", "src/wasm/wasm-external-refs.h",
"src/wasm/wasm-function-name-table.cc", "src/wasm/wasm-function-name-table.cc",
"src/wasm/wasm-function-name-table.h", "src/wasm/wasm-function-name-table.h",
"src/wasm/wasm-interpreter.cc",
"src/wasm/wasm-interpreter.h",
"src/wasm/wasm-js.cc", "src/wasm/wasm-js.cc",
"src/wasm/wasm-js.h", "src/wasm/wasm-js.h",
"src/wasm/wasm-macro-gen.h", "src/wasm/wasm-macro-gen.h",
......
...@@ -480,6 +480,7 @@ DEFINE_BOOL(trace_wasm_encoder, false, "trace encoding of wasm code") ...@@ -480,6 +480,7 @@ DEFINE_BOOL(trace_wasm_encoder, false, "trace encoding of wasm code")
DEFINE_BOOL(trace_wasm_decoder, false, "trace decoding of wasm code") DEFINE_BOOL(trace_wasm_decoder, false, "trace decoding of wasm code")
DEFINE_BOOL(trace_wasm_decode_time, false, "trace decoding time of wasm code") DEFINE_BOOL(trace_wasm_decode_time, false, "trace decoding time of wasm code")
DEFINE_BOOL(trace_wasm_compiler, false, "trace compiling of wasm code") DEFINE_BOOL(trace_wasm_compiler, false, "trace compiling of wasm code")
DEFINE_BOOL(trace_wasm_interpreter, false, "trace interpretation of wasm code")
DEFINE_INT(trace_wasm_ast_start, 0, DEFINE_INT(trace_wasm_ast_start, 0,
"start function for WASM AST trace (inclusive)") "start function for WASM AST trace (inclusive)")
DEFINE_INT(trace_wasm_ast_end, 0, "end function for WASM AST trace (exclusive)") DEFINE_INT(trace_wasm_ast_end, 0, "end function for WASM AST trace (exclusive)")
......
...@@ -1170,6 +1170,8 @@ ...@@ -1170,6 +1170,8 @@
'wasm/wasm-macro-gen.h', 'wasm/wasm-macro-gen.h',
'wasm/wasm-module.cc', 'wasm/wasm-module.cc',
'wasm/wasm-module.h', 'wasm/wasm-module.h',
'wasm/wasm-interpreter.cc',
'wasm/wasm-interpreter.h',
'wasm/wasm-opcodes.cc', 'wasm/wasm-opcodes.cc',
'wasm/wasm-opcodes.h', 'wasm/wasm-opcodes.h',
'wasm/wasm-result.cc', 'wasm/wasm-result.cc',
......
// Copyright 2016 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.
#include "src/wasm/wasm-interpreter.h"
#include "src/wasm/ast-decoder.h"
#include "src/wasm/decoder.h"
#include "src/wasm/wasm-external-refs.h"
#include "src/wasm/wasm-module.h"
#include "src/base/accounting-allocator.h"
#include "src/zone-containers.h"
namespace v8 {
namespace internal {
namespace wasm {
#if DEBUG
#define TRACE(...) \
do { \
if (FLAG_trace_wasm_interpreter) PrintF(__VA_ARGS__); \
} while (false)
#else
#define TRACE(...)
#endif
#define FOREACH_INTERNAL_OPCODE(V) V(Breakpoint, 0xFF)
#define FOREACH_SIMPLE_BINOP(V) \
V(I32Add, uint32_t, +) \
V(I32Sub, uint32_t, -) \
V(I32Mul, uint32_t, *) \
V(I32And, uint32_t, &) \
V(I32Ior, uint32_t, |) \
V(I32Xor, uint32_t, ^) \
V(I32Eq, uint32_t, ==) \
V(I32Ne, uint32_t, !=) \
V(I32LtU, uint32_t, <) \
V(I32LeU, uint32_t, <=) \
V(I32GtU, uint32_t, >) \
V(I32GeU, uint32_t, >=) \
V(I32LtS, int32_t, <) \
V(I32LeS, int32_t, <=) \
V(I32GtS, int32_t, >) \
V(I32GeS, int32_t, >=) \
V(I64Add, uint64_t, +) \
V(I64Sub, uint64_t, -) \
V(I64Mul, uint64_t, *) \
V(I64And, uint64_t, &) \
V(I64Ior, uint64_t, |) \
V(I64Xor, uint64_t, ^) \
V(I64Eq, uint64_t, ==) \
V(I64Ne, uint64_t, !=) \
V(I64LtU, uint64_t, <) \
V(I64LeU, uint64_t, <=) \
V(I64GtU, uint64_t, >) \
V(I64GeU, uint64_t, >=) \
V(I64LtS, int64_t, <) \
V(I64LeS, int64_t, <=) \
V(I64GtS, int64_t, >) \
V(I64GeS, int64_t, >=) \
V(F32Add, float, +) \
V(F32Sub, float, -) \
V(F32Mul, float, *) \
V(F32Div, float, /) \
V(F32Eq, float, ==) \
V(F32Ne, float, !=) \
V(F32Lt, float, <) \
V(F32Le, float, <=) \
V(F32Gt, float, >) \
V(F32Ge, float, >=) \
V(F64Add, double, +) \
V(F64Sub, double, -) \
V(F64Mul, double, *) \
V(F64Div, double, /) \
V(F64Eq, double, ==) \
V(F64Ne, double, !=) \
V(F64Lt, double, <) \
V(F64Le, double, <=) \
V(F64Gt, double, >) \
V(F64Ge, double, >=)
#define FOREACH_OTHER_BINOP(V) \
V(I32DivS, int32_t) \
V(I32DivU, uint32_t) \
V(I32RemS, int32_t) \
V(I32RemU, uint32_t) \
V(I32Shl, uint32_t) \
V(I32ShrU, uint32_t) \
V(I32ShrS, int32_t) \
V(I64DivS, int64_t) \
V(I64DivU, uint64_t) \
V(I64RemS, int64_t) \
V(I64RemU, uint64_t) \
V(I64Shl, uint64_t) \
V(I64ShrU, uint64_t) \
V(I64ShrS, int64_t) \
V(I32Ror, int32_t) \
V(I32Rol, int32_t) \
V(I64Ror, int64_t) \
V(I64Rol, int64_t) \
V(F32Min, float) \
V(F32Max, float) \
V(F32CopySign, float) \
V(F64Min, double) \
V(F64Max, double) \
V(F64CopySign, double) \
V(I32AsmjsDivS, int32_t) \
V(I32AsmjsDivU, uint32_t) \
V(I32AsmjsRemS, int32_t) \
V(I32AsmjsRemU, uint32_t)
#define FOREACH_OTHER_UNOP(V) \
V(I32Clz, uint32_t) \
V(I32Ctz, uint32_t) \
V(I32Popcnt, uint32_t) \
V(I32Eqz, uint32_t) \
V(I64Clz, uint64_t) \
V(I64Ctz, uint64_t) \
V(I64Popcnt, uint64_t) \
V(I64Eqz, uint64_t) \
V(F32Abs, float) \
V(F32Neg, float) \
V(F32Ceil, float) \
V(F32Floor, float) \
V(F32Trunc, float) \
V(F32NearestInt, float) \
V(F32Sqrt, float) \
V(F64Abs, double) \
V(F64Neg, double) \
V(F64Ceil, double) \
V(F64Floor, double) \
V(F64Trunc, double) \
V(F64NearestInt, double) \
V(F64Sqrt, double) \
V(I32SConvertF32, float) \
V(I32SConvertF64, double) \
V(I32UConvertF32, float) \
V(I32UConvertF64, double) \
V(I32ConvertI64, int64_t) \
V(I64SConvertF32, float) \
V(I64SConvertF64, double) \
V(I64UConvertF32, float) \
V(I64UConvertF64, double) \
V(I64SConvertI32, int32_t) \
V(I64UConvertI32, uint32_t) \
V(F32SConvertI32, int32_t) \
V(F32UConvertI32, uint32_t) \
V(F32SConvertI64, int64_t) \
V(F32UConvertI64, uint64_t) \
V(F32ConvertF64, double) \
V(F32ReinterpretI32, int32_t) \
V(F64SConvertI32, int32_t) \
V(F64UConvertI32, uint32_t) \
V(F64SConvertI64, int64_t) \
V(F64UConvertI64, uint64_t) \
V(F64ConvertF32, float) \
V(F64ReinterpretI64, int64_t) \
V(I32ReinterpretF32, float) \
V(I64ReinterpretF64, double) \
V(I32AsmjsSConvertF32, float) \
V(I32AsmjsUConvertF32, float) \
V(I32AsmjsSConvertF64, double) \
V(I32AsmjsUConvertF64, double)
static inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) {
if (b == 0) {
*trap = kTrapDivByZero;
return 0;
}
if (b == -1 && a == std::numeric_limits<int32_t>::min()) {
*trap = kTrapDivUnrepresentable;
return 0;
}
return a / b;
}
static inline uint32_t ExecuteI32DivU(uint32_t a, uint32_t b,
TrapReason* trap) {
if (b == 0) {
*trap = kTrapDivByZero;
return 0;
}
return a / b;
}
static inline int32_t ExecuteI32RemS(int32_t a, int32_t b, TrapReason* trap) {
if (b == 0) {
*trap = kTrapRemByZero;
return 0;
}
if (b == -1) return 0;
return a % b;
}
static inline uint32_t ExecuteI32RemU(uint32_t a, uint32_t b,
TrapReason* trap) {
if (b == 0) {
*trap = kTrapRemByZero;
return 0;
}
return a % b;
}
static inline uint32_t ExecuteI32Shl(uint32_t a, uint32_t b, TrapReason* trap) {
return a << (b & 0x1f);
}
static inline uint32_t ExecuteI32ShrU(uint32_t a, uint32_t b,
TrapReason* trap) {
return a >> (b & 0x1f);
}
static inline int32_t ExecuteI32ShrS(int32_t a, int32_t b, TrapReason* trap) {
return a >> (b & 0x1f);
}
static inline int64_t ExecuteI64DivS(int64_t a, int64_t b, TrapReason* trap) {
if (b == 0) {
*trap = kTrapDivByZero;
return 0;
}
if (b == -1 && a == std::numeric_limits<int64_t>::min()) {
*trap = kTrapDivUnrepresentable;
return 0;
}
return a / b;
}
static inline uint64_t ExecuteI64DivU(uint64_t a, uint64_t b,
TrapReason* trap) {
if (b == 0) {
*trap = kTrapDivByZero;
return 0;
}
return a / b;
}
static inline int64_t ExecuteI64RemS(int64_t a, int64_t b, TrapReason* trap) {
if (b == 0) {
*trap = kTrapRemByZero;
return 0;
}
if (b == -1) return 0;
return a % b;
}
static inline uint64_t ExecuteI64RemU(uint64_t a, uint64_t b,
TrapReason* trap) {
if (b == 0) {
*trap = kTrapRemByZero;
return 0;
}
return a % b;
}
static inline uint64_t ExecuteI64Shl(uint64_t a, uint64_t b, TrapReason* trap) {
return a << (b & 0x3f);
}
static inline uint64_t ExecuteI64ShrU(uint64_t a, uint64_t b,
TrapReason* trap) {
return a >> (b & 0x3f);
}
static inline int64_t ExecuteI64ShrS(int64_t a, int64_t b, TrapReason* trap) {
return a >> (b & 0x3f);
}
static inline uint32_t ExecuteI32Ror(uint32_t a, uint32_t b, TrapReason* trap) {
uint32_t shift = (b & 0x1f);
return (a >> shift) | (a << (32 - shift));
}
static inline uint32_t ExecuteI32Rol(uint32_t a, uint32_t b, TrapReason* trap) {
uint32_t shift = (b & 0x1f);
return (a << shift) | (a >> (32 - shift));
}
static inline uint64_t ExecuteI64Ror(uint64_t a, uint64_t b, TrapReason* trap) {
uint32_t shift = (b & 0x3f);
return (a >> shift) | (a << (64 - shift));
}
static inline uint64_t ExecuteI64Rol(uint64_t a, uint64_t b, TrapReason* trap) {
uint32_t shift = (b & 0x3f);
return (a << shift) | (a >> (64 - shift));
}
static float quiet(float a) {
static const uint32_t kSignalingBit = 1 << 22;
uint32_t q = bit_cast<uint32_t>(std::numeric_limits<float>::quiet_NaN());
if ((q & kSignalingBit) != 0) {
// On some machines, the signaling bit set indicates it's a quiet NaN.
return bit_cast<float>(bit_cast<uint32_t>(a) | kSignalingBit);
} else {
// On others, the signaling bit set indicates it's a signaling NaN.
return bit_cast<float>(bit_cast<uint32_t>(a) & ~kSignalingBit);
}
}
static double quiet(double a) {
static const uint64_t kSignalingBit = 1ULL << 51;
uint64_t q = bit_cast<uint64_t>(std::numeric_limits<double>::quiet_NaN());
if ((q & kSignalingBit) != 0) {
// On some machines, the signaling bit set indicates it's a quiet NaN.
return bit_cast<double>(bit_cast<uint64_t>(a) | kSignalingBit);
} else {
// On others, the signaling bit set indicates it's a signaling NaN.
return bit_cast<double>(bit_cast<uint64_t>(a) & ~kSignalingBit);
}
}
static inline float ExecuteF32Min(float a, float b, TrapReason* trap) {
if (std::isnan(a)) return quiet(a);
if (std::isnan(b)) return quiet(b);
return std::min(a, b);
}
static inline float ExecuteF32Max(float a, float b, TrapReason* trap) {
if (std::isnan(a)) return quiet(a);
if (std::isnan(b)) return quiet(b);
return std::max(a, b);
}
static inline float ExecuteF32CopySign(float a, float b, TrapReason* trap) {
return copysignf(a, b);
}
static inline double ExecuteF64Min(double a, double b, TrapReason* trap) {
if (std::isnan(a)) return quiet(a);
if (std::isnan(b)) return quiet(b);
return std::min(a, b);
}
static inline double ExecuteF64Max(double a, double b, TrapReason* trap) {
if (std::isnan(a)) return quiet(a);
if (std::isnan(b)) return quiet(b);
return std::max(a, b);
}
static inline double ExecuteF64CopySign(double a, double b, TrapReason* trap) {
return copysign(a, b);
}
static inline int32_t ExecuteI32AsmjsDivS(int32_t a, int32_t b,
TrapReason* trap) {
if (b == 0) return 0;
if (b == -1 && a == std::numeric_limits<int32_t>::min()) {
return std::numeric_limits<int32_t>::min();
}
return a / b;
}
static inline uint32_t ExecuteI32AsmjsDivU(uint32_t a, uint32_t b,
TrapReason* trap) {
if (b == 0) return 0;
return a / b;
}
static inline int32_t ExecuteI32AsmjsRemS(int32_t a, int32_t b,
TrapReason* trap) {
if (b == 0) return 0;
if (b == -1) return 0;
return a % b;
}
static inline uint32_t ExecuteI32AsmjsRemU(uint32_t a, uint32_t b,
TrapReason* trap) {
if (b == 0) return 0;
return a % b;
}
static inline int32_t ExecuteI32AsmjsSConvertF32(float a, TrapReason* trap) {
return DoubleToInt32(a);
}
static inline uint32_t ExecuteI32AsmjsUConvertF32(float a, TrapReason* trap) {
return DoubleToUint32(a);
}
static inline int32_t ExecuteI32AsmjsSConvertF64(double a, TrapReason* trap) {
return DoubleToInt32(a);
}
static inline uint32_t ExecuteI32AsmjsUConvertF64(double a, TrapReason* trap) {
return DoubleToUint32(a);
}
static int32_t ExecuteI32Clz(uint32_t val, TrapReason* trap) {
return base::bits::CountLeadingZeros32(val);
}
static uint32_t ExecuteI32Ctz(uint32_t val, TrapReason* trap) {
return base::bits::CountTrailingZeros32(val);
}
static uint32_t ExecuteI32Popcnt(uint32_t val, TrapReason* trap) {
return word32_popcnt_wrapper(&val);
}
static inline uint32_t ExecuteI32Eqz(uint32_t val, TrapReason* trap) {
return val == 0 ? 1 : 0;
}
static int64_t ExecuteI64Clz(uint64_t val, TrapReason* trap) {
return base::bits::CountLeadingZeros64(val);
}
static inline uint64_t ExecuteI64Ctz(uint64_t val, TrapReason* trap) {
return base::bits::CountTrailingZeros64(val);
}
static inline int64_t ExecuteI64Popcnt(uint64_t val, TrapReason* trap) {
return word64_popcnt_wrapper(&val);
}
static inline int32_t ExecuteI64Eqz(uint64_t val, TrapReason* trap) {
return val == 0 ? 1 : 0;
}
static inline float ExecuteF32Abs(float a, TrapReason* trap) {
return bit_cast<float>(bit_cast<uint32_t>(a) & 0x7fffffff);
}
static inline float ExecuteF32Neg(float a, TrapReason* trap) {
return bit_cast<float>(bit_cast<uint32_t>(a) ^ 0x80000000);
}
static inline float ExecuteF32Ceil(float a, TrapReason* trap) {
return ceilf(a);
}
static inline float ExecuteF32Floor(float a, TrapReason* trap) {
return floorf(a);
}
static inline float ExecuteF32Trunc(float a, TrapReason* trap) {
return truncf(a);
}
static inline float ExecuteF32NearestInt(float a, TrapReason* trap) {
return nearbyintf(a);
}
static inline float ExecuteF32Sqrt(float a, TrapReason* trap) {
return sqrtf(a);
}
static inline double ExecuteF64Abs(double a, TrapReason* trap) {
return bit_cast<double>(bit_cast<uint64_t>(a) & 0x7fffffffffffffff);
}
static inline double ExecuteF64Neg(double a, TrapReason* trap) {
return bit_cast<double>(bit_cast<uint64_t>(a) ^ 0x8000000000000000);
}
static inline double ExecuteF64Ceil(double a, TrapReason* trap) {
return ceil(a);
}
static inline double ExecuteF64Floor(double a, TrapReason* trap) {
return floor(a);
}
static inline double ExecuteF64Trunc(double a, TrapReason* trap) {
return trunc(a);
}
static inline double ExecuteF64NearestInt(double a, TrapReason* trap) {
return nearbyint(a);
}
static inline double ExecuteF64Sqrt(double a, TrapReason* trap) {
return sqrt(a);
}
static int32_t ExecuteI32SConvertF32(float a, TrapReason* trap) {
if (a < static_cast<float>(INT32_MAX) && a >= static_cast<float>(INT32_MIN)) {
return static_cast<int32_t>(a);
}
*trap = kTrapFloatUnrepresentable;
return 0;
}
static int32_t ExecuteI32SConvertF64(double a, TrapReason* trap) {
if (a < (static_cast<double>(INT32_MAX) + 1.0) &&
a > (static_cast<double>(INT32_MIN) - 1.0)) {
return static_cast<int32_t>(a);
}
*trap = kTrapFloatUnrepresentable;
return 0;
}
static uint32_t ExecuteI32UConvertF32(float a, TrapReason* trap) {
if (a < (static_cast<float>(UINT32_MAX) + 1.0) && a > -1) {
return static_cast<uint32_t>(a);
}
*trap = kTrapFloatUnrepresentable;
return 0;
}
static uint32_t ExecuteI32UConvertF64(double a, TrapReason* trap) {
if (a < (static_cast<float>(UINT32_MAX) + 1.0) && a > -1) {
return static_cast<uint32_t>(a);
}
*trap = kTrapFloatUnrepresentable;
return 0;
}
static inline uint32_t ExecuteI32ConvertI64(int64_t a, TrapReason* trap) {
return static_cast<uint32_t>(a & 0xFFFFFFFF);
}
static int64_t ExecuteI64SConvertF32(float a, TrapReason* trap) {
int64_t output;
if (!float32_to_int64_wrapper(&a, &output)) {
*trap = kTrapFloatUnrepresentable;
}
return output;
}
static int64_t ExecuteI64SConvertF64(double a, TrapReason* trap) {
int64_t output;
if (!float64_to_int64_wrapper(&a, &output)) {
*trap = kTrapFloatUnrepresentable;
}
return output;
}
static uint64_t ExecuteI64UConvertF32(float a, TrapReason* trap) {
uint64_t output;
if (!float32_to_uint64_wrapper(&a, &output)) {
*trap = kTrapFloatUnrepresentable;
}
return output;
}
static uint64_t ExecuteI64UConvertF64(double a, TrapReason* trap) {
uint64_t output;
if (!float64_to_uint64_wrapper(&a, &output)) {
*trap = kTrapFloatUnrepresentable;
}
return output;
}
static inline int64_t ExecuteI64SConvertI32(int32_t a, TrapReason* trap) {
return static_cast<int64_t>(a);
}
static inline int64_t ExecuteI64UConvertI32(uint32_t a, TrapReason* trap) {
return static_cast<uint64_t>(a);
}
static inline float ExecuteF32SConvertI32(int32_t a, TrapReason* trap) {
return static_cast<float>(a);
}
static inline float ExecuteF32UConvertI32(uint32_t a, TrapReason* trap) {
return static_cast<float>(a);
}
static inline float ExecuteF32SConvertI64(int64_t a, TrapReason* trap) {
float output;
int64_to_float32_wrapper(&a, &output);
return output;
}
static inline float ExecuteF32UConvertI64(uint64_t a, TrapReason* trap) {
float output;
uint64_to_float32_wrapper(&a, &output);
return output;
}
static inline float ExecuteF32ConvertF64(double a, TrapReason* trap) {
return static_cast<float>(a);
}
static inline float ExecuteF32ReinterpretI32(int32_t a, TrapReason* trap) {
return bit_cast<float>(a);
}
static inline double ExecuteF64SConvertI32(int32_t a, TrapReason* trap) {
return static_cast<double>(a);
}
static inline double ExecuteF64UConvertI32(uint32_t a, TrapReason* trap) {
return static_cast<double>(a);
}
static inline double ExecuteF64SConvertI64(int64_t a, TrapReason* trap) {
double output;
int64_to_float64_wrapper(&a, &output);
return output;
}
static inline double ExecuteF64UConvertI64(uint64_t a, TrapReason* trap) {
double output;
uint64_to_float64_wrapper(&a, &output);
return output;
}
static inline double ExecuteF64ConvertF32(float a, TrapReason* trap) {
return static_cast<double>(a);
}
static inline double ExecuteF64ReinterpretI64(int64_t a, TrapReason* trap) {
return bit_cast<double>(a);
}
static inline int32_t ExecuteI32ReinterpretF32(float a, TrapReason* trap) {
return bit_cast<int32_t>(a);
}
static inline int64_t ExecuteI64ReinterpretF64(double a, TrapReason* trap) {
return bit_cast<int64_t>(a);
}
enum InternalOpcode {
#define DECL_INTERNAL_ENUM(name, value) kInternal##name = value,
FOREACH_INTERNAL_OPCODE(DECL_INTERNAL_ENUM)
#undef DECL_INTERNAL_ENUM
};
static const char* OpcodeName(uint32_t val) {
switch (val) {
#define DECL_INTERNAL_CASE(name, value) \
case kInternal##name: \
return "Internal" #name;
FOREACH_INTERNAL_OPCODE(DECL_INTERNAL_CASE)
#undef DECL_INTERNAL_CASE
}
return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(val));
}
static const int kRunSteps = 1000;
// A helper class to compute the control transfers for each bytecode offset.
// Control transfers allow Br, BrIf, BrTable, If, Else, and End bytecodes to
// be directly executed without the need to dynamically track blocks.
class ControlTransfers : public ZoneObject {
public:
ControlTransferMap map_;
ControlTransfers(Zone* zone, size_t locals_encoded_size, const byte* start,
const byte* end)
: map_(zone) {
// A control reference including from PC, from value depth, and whether
// a value is explicitly passed (e.g. br/br_if/br_table with value).
struct CRef {
const byte* pc;
sp_t value_depth;
bool explicit_value;
};
// Represents a control flow label.
struct CLabel : public ZoneObject {
const byte* target;
size_t value_depth;
ZoneVector<CRef> refs;
CLabel(Zone* zone, size_t v)
: target(nullptr), value_depth(v), refs(zone) {}
// Bind this label to the given PC.
void Bind(ControlTransferMap* map, const byte* start, const byte* pc,
bool expect_value) {
DCHECK_NULL(target);
target = pc;
for (auto from : refs) {
auto pcdiff = static_cast<pcdiff_t>(target - from.pc);
auto spdiff = static_cast<spdiff_t>(from.value_depth - value_depth);
ControlTransfer::StackAction action = ControlTransfer::kNoAction;
if (expect_value && !from.explicit_value) {
action = spdiff == 0 ? ControlTransfer::kPushVoid
: ControlTransfer::kPopAndRepush;
}
pc_t offset = static_cast<size_t>(from.pc - start);
(*map)[offset] = {pcdiff, spdiff, action};
}
}
// Reference this label from the given location.
void Ref(ControlTransferMap* map, const byte* start, CRef from) {
DCHECK_GE(from.value_depth, value_depth);
if (target) {
auto pcdiff = static_cast<pcdiff_t>(target - from.pc);
auto spdiff = static_cast<spdiff_t>(from.value_depth - value_depth);
pc_t offset = static_cast<size_t>(from.pc - start);
(*map)[offset] = {pcdiff, spdiff, ControlTransfer::kNoAction};
} else {
refs.push_back(from);
}
}
};
// An entry in the control stack.
struct Control {
const byte* pc;
CLabel* end_label;
CLabel* else_label;
void Ref(ControlTransferMap* map, const byte* start, const byte* from_pc,
size_t from_value_depth, bool explicit_value) {
end_label->Ref(map, start, {from_pc, from_value_depth, explicit_value});
}
};
// Compute the ControlTransfer map.
// This works by maintaining a stack of control constructs similar to the
// AST decoder. The {control_stack} allows matching {br,br_if,br_table}
// bytecodes with their target, as well as determining whether the current
// bytecodes are within the true or false block of an else.
// The value stack depth is tracked as {value_depth} and is needed to
// determine how many values to pop off the stack for explicit and
// implicit control flow.
std::vector<Control> control_stack;
size_t value_depth = 0;
Decoder decoder(start, end); // for reading operands.
const byte* pc = start + locals_encoded_size;
while (pc < end) {
WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
TRACE("@%td: control %s (depth = %zu)\n", (pc - start),
WasmOpcodes::OpcodeName(opcode), value_depth);
switch (opcode) {
case kExprBlock: {
TRACE("control @%td $%zu: Block\n", (pc - start), value_depth);
CLabel* label = new (zone) CLabel(zone, value_depth);
control_stack.push_back({pc, label, nullptr});
break;
}
case kExprLoop: {
TRACE("control @%td $%zu: Loop\n", (pc - start), value_depth);
CLabel* label1 = new (zone) CLabel(zone, value_depth);
CLabel* label2 = new (zone) CLabel(zone, value_depth);
control_stack.push_back({pc, label1, nullptr});
control_stack.push_back({pc, label2, nullptr});
label2->Bind(&map_, start, pc, false);
break;
}
case kExprIf: {
TRACE("control @%td $%zu: If\n", (pc - start), value_depth);
value_depth--;
CLabel* end_label = new (zone) CLabel(zone, value_depth);
CLabel* else_label = new (zone) CLabel(zone, value_depth);
control_stack.push_back({pc, end_label, else_label});
else_label->Ref(&map_, start, {pc, value_depth, false});
break;
}
case kExprElse: {
Control* c = &control_stack.back();
TRACE("control @%td $%zu: Else\n", (pc - start), value_depth);
c->end_label->Ref(&map_, start, {pc, value_depth, false});
value_depth = c->end_label->value_depth;
DCHECK_NOT_NULL(c->else_label);
c->else_label->Bind(&map_, start, pc + 1, false);
c->else_label = nullptr;
break;
}
case kExprEnd: {
Control* c = &control_stack.back();
TRACE("control @%td $%zu: End\n", (pc - start), value_depth);
if (c->end_label->target) {
// only loops have bound labels.
DCHECK_EQ(kExprLoop, *c->pc);
control_stack.pop_back();
c = &control_stack.back();
}
if (c->else_label) c->else_label->Bind(&map_, start, pc + 1, true);
c->end_label->Ref(&map_, start, {pc, value_depth, false});
c->end_label->Bind(&map_, start, pc + 1, true);
value_depth = c->end_label->value_depth + 1;
control_stack.pop_back();
break;
}
case kExprBr: {
BreakDepthOperand operand(&decoder, pc);
TRACE("control @%td $%zu: Br[arity=%u, depth=%u]\n", (pc - start),
value_depth, operand.arity, operand.depth);
value_depth -= operand.arity;
control_stack[control_stack.size() - operand.depth - 1].Ref(
&map_, start, pc, value_depth, operand.arity > 0);
value_depth++;
break;
}
case kExprBrIf: {
BreakDepthOperand operand(&decoder, pc);
TRACE("control @%td $%zu: BrIf[arity=%u, depth=%u]\n", (pc - start),
value_depth, operand.arity, operand.depth);
value_depth -= (operand.arity + 1);
control_stack[control_stack.size() - operand.depth - 1].Ref(
&map_, start, pc, value_depth, operand.arity > 0);
value_depth++;
break;
}
case kExprBrTable: {
BranchTableOperand operand(&decoder, pc);
TRACE("control @%td $%zu: BrTable[arity=%u count=%u]\n", (pc - start),
value_depth, operand.arity, operand.table_count);
value_depth -= (operand.arity + 1);
for (uint32_t i = 0; i < operand.table_count + 1; i++) {
uint32_t target = operand.read_entry(&decoder, i);
control_stack[control_stack.size() - target - 1].Ref(
&map_, start, pc + i, value_depth, operand.arity > 0);
}
value_depth++;
break;
}
default: {
value_depth = value_depth - OpcodeArity(pc, end) + 1;
break;
}
}
pc += OpcodeLength(pc, end);
}
}
ControlTransfer Lookup(pc_t from) {
auto result = map_.find(from);
if (result == map_.end()) {
V8_Fatal(__FILE__, __LINE__, "no control target for pc %zu", from);
}
return result->second;
}
};
// Code and metadata needed to execute a function.
struct InterpreterCode {
const WasmFunction* function; // wasm function
AstLocalDecls locals; // local declarations
const byte* orig_start; // start of original code
const byte* orig_end; // end of original code
byte* start; // start of (maybe altered) code
byte* end; // end of (maybe altered) code
ControlTransfers* targets; // helper for control flow.
const byte* at(pc_t pc) { return start + pc; }
};
// The main storage for interpreter code. It maps {WasmFunction} to the
// metadata needed to execute each function.
class CodeMap {
public:
Zone* zone_;
const WasmModule* module_;
ZoneVector<InterpreterCode> interpreter_code_;
CodeMap(const WasmModule* module, Zone* zone)
: zone_(zone), module_(module), interpreter_code_(zone) {
if (module == nullptr) return;
for (size_t i = 0; i < module->functions.size(); i++) {
const WasmFunction* function = &module->functions[i];
const byte* code_start =
module->module_start + function->code_start_offset;
const byte* code_end = module->module_start + function->code_end_offset;
AddFunction(function, code_start, code_end);
}
}
InterpreterCode* FindCode(const WasmFunction* function) {
if (function->func_index < interpreter_code_.size()) {
InterpreterCode* code = &interpreter_code_[function->func_index];
DCHECK_EQ(function, code->function);
return code;
}
return nullptr;
}
InterpreterCode* GetCode(uint32_t function_index) {
CHECK_LT(function_index, interpreter_code_.size());
return Preprocess(&interpreter_code_[function_index]);
}
InterpreterCode* GetIndirectCode(uint32_t indirect_index) {
if (indirect_index >= module_->function_table.size()) return nullptr;
uint32_t index = module_->function_table[indirect_index];
if (index >= interpreter_code_.size()) return nullptr;
return GetCode(index);
}
InterpreterCode* Preprocess(InterpreterCode* code) {
if (code->targets == nullptr && code->start) {
// Compute the control targets map and the local declarations.
CHECK(DecodeLocalDecls(code->locals, code->start, code->end));
code->targets =
new (zone_) ControlTransfers(zone_, code->locals.decls_encoded_size,
code->orig_start, code->orig_end);
}
return code;
}
int AddFunction(const WasmFunction* function, const byte* code_start,
const byte* code_end) {
InterpreterCode code = {
function, AstLocalDecls(zone_), code_start,
code_end, const_cast<byte*>(code_start), const_cast<byte*>(code_end),
nullptr};
DCHECK_EQ(interpreter_code_.size(), function->func_index);
interpreter_code_.push_back(code);
return static_cast<int>(interpreter_code_.size()) - 1;
}
bool SetFunctionCode(const WasmFunction* function, const byte* start,
const byte* end) {
InterpreterCode* code = FindCode(function);
if (code == nullptr) return false;
code->targets = nullptr;
code->orig_start = start;
code->orig_end = end;
code->start = const_cast<byte*>(start);
code->end = const_cast<byte*>(end);
Preprocess(code);
return true;
}
};
// Responsible for executing code directly.
class ThreadImpl : public WasmInterpreter::Thread {
public:
ThreadImpl(Zone* zone, CodeMap* codemap, WasmModuleInstance* instance)
: codemap_(codemap),
instance_(instance),
stack_(zone),
frames_(zone),
state_(WasmInterpreter::STOPPED),
trap_reason_(kTrapCount) {}
virtual ~ThreadImpl() {}
//==========================================================================
// Implementation of public interface for WasmInterpreter::Thread.
//==========================================================================
virtual WasmInterpreter::State state() { return state_; }
virtual void PushFrame(const WasmFunction* function, WasmVal* args) {
InterpreterCode* code = codemap()->FindCode(function);
CHECK_NOT_NULL(code);
frames_.push_back({code, 0, 0, stack_.size()});
for (size_t i = 0; i < function->sig->parameter_count(); i++) {
stack_.push_back(args[i]);
}
frames_.back().ret_pc = InitLocals(code);
TRACE(" => push func#%u @%zu\n", code->function->func_index,
frames_.back().ret_pc);
}
virtual WasmInterpreter::State Run() {
do {
if (state_ == WasmInterpreter::STOPPED ||
state_ == WasmInterpreter::PAUSED) {
state_ = WasmInterpreter::RUNNING;
Execute(frames_.back().code, frames_.back().ret_pc, kRunSteps);
}
} while (state_ == WasmInterpreter::STOPPED);
return state_;
}
virtual WasmInterpreter::State Step() {
UNIMPLEMENTED();
return WasmInterpreter::STOPPED;
}
virtual void Pause() { UNIMPLEMENTED(); }
virtual void Reset() {
TRACE("----- RESET -----\n");
stack_.clear();
frames_.clear();
state_ = WasmInterpreter::STOPPED;
trap_reason_ = kTrapCount;
}
virtual int GetFrameCount() { return static_cast<int>(frames_.size()); }
virtual const WasmFrame* GetFrame(int index) {
UNIMPLEMENTED();
return nullptr;
}
virtual WasmFrame* GetMutableFrame(int index) {
UNIMPLEMENTED();
return nullptr;
}
virtual WasmVal GetReturnValue() {
if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef);
CHECK_EQ(WasmInterpreter::FINISHED, state_);
CHECK_EQ(1, stack_.size());
return stack_[0];
}
bool Terminated() {
return state_ == WasmInterpreter::TRAPPED ||
state_ == WasmInterpreter::FINISHED;
}
private:
// Entries on the stack of functions being evaluated.
struct Frame {
InterpreterCode* code;
pc_t call_pc;
pc_t ret_pc;
sp_t sp;
// Limit of parameters.
sp_t plimit() { return sp + code->function->sig->parameter_count(); }
// Limit of locals.
sp_t llimit() { return plimit() + code->locals.total_local_count; }
};
CodeMap* codemap_;
WasmModuleInstance* instance_;
ZoneVector<WasmVal> stack_;
ZoneVector<Frame> frames_;
WasmInterpreter::State state_;
TrapReason trap_reason_;
CodeMap* codemap() { return codemap_; }
WasmModuleInstance* instance() { return instance_; }
const WasmModule* module() { return instance_->module; }
void DoTrap(TrapReason trap, pc_t pc) {
state_ = WasmInterpreter::TRAPPED;
trap_reason_ = trap;
CommitPc(pc);
}
// Push a frame with arguments already on the stack.
void PushFrame(InterpreterCode* code, pc_t call_pc, pc_t ret_pc) {
CHECK_NOT_NULL(code);
DCHECK(!frames_.empty());
frames_.back().call_pc = call_pc;
frames_.back().ret_pc = ret_pc;
size_t arity = code->function->sig->parameter_count();
DCHECK_GE(stack_.size(), arity);
// The parameters will overlap the arguments already on the stack.
frames_.push_back({code, 0, 0, stack_.size() - arity});
frames_.back().ret_pc = InitLocals(code);
TRACE(" => push func#%u @%zu\n", code->function->func_index,
frames_.back().ret_pc);
}
pc_t InitLocals(InterpreterCode* code) {
for (auto p : code->locals.local_types) {
WasmVal val;
switch (p.first) {
case kAstI32:
val = WasmVal(static_cast<int32_t>(0));
break;
case kAstI64:
val = WasmVal(static_cast<int64_t>(0));
break;
case kAstF32:
val = WasmVal(static_cast<float>(0));
break;
case kAstF64:
val = WasmVal(static_cast<double>(0));
break;
default:
UNREACHABLE();
break;
}
stack_.insert(stack_.end(), p.second, val);
}
return code->locals.decls_encoded_size;
}
void CommitPc(pc_t pc) {
if (!frames_.empty()) {
frames_.back().ret_pc = pc;
}
}
bool SkipBreakpoint(InterpreterCode* code, pc_t pc) {
// TODO(titzer): skip a breakpoint if we are resuming from it, or it
// is set for another thread only.
return false;
}
bool DoReturn(InterpreterCode** code, pc_t* pc, pc_t* limit, WasmVal val) {
DCHECK_GT(frames_.size(), 0u);
stack_.resize(frames_.back().sp);
frames_.pop_back();
if (frames_.size() == 0) {
// A return from the top frame terminates the execution.
state_ = WasmInterpreter::FINISHED;
stack_.clear();
stack_.push_back(val);
TRACE(" => finish\n");
return false;
} else {
// Return to caller frame.
Frame* top = &frames_.back();
*code = top->code;
*pc = top->ret_pc;
*limit = top->code->end - top->code->start;
if (top->code->start[top->call_pc] == kExprCallIndirect ||
(top->code->orig_start &&
top->code->orig_start[top->call_pc] == kExprCallIndirect)) {
// UGLY: An indirect call has the additional function index on the
// stack.
stack_.pop_back();
}
TRACE(" => pop func#%u @%zu\n", (*code)->function->func_index, *pc);
stack_.push_back(val);
return true;
}
}
void DoCall(InterpreterCode* target, pc_t* pc, pc_t ret_pc, pc_t* limit) {
PushFrame(target, *pc, ret_pc);
*pc = frames_.back().ret_pc;
*limit = target->end - target->start;
}
// Adjust the program counter {pc} and the stack contents according to the
// code's precomputed control transfer map. Returns the different between
// the new pc and the old pc.
int DoControlTransfer(InterpreterCode* code, pc_t pc) {
auto target = code->targets->Lookup(pc);
switch (target.action) {
case ControlTransfer::kNoAction:
TRACE(" action [sp-%u]\n", target.spdiff);
PopN(target.spdiff);
break;
case ControlTransfer::kPopAndRepush: {
WasmVal val = Pop();
TRACE(" action [pop x, sp-%u, push x]\n", target.spdiff - 1);
DCHECK_GE(target.spdiff, 1u);
PopN(target.spdiff - 1);
Push(pc, val);
break;
}
case ControlTransfer::kPushVoid:
TRACE(" action [sp-%u, push void]\n", target.spdiff);
PopN(target.spdiff);
Push(pc, WasmVal());
break;
}
return target.pcdiff;
}
void Execute(InterpreterCode* code, pc_t pc, int max) {
Decoder decoder(code->start, code->end);
pc_t limit = code->end - code->start;
while (true) {
if (max-- <= 0) {
// Maximum number of instructions reached.
state_ = WasmInterpreter::PAUSED;
return CommitPc(pc);
}
if (pc >= limit) {
// Fell off end of code; do an implicit return.
TRACE("@%-3zu: ImplicitReturn\n", pc);
WasmVal val = PopArity(code->function->sig->return_count());
if (!DoReturn(&code, &pc, &limit, val)) return;
decoder.Reset(code->start, code->end);
continue;
}
const char* skip = "";
int len = 1;
byte opcode = code->start[pc];
byte orig = opcode;
if (opcode == kInternalBreakpoint) {
if (SkipBreakpoint(code, pc)) {
// skip breakpoint by switching on original code.
orig = code->orig_start[pc];
skip = "[skip] ";
} else {
state_ = WasmInterpreter::PAUSED;
return CommitPc(pc);
}
}
USE(skip);
TRACE("@%-3zu: %s%-24s:", pc, skip,
WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(orig)));
TraceValueStack();
TRACE("\n");
switch (orig) {
case kExprNop:
Push(pc, WasmVal());
break;
case kExprBlock:
case kExprLoop: {
// Do nothing.
break;
}
case kExprIf: {
WasmVal cond = Pop();
bool is_true = cond.to<uint32_t>() != 0;
if (is_true) {
// fall through to the true block.
TRACE(" true => fallthrough\n");
} else {
len = DoControlTransfer(code, pc);
TRACE(" false => @%zu\n", pc + len);
}
break;
}
case kExprElse: {
len = DoControlTransfer(code, pc);
TRACE(" end => @%zu\n", pc + len);
break;
}
case kExprSelect: {
WasmVal cond = Pop();
WasmVal fval = Pop();
WasmVal tval = Pop();
Push(pc, cond.to<int32_t>() != 0 ? tval : fval);
break;
}
case kExprBr: {
BreakDepthOperand operand(&decoder, code->at(pc));
WasmVal val = PopArity(operand.arity);
len = DoControlTransfer(code, pc);
TRACE(" br => @%zu\n", pc + len);
if (operand.arity > 0) Push(pc, val);
break;
}
case kExprBrIf: {
BreakDepthOperand operand(&decoder, code->at(pc));
WasmVal cond = Pop();
WasmVal val = PopArity(operand.arity);
bool is_true = cond.to<uint32_t>() != 0;
if (is_true) {
len = DoControlTransfer(code, pc);
TRACE(" br_if => @%zu\n", pc + len);
if (operand.arity > 0) Push(pc, val);
} else {
TRACE(" false => fallthrough\n");
len = 1 + operand.length;
Push(pc, WasmVal());
}
break;
}
case kExprBrTable: {
BranchTableOperand operand(&decoder, code->at(pc));
uint32_t key = Pop().to<uint32_t>();
WasmVal val = PopArity(operand.arity);
if (key >= operand.table_count) key = operand.table_count;
len = DoControlTransfer(code, pc + key) + key;
TRACE(" br[%u] => @%zu\n", key, pc + len);
if (operand.arity > 0) Push(pc, val);
break;
}
case kExprReturn: {
ReturnArityOperand operand(&decoder, code->at(pc));
WasmVal val = PopArity(operand.arity);
if (!DoReturn(&code, &pc, &limit, val)) return;
decoder.Reset(code->start, code->end);
continue;
}
case kExprUnreachable: {
DoTrap(kTrapUnreachable, pc);
return CommitPc(pc);
}
case kExprEnd: {
len = DoControlTransfer(code, pc);
DCHECK_EQ(1, len);
break;
}
case kExprI8Const: {
ImmI8Operand operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprI32Const: {
ImmI32Operand operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprI64Const: {
ImmI64Operand operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprF32Const: {
ImmF32Operand operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprF64Const: {
ImmF64Operand operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprGetLocal: {
LocalIndexOperand operand(&decoder, code->at(pc));
Push(pc, stack_[frames_.back().sp + operand.index]);
len = 1 + operand.length;
break;
}
case kExprSetLocal: {
LocalIndexOperand operand(&decoder, code->at(pc));
WasmVal val = Pop();
stack_[frames_.back().sp + operand.index] = val;
Push(pc, val);
len = 1 + operand.length;
break;
}
case kExprCallFunction: {
CallFunctionOperand operand(&decoder, code->at(pc));
InterpreterCode* target = codemap()->GetCode(operand.index);
DoCall(target, &pc, pc + 1 + operand.length, &limit);
code = target;
decoder.Reset(code->start, code->end);
continue;
}
case kExprCallIndirect: {
CallIndirectOperand operand(&decoder, code->at(pc));
size_t index = stack_.size() - operand.arity - 1;
DCHECK_LT(index, stack_.size());
uint32_t table_index = stack_[index].to<uint32_t>();
if (table_index >= module()->function_table.size()) {
return DoTrap(kTrapFuncInvalid, pc);
}
uint16_t function_index = module()->function_table[table_index];
InterpreterCode* target = codemap()->GetCode(function_index);
DCHECK(target);
if (target->function->sig_index != operand.index) {
return DoTrap(kTrapFuncSigMismatch, pc);
}
DoCall(target, &pc, pc + 1 + operand.length, &limit);
code = target;
decoder.Reset(code->start, code->end);
continue;
}
case kExprCallImport: {
UNIMPLEMENTED();
break;
}
case kExprLoadGlobal: {
GlobalIndexOperand operand(&decoder, code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index];
byte* ptr = instance()->globals_start + global->offset;
MachineType type = global->type;
WasmVal val;
if (type == MachineType::Int8()) {
val =
WasmVal(static_cast<int32_t>(*reinterpret_cast<int8_t*>(ptr)));
} else if (type == MachineType::Uint8()) {
val =
WasmVal(static_cast<int32_t>(*reinterpret_cast<uint8_t*>(ptr)));
} else if (type == MachineType::Int16()) {
val =
WasmVal(static_cast<int32_t>(*reinterpret_cast<int16_t*>(ptr)));
} else if (type == MachineType::Uint16()) {
val = WasmVal(
static_cast<int32_t>(*reinterpret_cast<uint16_t*>(ptr)));
} else if (type == MachineType::Int32()) {
val = WasmVal(*reinterpret_cast<int32_t*>(ptr));
} else if (type == MachineType::Uint32()) {
val = WasmVal(*reinterpret_cast<uint32_t*>(ptr));
} else if (type == MachineType::Int64()) {
val = WasmVal(*reinterpret_cast<int64_t*>(ptr));
} else if (type == MachineType::Uint64()) {
val = WasmVal(*reinterpret_cast<uint64_t*>(ptr));
} else if (type == MachineType::Float32()) {
val = WasmVal(*reinterpret_cast<float*>(ptr));
} else if (type == MachineType::Float64()) {
val = WasmVal(*reinterpret_cast<double*>(ptr));
} else {
UNREACHABLE();
}
Push(pc, val);
len = 1 + operand.length;
break;
}
case kExprStoreGlobal: {
GlobalIndexOperand operand(&decoder, code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index];
byte* ptr = instance()->globals_start + global->offset;
MachineType type = global->type;
WasmVal val = Pop();
if (type == MachineType::Int8()) {
*reinterpret_cast<int8_t*>(ptr) =
static_cast<int8_t>(val.to<int32_t>());
} else if (type == MachineType::Uint8()) {
*reinterpret_cast<uint8_t*>(ptr) =
static_cast<uint8_t>(val.to<uint32_t>());
} else if (type == MachineType::Int16()) {
*reinterpret_cast<int16_t*>(ptr) =
static_cast<int16_t>(val.to<int32_t>());
} else if (type == MachineType::Uint16()) {
*reinterpret_cast<uint16_t*>(ptr) =
static_cast<uint16_t>(val.to<uint32_t>());
} else if (type == MachineType::Int32()) {
*reinterpret_cast<int32_t*>(ptr) = val.to<int32_t>();
} else if (type == MachineType::Uint32()) {
*reinterpret_cast<uint32_t*>(ptr) = val.to<uint32_t>();
} else if (type == MachineType::Int64()) {
*reinterpret_cast<int64_t*>(ptr) = val.to<int64_t>();
} else if (type == MachineType::Uint64()) {
*reinterpret_cast<uint64_t*>(ptr) = val.to<uint64_t>();
} else if (type == MachineType::Float32()) {
*reinterpret_cast<float*>(ptr) = val.to<float>();
} else if (type == MachineType::Float64()) {
*reinterpret_cast<double*>(ptr) = val.to<double>();
} else {
UNREACHABLE();
}
Push(pc, val);
len = 1 + operand.length;
break;
}
#define LOAD_CASE(name, ctype, mtype) \
case kExpr##name: { \
MemoryAccessOperand operand(&decoder, code->at(pc)); \
uint32_t index = Pop().to<uint32_t>(); \
size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
if (operand.offset > effective_mem_size || \
index > (effective_mem_size - operand.offset)) { \
return DoTrap(kTrapMemOutOfBounds, pc); \
} \
byte* addr = instance()->mem_start + operand.offset + index; \
/* TODO(titzer): alignment, endianness for load mem */ \
WasmVal result(static_cast<ctype>(*reinterpret_cast<mtype*>(addr))); \
Push(pc, result); \
len = 1 + operand.length; \
break; \
}
LOAD_CASE(I32LoadMem8S, int32_t, int8_t);
LOAD_CASE(I32LoadMem8U, int32_t, uint8_t);
LOAD_CASE(I32LoadMem16S, int32_t, int16_t);
LOAD_CASE(I32LoadMem16U, int32_t, uint16_t);
LOAD_CASE(I64LoadMem8S, int64_t, int8_t);
LOAD_CASE(I64LoadMem8U, int64_t, uint8_t);
LOAD_CASE(I64LoadMem16S, int64_t, int16_t);
LOAD_CASE(I64LoadMem16U, int64_t, uint16_t);
LOAD_CASE(I64LoadMem32S, int64_t, int32_t);
LOAD_CASE(I64LoadMem32U, int64_t, uint32_t);
LOAD_CASE(I32LoadMem, int32_t, int32_t);
LOAD_CASE(I64LoadMem, int64_t, int64_t);
LOAD_CASE(F32LoadMem, float, float);
LOAD_CASE(F64LoadMem, double, double);
#undef LOAD_CASE
#define STORE_CASE(name, ctype, mtype) \
case kExpr##name: { \
MemoryAccessOperand operand(&decoder, code->at(pc)); \
WasmVal val = Pop(); \
uint32_t index = Pop().to<uint32_t>(); \
size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
if (operand.offset > effective_mem_size || \
index > (effective_mem_size - operand.offset)) { \
return DoTrap(kTrapMemOutOfBounds, pc); \
} \
byte* addr = instance()->mem_start + operand.offset + index; \
/* TODO(titzer): alignment, endianness for store mem */ \
*reinterpret_cast<mtype*>(addr) = static_cast<mtype>(val.to<ctype>()); \
Push(pc, val); \
len = 1 + operand.length; \
break; \
}
STORE_CASE(I32StoreMem8, int32_t, int8_t);
STORE_CASE(I32StoreMem16, int32_t, int16_t);
STORE_CASE(I64StoreMem8, int64_t, int8_t);
STORE_CASE(I64StoreMem16, int64_t, int16_t);
STORE_CASE(I64StoreMem32, int64_t, int32_t);
STORE_CASE(I32StoreMem, int32_t, int32_t);
STORE_CASE(I64StoreMem, int64_t, int64_t);
STORE_CASE(F32StoreMem, float, float);
STORE_CASE(F64StoreMem, double, double);
#undef STORE_CASE
#define ASMJS_LOAD_CASE(name, ctype, mtype, defval) \
case kExpr##name: { \
uint32_t index = Pop().to<uint32_t>(); \
ctype result; \
if (index >= (instance()->mem_size - sizeof(mtype))) { \
result = defval; \
} else { \
byte* addr = instance()->mem_start + index; \
/* TODO(titzer): alignment for asmjs load mem? */ \
result = static_cast<ctype>(*reinterpret_cast<mtype*>(addr)); \
} \
Push(pc, WasmVal(result)); \
break; \
}
ASMJS_LOAD_CASE(I32AsmjsLoadMem8S, int32_t, int8_t, 0);
ASMJS_LOAD_CASE(I32AsmjsLoadMem8U, int32_t, uint8_t, 0);
ASMJS_LOAD_CASE(I32AsmjsLoadMem16S, int32_t, int16_t, 0);
ASMJS_LOAD_CASE(I32AsmjsLoadMem16U, int32_t, uint16_t, 0);
ASMJS_LOAD_CASE(I32AsmjsLoadMem, int32_t, int32_t, 0);
ASMJS_LOAD_CASE(F32AsmjsLoadMem, float, float,
std::numeric_limits<float>::quiet_NaN());
ASMJS_LOAD_CASE(F64AsmjsLoadMem, double, double,
std::numeric_limits<double>::quiet_NaN());
#undef ASMJS_LOAD_CASE
#define ASMJS_STORE_CASE(name, ctype, mtype) \
case kExpr##name: { \
WasmVal val = Pop(); \
uint32_t index = Pop().to<uint32_t>(); \
if (index < (instance()->mem_size - sizeof(mtype))) { \
byte* addr = instance()->mem_start + index; \
/* TODO(titzer): alignment for asmjs store mem? */ \
*(reinterpret_cast<mtype*>(addr)) = static_cast<mtype>(val.to<ctype>()); \
} \
Push(pc, val); \
break; \
}
ASMJS_STORE_CASE(I32AsmjsStoreMem8, int32_t, int8_t);
ASMJS_STORE_CASE(I32AsmjsStoreMem16, int32_t, int16_t);
ASMJS_STORE_CASE(I32AsmjsStoreMem, int32_t, int32_t);
ASMJS_STORE_CASE(F32AsmjsStoreMem, float, float);
ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double);
#undef ASMJS_STORE_CASE
case kExprMemorySize: {
Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size)));
break;
}
#define EXECUTE_SIMPLE_BINOP(name, ctype, op) \
case kExpr##name: { \
WasmVal rval = Pop(); \
WasmVal lval = Pop(); \
WasmVal result(lval.to<ctype>() op rval.to<ctype>()); \
Push(pc, result); \
break; \
}
FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP)
#undef EXECUTE_SIMPLE_BINOP
#define EXECUTE_OTHER_BINOP(name, ctype) \
case kExpr##name: { \
TrapReason trap = kTrapCount; \
volatile ctype rval = Pop().to<ctype>(); \
volatile ctype lval = Pop().to<ctype>(); \
WasmVal result(Execute##name(lval, rval, &trap)); \
if (trap != kTrapCount) return DoTrap(trap, pc); \
Push(pc, result); \
break; \
}
FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP)
#undef EXECUTE_OTHER_BINOP
#define EXECUTE_OTHER_UNOP(name, ctype) \
case kExpr##name: { \
TrapReason trap = kTrapCount; \
volatile ctype val = Pop().to<ctype>(); \
WasmVal result(Execute##name(val, &trap)); \
if (trap != kTrapCount) return DoTrap(trap, pc); \
Push(pc, result); \
break; \
}
FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP)
#undef EXECUTE_OTHER_UNOP
default:
V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s",
code->start[pc], OpcodeName(code->start[pc]));
UNREACHABLE();
}
pc += len;
}
UNREACHABLE(); // above decoding loop should run forever.
}
WasmVal Pop() {
DCHECK_GT(stack_.size(), 0u);
DCHECK_GT(frames_.size(), 0u);
DCHECK_GT(stack_.size(), frames_.back().llimit()); // can't pop into locals
WasmVal val = stack_.back();
stack_.pop_back();
return val;
}
void PopN(int n) {
DCHECK_GE(stack_.size(), static_cast<size_t>(n));
DCHECK_GT(frames_.size(), 0u);
size_t nsize = stack_.size() - n;
DCHECK_GE(nsize, frames_.back().llimit()); // can't pop into locals
stack_.resize(nsize);
}
WasmVal PopArity(size_t arity) {
if (arity == 0) return WasmVal();
CHECK_EQ(1, arity);
return Pop();
}
void Push(pc_t pc, WasmVal val) {
// TODO(titzer): store PC as well?
stack_.push_back(val);
}
void TraceStack(const char* phase, pc_t pc) {
if (FLAG_trace_wasm_interpreter) {
PrintF("%s @%zu", phase, pc);
UNIMPLEMENTED();
PrintF("\n");
}
}
void TraceValueStack() {
Frame* top = frames_.size() > 0 ? &frames_.back() : nullptr;
sp_t sp = top ? top->sp : 0;
sp_t plimit = top ? top->plimit() : 0;
sp_t llimit = top ? top->llimit() : 0;
if (FLAG_trace_wasm_interpreter) {
for (size_t i = sp; i < stack_.size(); i++) {
if (i < plimit)
PrintF(" p%zu:", i);
else if (i < llimit)
PrintF(" l%zu:", i);
else
PrintF(" s%zu:", i);
WasmVal val = stack_[i];
switch (val.type) {
case kAstI32:
PrintF("i32:%d", val.to<int32_t>());
break;
case kAstI64:
PrintF("i64:%" PRId64 "", val.to<int64_t>());
break;
case kAstF32:
PrintF("f32:%f", val.to<float>());
break;
case kAstF64:
PrintF("f64:%lf", val.to<double>());
break;
case kAstStmt:
PrintF("void");
break;
default:
UNREACHABLE();
break;
}
}
}
}
};
//============================================================================
// The implementation details of the interpreter.
//============================================================================
class WasmInterpreterInternals : public ZoneObject {
public:
WasmModuleInstance* instance_;
CodeMap codemap_;
ZoneVector<ThreadImpl> threads_;
WasmInterpreterInternals(Zone* zone, WasmModuleInstance* instance)
: instance_(instance),
codemap_(instance_ ? instance_->module : nullptr, zone),
threads_(zone) {
threads_.push_back(ThreadImpl(zone, &codemap_, instance));
}
};
//============================================================================
// Implementation of the public interface of the interpreter.
//============================================================================
WasmInterpreter::WasmInterpreter(WasmModuleInstance* instance,
base::AccountingAllocator* allocator)
: zone_(allocator),
internals_(new (&zone_) WasmInterpreterInternals(&zone_, instance)) {}
WasmInterpreter::~WasmInterpreter() {}
void WasmInterpreter::Run() { internals_->threads_[0].Run(); }
void WasmInterpreter::Pause() { internals_->threads_[0].Pause(); }
bool WasmInterpreter::SetBreakpoint(const WasmFunction* function, int pc,
bool enabled) {
InterpreterCode* code = internals_->codemap_.FindCode(function);
if (!code) return false;
int size = static_cast<int>(code->end - code->start);
// Check bounds for {pc}.
if (pc < 0 || pc >= size) return false;
// Make a copy of the code before enabling a breakpoint.
if (enabled && code->orig_start == code->start) {
code->start = reinterpret_cast<byte*>(zone_.New(size));
memcpy(code->start, code->orig_start, size);
code->end = code->start + size;
}
bool prev = code->start[pc] == kInternalBreakpoint;
if (enabled) {
code->start[pc] = kInternalBreakpoint;
} else {
code->start[pc] = code->orig_start[pc];
}
return prev;
}
bool WasmInterpreter::GetBreakpoint(const WasmFunction* function, int pc) {
InterpreterCode* code = internals_->codemap_.FindCode(function);
if (!code) return false;
int size = static_cast<int>(code->end - code->start);
// Check bounds for {pc}.
if (pc < 0 || pc >= size) return false;
// Check if a breakpoint is present at that place in the code.
return code->start[pc] == kInternalBreakpoint;
}
bool WasmInterpreter::SetTracing(const WasmFunction* function, bool enabled) {
UNIMPLEMENTED();
return false;
}
int WasmInterpreter::GetThreadCount() {
return 1; // only one thread for now.
}
WasmInterpreter::Thread& WasmInterpreter::GetThread(int id) {
CHECK_EQ(0, id); // only one thread for now.
return internals_->threads_[id];
}
WasmVal WasmInterpreter::GetLocalVal(const WasmFrame* frame, int index) {
CHECK_GE(index, 0);
UNIMPLEMENTED();
WasmVal none;
none.type = kAstStmt;
return none;
}
WasmVal WasmInterpreter::GetExprVal(const WasmFrame* frame, int pc) {
UNIMPLEMENTED();
WasmVal none;
none.type = kAstStmt;
return none;
}
void WasmInterpreter::SetLocalVal(WasmFrame* frame, int index, WasmVal val) {
UNIMPLEMENTED();
}
void WasmInterpreter::SetExprVal(WasmFrame* frame, int pc, WasmVal val) {
UNIMPLEMENTED();
}
size_t WasmInterpreter::GetMemorySize() {
return internals_->instance_->mem_size;
}
WasmVal WasmInterpreter::ReadMemory(size_t offset) {
UNIMPLEMENTED();
return WasmVal();
}
void WasmInterpreter::WriteMemory(size_t offset, WasmVal val) {
UNIMPLEMENTED();
}
int WasmInterpreter::AddFunctionForTesting(const WasmFunction* function) {
return internals_->codemap_.AddFunction(function, nullptr, nullptr);
}
bool WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function,
const byte* start,
const byte* end) {
return internals_->codemap_.SetFunctionCode(function, start, end);
}
ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
Zone* zone, const byte* start, const byte* end) {
ControlTransfers targets(zone, 0, start, end);
return targets.map_;
}
} // namespace wasm
} // namespace internal
} // namespace v8
// Copyright 2016 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_INTERPRETER_H_
#define V8_WASM_INTERPRETER_H_
#include "src/wasm/wasm-opcodes.h"
#include "src/zone-containers.h"
namespace v8 {
namespace base {
class AccountingAllocator;
}
namespace internal {
namespace wasm {
// forward declarations.
struct WasmFunction;
struct WasmModuleInstance;
class WasmInterpreterInternals;
typedef size_t pc_t;
typedef size_t sp_t;
typedef int32_t pcdiff_t;
typedef uint32_t spdiff_t;
// Visible for testing. A {ControlTransfer} helps the interpreter figure out
// the target program counter and stack manipulations for a branch.
struct ControlTransfer {
enum StackAction { kNoAction, kPopAndRepush, kPushVoid };
pcdiff_t pcdiff; // adjustment to the program counter (positive or negative).
spdiff_t spdiff; // number of elements to pop off the stack.
StackAction action; // action to perform on the stack.
};
typedef ZoneMap<pc_t, ControlTransfer> ControlTransferMap;
// Macro for defining union members.
#define FOREACH_UNION_MEMBER(V) \
V(i32, kAstI32, int32_t) \
V(u32, kAstI32, uint32_t) \
V(i64, kAstI64, int64_t) \
V(u64, kAstI64, uint64_t) \
V(f32, kAstF32, float) \
V(f64, kAstF64, double)
// Representation of values within the interpreter.
struct WasmVal {
LocalType type;
union {
#define DECLARE_FIELD(field, localtype, ctype) ctype field;
FOREACH_UNION_MEMBER(DECLARE_FIELD)
#undef DECLARE_FIELD
} val;
WasmVal() : type(kAstStmt) {}
#define DECLARE_CONSTRUCTOR(field, localtype, ctype) \
explicit WasmVal(ctype v) : type(localtype) { val.field = v; }
FOREACH_UNION_MEMBER(DECLARE_CONSTRUCTOR)
#undef DECLARE_CONSTRUCTOR
template <typename T>
T to() {
UNREACHABLE();
}
};
#define DECLARE_CAST(field, localtype, ctype) \
template <> \
inline ctype WasmVal::to() { \
CHECK_EQ(localtype, type); \
return val.field; \
}
FOREACH_UNION_MEMBER(DECLARE_CAST)
#undef DECLARE_CAST
template <>
inline void WasmVal::to() {
CHECK_EQ(kAstStmt, type);
}
// Representation of frames within the interpreter.
class WasmFrame {
public:
const WasmFunction* function() const { return function_; }
int pc() const { return pc_; }
private:
friend class WasmInterpreter;
WasmFrame(const WasmFunction* function, int pc, int fp, int sp)
: function_(function), pc_(pc), fp_(fp), sp_(sp) {}
const WasmFunction* function_;
int pc_;
int fp_;
int sp_;
};
// An interpreter capable of executing WASM.
class WasmInterpreter {
public:
// State machine for a Thread:
// +---------------Run()-----------+
// V |
// STOPPED ---Run()--> RUNNING ------Pause()-----+-> PAUSED <------+
// | | | / | |
// | | +---- Breakpoint ---+ +-- Step() --+
// | |
// | +------------ Trap --------------> TRAPPED
// +------------- Finish -------------> FINISHED
enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED };
// Representation of a thread in the interpreter.
class Thread {
public:
// Execution control.
virtual State state() = 0;
virtual void PushFrame(const WasmFunction* function, WasmVal* args) = 0;
virtual State Run() = 0;
virtual State Step() = 0;
virtual void Pause() = 0;
virtual void Reset() = 0;
virtual ~Thread() {}
// Stack inspection and modification.
virtual int GetFrameCount() = 0;
virtual const WasmFrame* GetFrame(int index) = 0;
virtual WasmFrame* GetMutableFrame(int index) = 0;
virtual WasmVal GetReturnValue() = 0;
// Thread-specific breakpoints.
bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled);
bool GetBreakpoint(const WasmFunction* function, int pc);
};
WasmInterpreter(WasmModuleInstance* instance,
base::AccountingAllocator* allocator);
~WasmInterpreter();
//==========================================================================
// Execution controls.
//==========================================================================
void Run();
void Pause();
// Set a breakpoint at {pc} in {function} to be {enabled}. Returns the
// previous state of the breakpoint at {pc}.
bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled);
// Gets the current state of the breakpoint at {function}.
bool GetBreakpoint(const WasmFunction* function, int pc);
// Enable or disable tracing for {function}. Return the previous state.
bool SetTracing(const WasmFunction* function, bool enabled);
//==========================================================================
// Thread iteration and inspection.
//==========================================================================
int GetThreadCount();
Thread& GetThread(int id);
//==========================================================================
// Stack frame inspection.
//==========================================================================
WasmVal GetLocalVal(const WasmFrame* frame, int index);
WasmVal GetExprVal(const WasmFrame* frame, int pc);
void SetLocalVal(WasmFrame* frame, int index, WasmVal val);
void SetExprVal(WasmFrame* frame, int pc, WasmVal val);
//==========================================================================
// Memory access.
//==========================================================================
size_t GetMemorySize();
WasmVal ReadMemory(size_t offset);
void WriteMemory(size_t offset, WasmVal val);
//==========================================================================
// Testing functionality.
//==========================================================================
// Manually adds a function to this interpreter, returning the index of the
// function.
int AddFunctionForTesting(const WasmFunction* function);
// Manually adds code to the interpreter for the given function.
bool SetFunctionCodeForTesting(const WasmFunction* function,
const byte* start, const byte* end);
// Computes the control targets for the given bytecode as {pc offset, sp
// offset}
// pairs. Used internally in the interpreter, but exposed for testing.
static ControlTransferMap ComputeControlTransfersForTesting(Zone* zone,
const byte* start,
const byte* end);
private:
Zone zone_;
WasmInterpreterInternals* internals_;
};
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_INTERPRETER_H_
...@@ -140,9 +140,9 @@ class LocalDeclEncoder { ...@@ -140,9 +140,9 @@ class LocalDeclEncoder {
// Prepend local declarations by creating a new buffer and copying data // Prepend local declarations by creating a new buffer and copying data
// over. The new buffer must be delete[]'d by the caller. // over. The new buffer must be delete[]'d by the caller.
void Prepend(const byte** start, const byte** end) const { void Prepend(Zone* zone, const byte** start, const byte** end) const {
size_t size = (*end - *start); size_t size = (*end - *start);
byte* buffer = new byte[Size() + size]; byte* buffer = reinterpret_cast<byte*>(zone->New(Size() + size));
size_t pos = Emit(buffer); size_t pos = Emit(buffer);
memcpy(buffer + pos, *start, size); memcpy(buffer + pos, *start, size);
pos += size; pos += size;
......
...@@ -190,6 +190,7 @@ ...@@ -190,6 +190,7 @@
'wasm/test-run-wasm.cc', 'wasm/test-run-wasm.cc',
'wasm/test-run-wasm-64.cc', 'wasm/test-run-wasm-64.cc',
'wasm/test-run-wasm-asmjs.cc', 'wasm/test-run-wasm-asmjs.cc',
'wasm/test-run-wasm-interpreter.cc',
'wasm/test-run-wasm-js.cc', 'wasm/test-run-wasm-js.cc',
'wasm/test-run-wasm-module.cc', 'wasm/test-run-wasm-module.cc',
'wasm/test-signatures.h', 'wasm/test-signatures.h',
......
...@@ -92,7 +92,7 @@ FOREACH_I64_OPERATOR(DECLARE_CONST) ...@@ -92,7 +92,7 @@ FOREACH_I64_OPERATOR(DECLARE_CONST)
WASM_EXEC_TEST(I64Const) { WASM_EXEC_TEST(I64Const) {
REQUIRE(I64Const); REQUIRE(I64Const);
WasmRunner<int64_t> r; WasmRunner<int64_t> r(execution_mode);
const int64_t kExpectedValue = 0x1122334455667788LL; const int64_t kExpectedValue = 0x1122334455667788LL;
// return(kExpectedValue) // return(kExpectedValue)
BUILD(r, WASM_I64V_9(kExpectedValue)); BUILD(r, WASM_I64V_9(kExpectedValue));
...@@ -103,7 +103,7 @@ WASM_EXEC_TEST(I64Const_many) { ...@@ -103,7 +103,7 @@ WASM_EXEC_TEST(I64Const_many) {
REQUIRE(I64Const); REQUIRE(I64Const);
int cntr = 0; int cntr = 0;
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
WasmRunner<int64_t> r; WasmRunner<int64_t> r(execution_mode);
const int64_t kExpectedValue = (static_cast<int64_t>(*i) << 32) | cntr; const int64_t kExpectedValue = (static_cast<int64_t>(*i) << 32) | cntr;
// return(kExpectedValue) // return(kExpectedValue)
BUILD(r, WASM_I64V(kExpectedValue)); BUILD(r, WASM_I64V(kExpectedValue));
...@@ -114,7 +114,7 @@ WASM_EXEC_TEST(I64Const_many) { ...@@ -114,7 +114,7 @@ WASM_EXEC_TEST(I64Const_many) {
WASM_EXEC_TEST(Return_I64) { WASM_EXEC_TEST(Return_I64) {
REQUIRE(I64Return); REQUIRE(I64Return);
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_RETURN1(WASM_GET_LOCAL(0))); BUILD(r, WASM_RETURN1(WASM_GET_LOCAL(0)));
...@@ -123,7 +123,8 @@ WASM_EXEC_TEST(Return_I64) { ...@@ -123,7 +123,8 @@ WASM_EXEC_TEST(Return_I64) {
WASM_EXEC_TEST(I64Add) { WASM_EXEC_TEST(I64Add) {
REQUIRE(I64Add); REQUIRE(I64Add);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i + *j, r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ(*i + *j, r.Call(*i, *j)); }
...@@ -132,7 +133,8 @@ WASM_EXEC_TEST(I64Add) { ...@@ -132,7 +133,8 @@ WASM_EXEC_TEST(I64Add) {
WASM_EXEC_TEST(I64Sub) { WASM_EXEC_TEST(I64Sub) {
REQUIRE(I64Sub); REQUIRE(I64Sub);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i - *j, r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ(*i - *j, r.Call(*i, *j)); }
...@@ -141,7 +143,8 @@ WASM_EXEC_TEST(I64Sub) { ...@@ -141,7 +143,8 @@ WASM_EXEC_TEST(I64Sub) {
WASM_EXEC_TEST(I64DivS) { WASM_EXEC_TEST(I64DivS) {
REQUIRE(I64DivS); REQUIRE(I64DivS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { FOR_INT64_INPUTS(j) {
...@@ -158,7 +161,8 @@ WASM_EXEC_TEST(I64DivS) { ...@@ -158,7 +161,8 @@ WASM_EXEC_TEST(I64DivS) {
WASM_EXEC_TEST(I64DivS_Trap) { WASM_EXEC_TEST(I64DivS_Trap) {
REQUIRE(I64DivS); REQUIRE(I64DivS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(0, r.Call(asi64(0), asi64(100))); CHECK_EQ(0, r.Call(asi64(0), asi64(100)));
CHECK_TRAP64(r.Call(asi64(100), asi64(0))); CHECK_TRAP64(r.Call(asi64(100), asi64(0)));
...@@ -170,7 +174,7 @@ WASM_EXEC_TEST(I64DivS_Trap) { ...@@ -170,7 +174,7 @@ WASM_EXEC_TEST(I64DivS_Trap) {
WASM_EXEC_TEST(I64DivS_Byzero_Const) { WASM_EXEC_TEST(I64DivS_Byzero_Const) {
REQUIRE(I64DivS); REQUIRE(I64DivS);
for (int8_t denom = -2; denom < 8; denom++) { for (int8_t denom = -2; denom < 8; denom++) {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_I64V_1(denom))); BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_I64V_1(denom)));
for (int64_t val = -7; val < 8; val++) { for (int64_t val = -7; val < 8; val++) {
if (denom == 0) { if (denom == 0) {
...@@ -184,7 +188,8 @@ WASM_EXEC_TEST(I64DivS_Byzero_Const) { ...@@ -184,7 +188,8 @@ WASM_EXEC_TEST(I64DivS_Byzero_Const) {
WASM_EXEC_TEST(I64DivU) { WASM_EXEC_TEST(I64DivU) {
REQUIRE(I64DivU); REQUIRE(I64DivU);
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64()); WasmRunner<uint64_t> r(execution_mode, MachineType::Uint64(),
MachineType::Uint64());
BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) { FOR_UINT64_INPUTS(j) {
...@@ -199,7 +204,8 @@ WASM_EXEC_TEST(I64DivU) { ...@@ -199,7 +204,8 @@ WASM_EXEC_TEST(I64DivU) {
WASM_EXEC_TEST(I64DivU_Trap) { WASM_EXEC_TEST(I64DivU_Trap) {
REQUIRE(I64DivU); REQUIRE(I64DivU);
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64()); WasmRunner<uint64_t> r(execution_mode, MachineType::Uint64(),
MachineType::Uint64());
BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(0, r.Call(asu64(0), asu64(100))); CHECK_EQ(0, r.Call(asu64(0), asu64(100)));
CHECK_TRAP64(r.Call(asu64(100), asu64(0))); CHECK_TRAP64(r.Call(asu64(100), asu64(0)));
...@@ -210,7 +216,7 @@ WASM_EXEC_TEST(I64DivU_Trap) { ...@@ -210,7 +216,7 @@ WASM_EXEC_TEST(I64DivU_Trap) {
WASM_EXEC_TEST(I64DivU_Byzero_Const) { WASM_EXEC_TEST(I64DivU_Byzero_Const) {
REQUIRE(I64DivU); REQUIRE(I64DivU);
for (uint64_t denom = 0xfffffffffffffffe; denom < 8; denom++) { for (uint64_t denom = 0xfffffffffffffffe; denom < 8; denom++) {
WasmRunner<uint64_t> r(MachineType::Uint64()); WasmRunner<uint64_t> r(execution_mode, MachineType::Uint64());
BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_I64V_1(denom))); BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_I64V_1(denom)));
for (uint64_t val = 0xfffffffffffffff0; val < 8; val++) { for (uint64_t val = 0xfffffffffffffff0; val < 8; val++) {
...@@ -225,7 +231,8 @@ WASM_EXEC_TEST(I64DivU_Byzero_Const) { ...@@ -225,7 +231,8 @@ WASM_EXEC_TEST(I64DivU_Byzero_Const) {
WASM_EXEC_TEST(I64RemS) { WASM_EXEC_TEST(I64RemS) {
REQUIRE(I64RemS); REQUIRE(I64RemS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { FOR_INT64_INPUTS(j) {
...@@ -240,7 +247,8 @@ WASM_EXEC_TEST(I64RemS) { ...@@ -240,7 +247,8 @@ WASM_EXEC_TEST(I64RemS) {
WASM_EXEC_TEST(I64RemS_Trap) { WASM_EXEC_TEST(I64RemS_Trap) {
REQUIRE(I64RemS); REQUIRE(I64RemS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(33, r.Call(asi64(133), asi64(100))); CHECK_EQ(33, r.Call(asi64(133), asi64(100)));
CHECK_EQ(0, r.Call(std::numeric_limits<int64_t>::min(), asi64(-1))); CHECK_EQ(0, r.Call(std::numeric_limits<int64_t>::min(), asi64(-1)));
...@@ -251,7 +259,8 @@ WASM_EXEC_TEST(I64RemS_Trap) { ...@@ -251,7 +259,8 @@ WASM_EXEC_TEST(I64RemS_Trap) {
WASM_EXEC_TEST(I64RemU) { WASM_EXEC_TEST(I64RemU) {
REQUIRE(I64RemU); REQUIRE(I64RemU);
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64()); WasmRunner<uint64_t> r(execution_mode, MachineType::Uint64(),
MachineType::Uint64());
BUILD(r, WASM_I64_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) { FOR_UINT64_INPUTS(j) {
...@@ -266,7 +275,8 @@ WASM_EXEC_TEST(I64RemU) { ...@@ -266,7 +275,8 @@ WASM_EXEC_TEST(I64RemU) {
WASM_EXEC_TEST(I64RemU_Trap) { WASM_EXEC_TEST(I64RemU_Trap) {
REQUIRE(I64RemU); REQUIRE(I64RemU);
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64()); WasmRunner<uint64_t> r(execution_mode, MachineType::Uint64(),
MachineType::Uint64());
BUILD(r, WASM_I64_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(17, r.Call(asu64(217), asu64(100))); CHECK_EQ(17, r.Call(asu64(217), asu64(100)));
CHECK_TRAP64(r.Call(asu64(100), asu64(0))); CHECK_TRAP64(r.Call(asu64(100), asu64(0)));
...@@ -276,7 +286,8 @@ WASM_EXEC_TEST(I64RemU_Trap) { ...@@ -276,7 +286,8 @@ WASM_EXEC_TEST(I64RemU_Trap) {
WASM_EXEC_TEST(I64And) { WASM_EXEC_TEST(I64And) {
REQUIRE(I64And); REQUIRE(I64And);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_AND(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_AND(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ((*i) & (*j), r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ((*i) & (*j), r.Call(*i, *j)); }
...@@ -285,7 +296,8 @@ WASM_EXEC_TEST(I64And) { ...@@ -285,7 +296,8 @@ WASM_EXEC_TEST(I64And) {
WASM_EXEC_TEST(I64Ior) { WASM_EXEC_TEST(I64Ior) {
REQUIRE(I64Ior); REQUIRE(I64Ior);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_IOR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_IOR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ((*i) | (*j), r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ((*i) | (*j), r.Call(*i, *j)); }
...@@ -294,7 +306,8 @@ WASM_EXEC_TEST(I64Ior) { ...@@ -294,7 +306,8 @@ WASM_EXEC_TEST(I64Ior) {
WASM_EXEC_TEST(I64Xor) { WASM_EXEC_TEST(I64Xor) {
REQUIRE(I64Xor); REQUIRE(I64Xor);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ((*i) ^ (*j), r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ((*i) ^ (*j), r.Call(*i, *j)); }
...@@ -304,7 +317,8 @@ WASM_EXEC_TEST(I64Xor) { ...@@ -304,7 +317,8 @@ WASM_EXEC_TEST(I64Xor) {
WASM_EXEC_TEST(I64Shl) { WASM_EXEC_TEST(I64Shl) {
REQUIRE(I64Shl); REQUIRE(I64Shl);
{ {
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64()); WasmRunner<uint64_t> r(execution_mode, MachineType::Uint64(),
MachineType::Uint64());
BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
...@@ -315,22 +329,22 @@ WASM_EXEC_TEST(I64Shl) { ...@@ -315,22 +329,22 @@ WASM_EXEC_TEST(I64Shl) {
} }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(0))); BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(0)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 0, r.Call(*i)); } FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 0, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(32))); BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(32)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 32, r.Call(*i)); } FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 32, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(20))); BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(20)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 20, r.Call(*i)); } FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 20, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(40))); BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(40)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 40, r.Call(*i)); } FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 40, r.Call(*i)); }
} }
...@@ -339,7 +353,8 @@ WASM_EXEC_TEST(I64Shl) { ...@@ -339,7 +353,8 @@ WASM_EXEC_TEST(I64Shl) {
WASM_EXEC_TEST(I64ShrU) { WASM_EXEC_TEST(I64ShrU) {
REQUIRE(I64ShrU); REQUIRE(I64ShrU);
{ {
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64()); WasmRunner<uint64_t> r(execution_mode, MachineType::Uint64(),
MachineType::Uint64());
BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
...@@ -350,22 +365,22 @@ WASM_EXEC_TEST(I64ShrU) { ...@@ -350,22 +365,22 @@ WASM_EXEC_TEST(I64ShrU) {
} }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(0))); BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(0)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 0, r.Call(*i)); } FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 0, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(32))); BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(32)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 32, r.Call(*i)); } FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 32, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(20))); BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(20)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 20, r.Call(*i)); } FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 20, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(40))); BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(40)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 40, r.Call(*i)); } FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 40, r.Call(*i)); }
} }
...@@ -374,7 +389,8 @@ WASM_EXEC_TEST(I64ShrU) { ...@@ -374,7 +389,8 @@ WASM_EXEC_TEST(I64ShrU) {
WASM_EXEC_TEST(I64ShrS) { WASM_EXEC_TEST(I64ShrS) {
REQUIRE(I64ShrS); REQUIRE(I64ShrS);
{ {
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
...@@ -385,22 +401,22 @@ WASM_EXEC_TEST(I64ShrS) { ...@@ -385,22 +401,22 @@ WASM_EXEC_TEST(I64ShrS) {
} }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(0))); BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(0)));
FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 0, r.Call(*i)); } FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 0, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(32))); BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(32)));
FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 32, r.Call(*i)); } FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 32, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(20))); BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(20)));
FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 20, r.Call(*i)); } FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 20, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(40))); BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(40)));
FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 40, r.Call(*i)); } FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 40, r.Call(*i)); }
} }
...@@ -408,7 +424,8 @@ WASM_EXEC_TEST(I64ShrS) { ...@@ -408,7 +424,8 @@ WASM_EXEC_TEST(I64ShrS) {
WASM_EXEC_TEST(I64Eq) { WASM_EXEC_TEST(I64Eq) {
REQUIRE(I64Eq); REQUIRE(I64Eq);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_EQ(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_EQ(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i == *j ? 1 : 0, r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ(*i == *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -417,7 +434,8 @@ WASM_EXEC_TEST(I64Eq) { ...@@ -417,7 +434,8 @@ WASM_EXEC_TEST(I64Eq) {
WASM_EXEC_TEST(I64Ne) { WASM_EXEC_TEST(I64Ne) {
REQUIRE(I64Ne); REQUIRE(I64Ne);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_NE(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_NE(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i != *j ? 1 : 0, r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ(*i != *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -426,7 +444,8 @@ WASM_EXEC_TEST(I64Ne) { ...@@ -426,7 +444,8 @@ WASM_EXEC_TEST(I64Ne) {
WASM_EXEC_TEST(I64LtS) { WASM_EXEC_TEST(I64LtS) {
REQUIRE(I64LtS); REQUIRE(I64LtS);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_LTS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_LTS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i < *j ? 1 : 0, r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ(*i < *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -435,7 +454,8 @@ WASM_EXEC_TEST(I64LtS) { ...@@ -435,7 +454,8 @@ WASM_EXEC_TEST(I64LtS) {
WASM_EXEC_TEST(I64LeS) { WASM_EXEC_TEST(I64LeS) {
REQUIRE(I64LeS); REQUIRE(I64LeS);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_LES(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_LES(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i <= *j ? 1 : 0, r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ(*i <= *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -444,7 +464,8 @@ WASM_EXEC_TEST(I64LeS) { ...@@ -444,7 +464,8 @@ WASM_EXEC_TEST(I64LeS) {
WASM_EXEC_TEST(I64LtU) { WASM_EXEC_TEST(I64LtU) {
REQUIRE(I64LtU); REQUIRE(I64LtU);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_LTU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_LTU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) { CHECK_EQ(*i < *j ? 1 : 0, r.Call(*i, *j)); } FOR_UINT64_INPUTS(j) { CHECK_EQ(*i < *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -453,7 +474,8 @@ WASM_EXEC_TEST(I64LtU) { ...@@ -453,7 +474,8 @@ WASM_EXEC_TEST(I64LtU) {
WASM_EXEC_TEST(I64LeU) { WASM_EXEC_TEST(I64LeU) {
REQUIRE(I64LeU); REQUIRE(I64LeU);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_LEU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_LEU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) { CHECK_EQ(*i <= *j ? 1 : 0, r.Call(*i, *j)); } FOR_UINT64_INPUTS(j) { CHECK_EQ(*i <= *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -462,7 +484,8 @@ WASM_EXEC_TEST(I64LeU) { ...@@ -462,7 +484,8 @@ WASM_EXEC_TEST(I64LeU) {
WASM_EXEC_TEST(I64GtS) { WASM_EXEC_TEST(I64GtS) {
REQUIRE(I64GtS); REQUIRE(I64GtS);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_GTS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_GTS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i > *j ? 1 : 0, r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ(*i > *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -471,7 +494,8 @@ WASM_EXEC_TEST(I64GtS) { ...@@ -471,7 +494,8 @@ WASM_EXEC_TEST(I64GtS) {
WASM_EXEC_TEST(I64GeS) { WASM_EXEC_TEST(I64GeS) {
REQUIRE(I64GeS); REQUIRE(I64GeS);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_GES(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_GES(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i >= *j ? 1 : 0, r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ(*i >= *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -480,7 +504,8 @@ WASM_EXEC_TEST(I64GeS) { ...@@ -480,7 +504,8 @@ WASM_EXEC_TEST(I64GeS) {
WASM_EXEC_TEST(I64GtU) { WASM_EXEC_TEST(I64GtU) {
REQUIRE(I64GtU); REQUIRE(I64GtU);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_GTU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_GTU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) { CHECK_EQ(*i > *j ? 1 : 0, r.Call(*i, *j)); } FOR_UINT64_INPUTS(j) { CHECK_EQ(*i > *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -489,7 +514,8 @@ WASM_EXEC_TEST(I64GtU) { ...@@ -489,7 +514,8 @@ WASM_EXEC_TEST(I64GtU) {
WASM_EXEC_TEST(I64GeU) { WASM_EXEC_TEST(I64GeU) {
REQUIRE(I64GeU); REQUIRE(I64GeU);
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_GEU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_GEU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) { CHECK_EQ(*i >= *j ? 1 : 0, r.Call(*i, *j)); } FOR_UINT64_INPUTS(j) { CHECK_EQ(*i >= *j ? 1 : 0, r.Call(*i, *j)); }
...@@ -499,7 +525,7 @@ WASM_EXEC_TEST(I64GeU) { ...@@ -499,7 +525,7 @@ WASM_EXEC_TEST(I64GeU) {
WASM_EXEC_TEST(I32ConvertI64) { WASM_EXEC_TEST(I32ConvertI64) {
REQUIRE(I32ConvertI64); REQUIRE(I32ConvertI64);
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
BUILD(r, WASM_I32_CONVERT_I64(WASM_I64V(*i))); BUILD(r, WASM_I32_CONVERT_I64(WASM_I64V(*i)));
CHECK_EQ(static_cast<int32_t>(*i), r.Call()); CHECK_EQ(static_cast<int32_t>(*i), r.Call());
} }
...@@ -507,14 +533,14 @@ WASM_EXEC_TEST(I32ConvertI64) { ...@@ -507,14 +533,14 @@ WASM_EXEC_TEST(I32ConvertI64) {
WASM_EXEC_TEST(I64SConvertI32) { WASM_EXEC_TEST(I64SConvertI32) {
REQUIRE(I64SConvertI32); REQUIRE(I64SConvertI32);
WasmRunner<int64_t> r(MachineType::Int32()); WasmRunner<int64_t> r(execution_mode, MachineType::Int32());
BUILD(r, WASM_I64_SCONVERT_I32(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_SCONVERT_I32(WASM_GET_LOCAL(0)));
FOR_INT32_INPUTS(i) { CHECK_EQ(static_cast<int64_t>(*i), r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(static_cast<int64_t>(*i), r.Call(*i)); }
} }
WASM_EXEC_TEST(I64UConvertI32) { WASM_EXEC_TEST(I64UConvertI32) {
REQUIRE(I64UConvertI32); REQUIRE(I64UConvertI32);
WasmRunner<int64_t> r(MachineType::Uint32()); WasmRunner<int64_t> r(execution_mode, MachineType::Uint32());
BUILD(r, WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(0)));
FOR_UINT32_INPUTS(i) { CHECK_EQ(static_cast<uint64_t>(*i), r.Call(*i)); } FOR_UINT32_INPUTS(i) { CHECK_EQ(static_cast<uint64_t>(*i), r.Call(*i)); }
} }
...@@ -529,7 +555,7 @@ WASM_EXEC_TEST(I64Popcnt) { ...@@ -529,7 +555,7 @@ WASM_EXEC_TEST(I64Popcnt) {
{26, 0x1123456782345678}, {26, 0x1123456782345678},
{38, 0xffedcba09edcba09}}; {38, 0xffedcba09edcba09}};
WasmRunner<int64_t> r(MachineType::Uint64()); WasmRunner<int64_t> r(execution_mode, MachineType::Uint64());
BUILD(r, WASM_I64_POPCNT(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_POPCNT(WASM_GET_LOCAL(0)));
for (size_t i = 0; i < arraysize(values); i++) { for (size_t i = 0; i < arraysize(values); i++) {
CHECK_EQ(values[i].expected, r.Call(values[i].input)); CHECK_EQ(values[i].expected, r.Call(values[i].input));
...@@ -538,7 +564,7 @@ WASM_EXEC_TEST(I64Popcnt) { ...@@ -538,7 +564,7 @@ WASM_EXEC_TEST(I64Popcnt) {
WASM_EXEC_TEST(F32SConvertI64) { WASM_EXEC_TEST(F32SConvertI64) {
REQUIRE(F32SConvertI64); REQUIRE(F32SConvertI64);
WasmRunner<float> r(MachineType::Int64()); WasmRunner<float> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_F32_SCONVERT_I64(WASM_GET_LOCAL(0))); BUILD(r, WASM_F32_SCONVERT_I64(WASM_GET_LOCAL(0)));
FOR_INT64_INPUTS(i) { CHECK_FLOAT_EQ(static_cast<float>(*i), r.Call(*i)); } FOR_INT64_INPUTS(i) { CHECK_FLOAT_EQ(static_cast<float>(*i), r.Call(*i)); }
} }
...@@ -624,7 +650,7 @@ WASM_EXEC_TEST(F32UConvertI64) { ...@@ -624,7 +650,7 @@ WASM_EXEC_TEST(F32UConvertI64) {
{0x8000008000000001, 0x5f000001}, {0x8000008000000001, 0x5f000001},
{0x8000000000000400, 0x5f000000}, {0x8000000000000400, 0x5f000000},
{0x8000000000000401, 0x5f000000}}; {0x8000000000000401, 0x5f000000}};
WasmRunner<float> r(MachineType::Uint64()); WasmRunner<float> r(execution_mode, MachineType::Uint64());
BUILD(r, WASM_F32_UCONVERT_I64(WASM_GET_LOCAL(0))); BUILD(r, WASM_F32_UCONVERT_I64(WASM_GET_LOCAL(0)));
for (size_t i = 0; i < arraysize(values); i++) { for (size_t i = 0; i < arraysize(values); i++) {
CHECK_EQ(bit_cast<float>(values[i].expected), r.Call(values[i].input)); CHECK_EQ(bit_cast<float>(values[i].expected), r.Call(values[i].input));
...@@ -633,7 +659,7 @@ WASM_EXEC_TEST(F32UConvertI64) { ...@@ -633,7 +659,7 @@ WASM_EXEC_TEST(F32UConvertI64) {
WASM_EXEC_TEST(F64SConvertI64) { WASM_EXEC_TEST(F64SConvertI64) {
REQUIRE(F64SConvertI64); REQUIRE(F64SConvertI64);
WasmRunner<double> r(MachineType::Int64()); WasmRunner<double> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_F64_SCONVERT_I64(WASM_GET_LOCAL(0))); BUILD(r, WASM_F64_SCONVERT_I64(WASM_GET_LOCAL(0)));
FOR_INT64_INPUTS(i) { CHECK_DOUBLE_EQ(static_cast<double>(*i), r.Call(*i)); } FOR_INT64_INPUTS(i) { CHECK_DOUBLE_EQ(static_cast<double>(*i), r.Call(*i)); }
} }
...@@ -718,7 +744,7 @@ WASM_EXEC_TEST(F64UConvertI64) { ...@@ -718,7 +744,7 @@ WASM_EXEC_TEST(F64UConvertI64) {
{0x8000008000000001, 0x43e0000010000000}, {0x8000008000000001, 0x43e0000010000000},
{0x8000000000000400, 0x43e0000000000000}, {0x8000000000000400, 0x43e0000000000000},
{0x8000000000000401, 0x43e0000000000001}}; {0x8000000000000401, 0x43e0000000000001}};
WasmRunner<double> r(MachineType::Uint64()); WasmRunner<double> r(execution_mode, MachineType::Uint64());
BUILD(r, WASM_F64_UCONVERT_I64(WASM_GET_LOCAL(0))); BUILD(r, WASM_F64_UCONVERT_I64(WASM_GET_LOCAL(0)));
for (size_t i = 0; i < arraysize(values); i++) { for (size_t i = 0; i < arraysize(values); i++) {
CHECK_EQ(bit_cast<double>(values[i].expected), r.Call(values[i].input)); CHECK_EQ(bit_cast<double>(values[i].expected), r.Call(values[i].input));
...@@ -726,7 +752,7 @@ WASM_EXEC_TEST(F64UConvertI64) { ...@@ -726,7 +752,7 @@ WASM_EXEC_TEST(F64UConvertI64) {
} }
WASM_EXEC_TEST(I64SConvertF32a) { WASM_EXEC_TEST(I64SConvertF32a) {
WasmRunner<int64_t> r(MachineType::Float32()); WasmRunner<int64_t> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_I64_SCONVERT_F32(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_SCONVERT_F32(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -740,7 +766,7 @@ WASM_EXEC_TEST(I64SConvertF32a) { ...@@ -740,7 +766,7 @@ WASM_EXEC_TEST(I64SConvertF32a) {
} }
WASM_EXEC_TEST(I64SConvertF64a) { WASM_EXEC_TEST(I64SConvertF64a) {
WasmRunner<int64_t> r(MachineType::Float64()); WasmRunner<int64_t> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -754,7 +780,7 @@ WASM_EXEC_TEST(I64SConvertF64a) { ...@@ -754,7 +780,7 @@ WASM_EXEC_TEST(I64SConvertF64a) {
} }
WASM_EXEC_TEST(I64UConvertF32a) { WASM_EXEC_TEST(I64UConvertF32a) {
WasmRunner<uint64_t> r(MachineType::Float32()); WasmRunner<uint64_t> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_I64_UCONVERT_F32(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_UCONVERT_F32(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -768,7 +794,7 @@ WASM_EXEC_TEST(I64UConvertF32a) { ...@@ -768,7 +794,7 @@ WASM_EXEC_TEST(I64UConvertF32a) {
} }
WASM_EXEC_TEST(I64UConvertF64a) { WASM_EXEC_TEST(I64UConvertF64a) {
WasmRunner<uint64_t> r(MachineType::Float64()); WasmRunner<uint64_t> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_I64_UCONVERT_F64(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_UCONVERT_F64(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -789,7 +815,7 @@ WASM_EXEC_TEST(CallI64Parameter) { ...@@ -789,7 +815,7 @@ WASM_EXEC_TEST(CallI64Parameter) {
param_types[4] = kAstI32; param_types[4] = kAstI32;
FunctionSig sig(1, 19, param_types); FunctionSig sig(1, 19, param_types);
for (int i = 0; i < 19; i++) { for (int i = 0; i < 19; i++) {
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t(&sig, &module); WasmFunctionCompiler t(&sig, &module);
if (i == 2 || i == 3) { if (i == 2 || i == 3) {
continue; continue;
...@@ -819,40 +845,44 @@ WASM_EXEC_TEST(CallI64Parameter) { ...@@ -819,40 +845,44 @@ WASM_EXEC_TEST(CallI64Parameter) {
} }
} }
void TestI64Binop(WasmOpcode opcode, int64_t expected, int64_t a, int64_t b) { void TestI64Binop(WasmExecutionMode execution_mode, WasmOpcode opcode,
int64_t expected, int64_t a, int64_t b) {
{ {
WasmRunner<int64_t> r; WasmRunner<int64_t> r(execution_mode);
// return K op K // return K op K
BUILD(r, WASM_BINOP(opcode, WASM_I64V(a), WASM_I64V(b))); BUILD(r, WASM_BINOP(opcode, WASM_I64V(a), WASM_I64V(b)));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
// return a op b // return a op b
BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(expected, r.Call(a, b)); CHECK_EQ(expected, r.Call(a, b));
} }
} }
void TestI64Cmp(WasmOpcode opcode, int64_t expected, int64_t a, int64_t b) { void TestI64Cmp(WasmExecutionMode execution_mode, WasmOpcode opcode,
int64_t expected, int64_t a, int64_t b) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return K op K // return K op K
BUILD(r, WASM_BINOP(opcode, WASM_I64V(a), WASM_I64V(b))); BUILD(r, WASM_BINOP(opcode, WASM_I64V(a), WASM_I64V(b)));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int32_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
// return a op b // return a op b
BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(expected, r.Call(a, b)); CHECK_EQ(expected, r.Call(a, b));
} }
} }
#define TEST_I64_BINOP(name, expected, a, b) \ #define TEST_I64_BINOP(name, expected, a, b) \
do { \ do { \
if (WASM_64 || kSupported_##name) \ if (WASM_64 || kSupported_##name) \
TestI64Binop(kExpr##name, expected, a, b); \ TestI64Binop(execution_mode, kExpr##name, expected, a, b); \
} while (false) } while (false)
WASM_EXEC_TEST(I64Binops) { WASM_EXEC_TEST(I64Binops) {
...@@ -887,9 +917,10 @@ WASM_EXEC_TEST(I64Binops) { ...@@ -887,9 +917,10 @@ WASM_EXEC_TEST(I64Binops) {
TEST_I64_BINOP(I64Rol, 8728493013947314237, 0xe07af243ac4d219d, 15); TEST_I64_BINOP(I64Rol, 8728493013947314237, 0xe07af243ac4d219d, 15);
} }
#define TEST_I64_CMP(name, expected, a, b) \ #define TEST_I64_CMP(name, expected, a, b) \
do { \ do { \
if (WASM_64 || kSupported_##name) TestI64Cmp(kExpr##name, expected, a, b); \ if (WASM_64 || kSupported_##name) \
TestI64Cmp(execution_mode, kExpr##name, expected, a, b); \
} while (false) } while (false)
WASM_EXEC_TEST(I64Compare) { WASM_EXEC_TEST(I64Compare) {
...@@ -944,7 +975,7 @@ WASM_EXEC_TEST(I64Clz) { ...@@ -944,7 +975,7 @@ WASM_EXEC_TEST(I64Clz) {
{62, 0x0000000000000002}, {63, 0x0000000000000001}, {62, 0x0000000000000002}, {63, 0x0000000000000001},
{64, 0x0000000000000000}}; {64, 0x0000000000000000}};
WasmRunner<int64_t> r(MachineType::Uint64()); WasmRunner<int64_t> r(execution_mode, MachineType::Uint64());
BUILD(r, WASM_I64_CLZ(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_CLZ(WASM_GET_LOCAL(0)));
for (size_t i = 0; i < arraysize(values); i++) { for (size_t i = 0; i < arraysize(values); i++) {
CHECK_EQ(values[i].expected, r.Call(values[i].input)); CHECK_EQ(values[i].expected, r.Call(values[i].input));
...@@ -990,7 +1021,7 @@ WASM_EXEC_TEST(I64Ctz) { ...@@ -990,7 +1021,7 @@ WASM_EXEC_TEST(I64Ctz) {
{2, 0x000000009afdbc84}, {1, 0x000000009afdbc82}, {2, 0x000000009afdbc84}, {1, 0x000000009afdbc82},
{0, 0x000000009afdbc81}}; {0, 0x000000009afdbc81}};
WasmRunner<int64_t> r(MachineType::Uint64()); WasmRunner<int64_t> r(execution_mode, MachineType::Uint64());
BUILD(r, WASM_I64_CTZ(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_CTZ(WASM_GET_LOCAL(0)));
for (size_t i = 0; i < arraysize(values); i++) { for (size_t i = 0; i < arraysize(values); i++) {
CHECK_EQ(values[i].expected, r.Call(values[i].input)); CHECK_EQ(values[i].expected, r.Call(values[i].input));
...@@ -1008,7 +1039,7 @@ WASM_EXEC_TEST(I64Popcnt2) { ...@@ -1008,7 +1039,7 @@ WASM_EXEC_TEST(I64Popcnt2) {
{26, 0x1123456782345678}, {26, 0x1123456782345678},
{38, 0xffedcba09edcba09}}; {38, 0xffedcba09edcba09}};
WasmRunner<int64_t> r(MachineType::Uint64()); WasmRunner<int64_t> r(execution_mode, MachineType::Uint64());
BUILD(r, WASM_I64_POPCNT(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_POPCNT(WASM_GET_LOCAL(0)));
for (size_t i = 0; i < arraysize(values); i++) { for (size_t i = 0; i < arraysize(values); i++) {
CHECK_EQ(values[i].expected, r.Call(values[i].input)); CHECK_EQ(values[i].expected, r.Call(values[i].input));
...@@ -1017,29 +1048,30 @@ WASM_EXEC_TEST(I64Popcnt2) { ...@@ -1017,29 +1048,30 @@ WASM_EXEC_TEST(I64Popcnt2) {
// Test the WasmRunner with an Int64 return value and different numbers of // Test the WasmRunner with an Int64 return value and different numbers of
// Int64 parameters. // Int64 parameters.
TEST(Run_TestI64WasmRunner) { WASM_EXEC_TEST(I64WasmRunner) {
REQUIRE(I64Param); REQUIRE(I64Param);
REQUIRE(I64Xor); REQUIRE(I64Xor);
{FOR_INT64_INPUTS(i){WasmRunner<int64_t> r; {FOR_INT64_INPUTS(i){WasmRunner<int64_t> r(execution_mode);
BUILD(r, WASM_I64V(*i)); BUILD(r, WASM_I64V(*i));
CHECK_EQ(*i, r.Call()); CHECK_EQ(*i, r.Call());
} }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_GET_LOCAL(0)); BUILD(r, WASM_GET_LOCAL(0));
FOR_INT64_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_INT64_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i ^ *j, r.Call(*i, *j)); } FOR_INT64_INPUTS(j) { CHECK_EQ(*i ^ *j, r.Call(*i, *j)); }
} }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64(), WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64()); MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0),
WASM_I64_XOR(WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)))); WASM_I64_XOR(WASM_GET_LOCAL(1), WASM_GET_LOCAL(2))));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
...@@ -1051,8 +1083,9 @@ TEST(Run_TestI64WasmRunner) { ...@@ -1051,8 +1083,9 @@ TEST(Run_TestI64WasmRunner) {
} }
} }
{ {
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64(), WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64(), MachineType::Int64()); MachineType::Int64(), MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0),
WASM_I64_XOR(WASM_GET_LOCAL(1), WASM_I64_XOR(WASM_GET_LOCAL(1),
WASM_I64_XOR(WASM_GET_LOCAL(2), WASM_I64_XOR(WASM_GET_LOCAL(2),
...@@ -1072,7 +1105,7 @@ WASM_EXEC_TEST(Call_Int64Sub) { ...@@ -1072,7 +1105,7 @@ WASM_EXEC_TEST(Call_Int64Sub) {
REQUIRE(I64Sub); REQUIRE(I64Sub);
// Build the target function. // Build the target function.
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t(sigs.l_ll(), &module); WasmFunctionCompiler t(sigs.l_ll(), &module);
BUILD(t, WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(t, WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
uint32_t index = t.CompileAndAdd(); uint32_t index = t.CompileAndAdd();
...@@ -1102,7 +1135,7 @@ WASM_EXEC_TEST(LoadStoreI64_sx) { ...@@ -1102,7 +1135,7 @@ WASM_EXEC_TEST(LoadStoreI64_sx) {
kExprI64LoadMem}; kExprI64LoadMem};
for (size_t m = 0; m < arraysize(loads); m++) { for (size_t m = 0; m < arraysize(loads); m++) {
TestingModule module; TestingModule module(execution_mode);
byte* memory = module.AddMemoryElems<byte>(16); byte* memory = module.AddMemoryElems<byte>(16);
WasmRunner<int64_t> r(&module); WasmRunner<int64_t> r(&module);
...@@ -1138,7 +1171,7 @@ WASM_EXEC_TEST(LoadStoreI64_sx) { ...@@ -1138,7 +1171,7 @@ WASM_EXEC_TEST(LoadStoreI64_sx) {
WASM_EXEC_TEST(I64SConvertF32b) { WASM_EXEC_TEST(I64SConvertF32b) {
REQUIRE(I64SConvertF32); REQUIRE(I64SConvertF32);
WasmRunner<int64_t> r(MachineType::Float32()); WasmRunner<int64_t> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_I64_SCONVERT_F32(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_SCONVERT_F32(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -1153,7 +1186,7 @@ WASM_EXEC_TEST(I64SConvertF32b) { ...@@ -1153,7 +1186,7 @@ WASM_EXEC_TEST(I64SConvertF32b) {
WASM_EXEC_TEST(I64SConvertF64b) { WASM_EXEC_TEST(I64SConvertF64b) {
REQUIRE(I64SConvertF64); REQUIRE(I64SConvertF64);
WasmRunner<int64_t> r(MachineType::Float64()); WasmRunner<int64_t> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -1168,7 +1201,7 @@ WASM_EXEC_TEST(I64SConvertF64b) { ...@@ -1168,7 +1201,7 @@ WASM_EXEC_TEST(I64SConvertF64b) {
WASM_EXEC_TEST(I64UConvertF32b) { WASM_EXEC_TEST(I64UConvertF32b) {
REQUIRE(I64UConvertF32); REQUIRE(I64UConvertF32);
WasmRunner<uint64_t> r(MachineType::Float32()); WasmRunner<uint64_t> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_I64_UCONVERT_F32(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_UCONVERT_F32(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -1182,7 +1215,7 @@ WASM_EXEC_TEST(I64UConvertF32b) { ...@@ -1182,7 +1215,7 @@ WASM_EXEC_TEST(I64UConvertF32b) {
WASM_EXEC_TEST(I64UConvertF64b) { WASM_EXEC_TEST(I64UConvertF64b) {
REQUIRE(I64UConvertF64); REQUIRE(I64UConvertF64);
WasmRunner<uint64_t> r(MachineType::Float64()); WasmRunner<uint64_t> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_I64_UCONVERT_F64(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_UCONVERT_F64(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -1196,7 +1229,7 @@ WASM_EXEC_TEST(I64UConvertF64b) { ...@@ -1196,7 +1229,7 @@ WASM_EXEC_TEST(I64UConvertF64b) {
WASM_EXEC_TEST(I64ReinterpretF64) { WASM_EXEC_TEST(I64ReinterpretF64) {
REQUIRE(I64ReinterpretF64); REQUIRE(I64ReinterpretF64);
TestingModule module; TestingModule module(execution_mode);
int64_t* memory = module.AddMemoryElems<int64_t>(8); int64_t* memory = module.AddMemoryElems<int64_t>(8);
WasmRunner<int64_t> r(&module); WasmRunner<int64_t> r(&module);
...@@ -1212,7 +1245,7 @@ WASM_EXEC_TEST(I64ReinterpretF64) { ...@@ -1212,7 +1245,7 @@ WASM_EXEC_TEST(I64ReinterpretF64) {
WASM_EXEC_TEST(F64ReinterpretI64) { WASM_EXEC_TEST(F64ReinterpretI64) {
REQUIRE(F64ReinterpretI64); REQUIRE(F64ReinterpretI64);
TestingModule module; TestingModule module(execution_mode);
int64_t* memory = module.AddMemoryElems<int64_t>(8); int64_t* memory = module.AddMemoryElems<int64_t>(8);
WasmRunner<int64_t> r(&module, MachineType::Int64()); WasmRunner<int64_t> r(&module, MachineType::Int64());
...@@ -1230,7 +1263,7 @@ WASM_EXEC_TEST(F64ReinterpretI64) { ...@@ -1230,7 +1263,7 @@ WASM_EXEC_TEST(F64ReinterpretI64) {
WASM_EXEC_TEST(LoadMemI64) { WASM_EXEC_TEST(LoadMemI64) {
REQUIRE(I64LoadStore); REQUIRE(I64LoadStore);
TestingModule module; TestingModule module(execution_mode);
int64_t* memory = module.AddMemoryElems<int64_t>(8); int64_t* memory = module.AddMemoryElems<int64_t>(8);
module.RandomizeMemory(1111); module.RandomizeMemory(1111);
WasmRunner<int64_t> r(&module); WasmRunner<int64_t> r(&module);
...@@ -1247,9 +1280,9 @@ WASM_EXEC_TEST(LoadMemI64) { ...@@ -1247,9 +1280,9 @@ WASM_EXEC_TEST(LoadMemI64) {
CHECK_EQ(77777777, r.Call()); CHECK_EQ(77777777, r.Call());
} }
WASM_EXEC_TEST(Run_Wasm_LoadMemI64_alignment) { WASM_EXEC_TEST(LoadMemI64_alignment) {
REQUIRE(I64LoadStore); REQUIRE(I64LoadStore);
TestingModule module; TestingModule module(execution_mode);
int64_t* memory = module.AddMemoryElems<int64_t>(8); int64_t* memory = module.AddMemoryElems<int64_t>(8);
for (byte alignment = 0; alignment <= 3; alignment++) { for (byte alignment = 0; alignment <= 3; alignment++) {
module.RandomizeMemory(1111); module.RandomizeMemory(1111);
...@@ -1269,13 +1302,13 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI64_alignment) { ...@@ -1269,13 +1302,13 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI64_alignment) {
} }
} }
WASM_EXEC_TEST(Run_Wasm_MemI64_Sum) { WASM_EXEC_TEST(MemI64_Sum) {
REQUIRE(I64LoadStore); REQUIRE(I64LoadStore);
REQUIRE(I64Add); REQUIRE(I64Add);
REQUIRE(I64Sub); REQUIRE(I64Sub);
REQUIRE(I64Phi); REQUIRE(I64Phi);
const int kNumElems = 20; const int kNumElems = 20;
TestingModule module; TestingModule module(execution_mode);
uint64_t* memory = module.AddMemoryElems<uint64_t>(kNumElems); uint64_t* memory = module.AddMemoryElems<uint64_t>(kNumElems);
WasmRunner<uint64_t> r(&module, MachineType::Int32()); WasmRunner<uint64_t> r(&module, MachineType::Int32());
const byte kSum = r.AllocateLocal(kAstI64); const byte kSum = r.AllocateLocal(kAstI64);
...@@ -1305,8 +1338,8 @@ WASM_EXEC_TEST(Run_Wasm_MemI64_Sum) { ...@@ -1305,8 +1338,8 @@ WASM_EXEC_TEST(Run_Wasm_MemI64_Sum) {
} }
} }
WASM_EXEC_TEST(Run_Wasm_StoreMemI64_alignment) { WASM_EXEC_TEST(StoreMemI64_alignment) {
TestingModule module; TestingModule module(execution_mode);
int64_t* memory = module.AddMemoryElems<int64_t>(4); int64_t* memory = module.AddMemoryElems<int64_t>(4);
const int64_t kWritten = 0x12345678abcd0011ll; const int64_t kWritten = 0x12345678abcd0011ll;
...@@ -1322,12 +1355,12 @@ WASM_EXEC_TEST(Run_Wasm_StoreMemI64_alignment) { ...@@ -1322,12 +1355,12 @@ WASM_EXEC_TEST(Run_Wasm_StoreMemI64_alignment) {
} }
} }
WASM_EXEC_TEST(Run_Wasm_I64Global) { WASM_EXEC_TEST(I64Global) {
REQUIRE(I64LoadStore); REQUIRE(I64LoadStore);
REQUIRE(I64SConvertI32); REQUIRE(I64SConvertI32);
REQUIRE(I64And); REQUIRE(I64And);
REQUIRE(DepthFirst); REQUIRE(DepthFirst);
TestingModule module; TestingModule module(execution_mode);
int64_t* global = module.AddGlobal<int64_t>(MachineType::Int64()); int64_t* global = module.AddGlobal<int64_t>(MachineType::Int64());
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
// global = global + p0 // global = global + p0
...@@ -1347,7 +1380,7 @@ WASM_EXEC_TEST(Run_Wasm_I64Global) { ...@@ -1347,7 +1380,7 @@ WASM_EXEC_TEST(Run_Wasm_I64Global) {
WASM_EXEC_TEST(I64Eqz) { WASM_EXEC_TEST(I64Eqz) {
REQUIRE(I64Eq); REQUIRE(I64Eq);
WasmRunner<int32_t> r(MachineType::Int64()); WasmRunner<int32_t> r(execution_mode, MachineType::Int64());
BUILD(r, WASM_I64_EQZ(WASM_GET_LOCAL(0))); BUILD(r, WASM_I64_EQZ(WASM_GET_LOCAL(0)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
...@@ -1358,7 +1391,8 @@ WASM_EXEC_TEST(I64Eqz) { ...@@ -1358,7 +1391,8 @@ WASM_EXEC_TEST(I64Eqz) {
WASM_EXEC_TEST(I64Ror) { WASM_EXEC_TEST(I64Ror) {
REQUIRE(I64Ror); REQUIRE(I64Ror);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_ROR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_ROR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
...@@ -1371,7 +1405,8 @@ WASM_EXEC_TEST(I64Ror) { ...@@ -1371,7 +1405,8 @@ WASM_EXEC_TEST(I64Ror) {
WASM_EXEC_TEST(I64Rol) { WASM_EXEC_TEST(I64Rol) {
REQUIRE(I64Rol); REQUIRE(I64Rol);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I64_ROL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I64_ROL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) { FOR_UINT64_INPUTS(i) {
......
...@@ -27,7 +27,8 @@ using namespace v8::internal::wasm; ...@@ -27,7 +27,8 @@ using namespace v8::internal::wasm;
#define RET_I8(x) kExprI8Const, x, kExprReturn, 1 #define RET_I8(x) kExprI8Const, x, kExprReturn, 1
WASM_EXEC_TEST(Int32AsmjsDivS) { WASM_EXEC_TEST(Int32AsmjsDivS) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_BINOP(kExprI32AsmjsDivS, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_BINOP(kExprI32AsmjsDivS, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min(); const int32_t kMin = std::numeric_limits<int32_t>::min();
CHECK_EQ(0, r.Call(0, 100)); CHECK_EQ(0, r.Call(0, 100));
...@@ -38,7 +39,8 @@ WASM_EXEC_TEST(Int32AsmjsDivS) { ...@@ -38,7 +39,8 @@ WASM_EXEC_TEST(Int32AsmjsDivS) {
} }
WASM_EXEC_TEST(Int32AsmjsRemS) { WASM_EXEC_TEST(Int32AsmjsRemS) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_BINOP(kExprI32AsmjsRemS, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_BINOP(kExprI32AsmjsRemS, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min(); const int32_t kMin = std::numeric_limits<int32_t>::min();
CHECK_EQ(33, r.Call(133, 100)); CHECK_EQ(33, r.Call(133, 100));
...@@ -49,7 +51,8 @@ WASM_EXEC_TEST(Int32AsmjsRemS) { ...@@ -49,7 +51,8 @@ WASM_EXEC_TEST(Int32AsmjsRemS) {
} }
WASM_EXEC_TEST(Int32AsmjsDivU) { WASM_EXEC_TEST(Int32AsmjsDivU) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_BINOP(kExprI32AsmjsDivU, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_BINOP(kExprI32AsmjsDivU, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min(); const int32_t kMin = std::numeric_limits<int32_t>::min();
CHECK_EQ(0, r.Call(0, 100)); CHECK_EQ(0, r.Call(0, 100));
...@@ -60,7 +63,8 @@ WASM_EXEC_TEST(Int32AsmjsDivU) { ...@@ -60,7 +63,8 @@ WASM_EXEC_TEST(Int32AsmjsDivU) {
} }
WASM_EXEC_TEST(Int32AsmjsRemU) { WASM_EXEC_TEST(Int32AsmjsRemU) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_BINOP(kExprI32AsmjsRemU, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_BINOP(kExprI32AsmjsRemU, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min(); const int32_t kMin = std::numeric_limits<int32_t>::min();
CHECK_EQ(17, r.Call(217, 100)); CHECK_EQ(17, r.Call(217, 100));
...@@ -71,7 +75,7 @@ WASM_EXEC_TEST(Int32AsmjsRemU) { ...@@ -71,7 +75,7 @@ WASM_EXEC_TEST(Int32AsmjsRemU) {
} }
WASM_EXEC_TEST(I32AsmjsSConvertF32) { WASM_EXEC_TEST(I32AsmjsSConvertF32) {
WasmRunner<int32_t> r(MachineType::Float32()); WasmRunner<int32_t> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_UNOP(kExprI32AsmjsSConvertF32, WASM_GET_LOCAL(0))); BUILD(r, WASM_UNOP(kExprI32AsmjsSConvertF32, WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -81,7 +85,7 @@ WASM_EXEC_TEST(I32AsmjsSConvertF32) { ...@@ -81,7 +85,7 @@ WASM_EXEC_TEST(I32AsmjsSConvertF32) {
} }
WASM_EXEC_TEST(I32AsmjsSConvertF64) { WASM_EXEC_TEST(I32AsmjsSConvertF64) {
WasmRunner<int32_t> r(MachineType::Float64()); WasmRunner<int32_t> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_UNOP(kExprI32AsmjsSConvertF64, WASM_GET_LOCAL(0))); BUILD(r, WASM_UNOP(kExprI32AsmjsSConvertF64, WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -91,7 +95,7 @@ WASM_EXEC_TEST(I32AsmjsSConvertF64) { ...@@ -91,7 +95,7 @@ WASM_EXEC_TEST(I32AsmjsSConvertF64) {
} }
WASM_EXEC_TEST(I32AsmjsUConvertF32) { WASM_EXEC_TEST(I32AsmjsUConvertF32) {
WasmRunner<uint32_t> r(MachineType::Float32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_UNOP(kExprI32AsmjsUConvertF32, WASM_GET_LOCAL(0))); BUILD(r, WASM_UNOP(kExprI32AsmjsUConvertF32, WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -101,7 +105,7 @@ WASM_EXEC_TEST(I32AsmjsUConvertF32) { ...@@ -101,7 +105,7 @@ WASM_EXEC_TEST(I32AsmjsUConvertF32) {
} }
WASM_EXEC_TEST(I32AsmjsUConvertF64) { WASM_EXEC_TEST(I32AsmjsUConvertF64) {
WasmRunner<uint32_t> r(MachineType::Float64()); WasmRunner<uint32_t> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_UNOP(kExprI32AsmjsUConvertF64, WASM_GET_LOCAL(0))); BUILD(r, WASM_UNOP(kExprI32AsmjsUConvertF64, WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -111,7 +115,7 @@ WASM_EXEC_TEST(I32AsmjsUConvertF64) { ...@@ -111,7 +115,7 @@ WASM_EXEC_TEST(I32AsmjsUConvertF64) {
} }
WASM_EXEC_TEST(LoadMemI32_oob_asm) { WASM_EXEC_TEST(LoadMemI32_oob_asm) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(8); int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module, MachineType::Uint32()); WasmRunner<int32_t> r(&module, MachineType::Uint32());
module.RandomizeMemory(1112); module.RandomizeMemory(1112);
...@@ -131,7 +135,7 @@ WASM_EXEC_TEST(LoadMemI32_oob_asm) { ...@@ -131,7 +135,7 @@ WASM_EXEC_TEST(LoadMemI32_oob_asm) {
} }
WASM_EXEC_TEST(LoadMemF32_oob_asm) { WASM_EXEC_TEST(LoadMemF32_oob_asm) {
TestingModule module; TestingModule module(execution_mode);
float* memory = module.AddMemoryElems<float>(8); float* memory = module.AddMemoryElems<float>(8);
WasmRunner<float> r(&module, MachineType::Uint32()); WasmRunner<float> r(&module, MachineType::Uint32());
module.RandomizeMemory(1112); module.RandomizeMemory(1112);
...@@ -151,7 +155,7 @@ WASM_EXEC_TEST(LoadMemF32_oob_asm) { ...@@ -151,7 +155,7 @@ WASM_EXEC_TEST(LoadMemF32_oob_asm) {
} }
WASM_EXEC_TEST(LoadMemF64_oob_asm) { WASM_EXEC_TEST(LoadMemF64_oob_asm) {
TestingModule module; TestingModule module(execution_mode);
double* memory = module.AddMemoryElems<double>(8); double* memory = module.AddMemoryElems<double>(8);
WasmRunner<double> r(&module, MachineType::Uint32()); WasmRunner<double> r(&module, MachineType::Uint32());
module.RandomizeMemory(1112); module.RandomizeMemory(1112);
...@@ -173,7 +177,7 @@ WASM_EXEC_TEST(LoadMemF64_oob_asm) { ...@@ -173,7 +177,7 @@ WASM_EXEC_TEST(LoadMemF64_oob_asm) {
} }
WASM_EXEC_TEST(StoreMemI32_oob_asm) { WASM_EXEC_TEST(StoreMemI32_oob_asm) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(8); int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module, MachineType::Uint32(), MachineType::Uint32()); WasmRunner<int32_t> r(&module, MachineType::Uint32(), MachineType::Uint32());
module.RandomizeMemory(1112); module.RandomizeMemory(1112);
......
// Copyright 2016 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.
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "src/wasm/wasm-macro-gen.h"
#include "src/wasm/wasm-interpreter.h"
#include "test/cctest/cctest.h"
#include "test/cctest/compiler/value-helper.h"
#include "test/cctest/wasm/test-signatures.h"
#include "test/cctest/wasm/wasm-run-utils.h"
using namespace v8::base;
using namespace v8::internal;
using namespace v8::internal::compiler;
using namespace v8::internal::wasm;
namespace v8 {
namespace internal {
namespace wasm {
TEST(Run_WasmInt8Const_i) {
WasmRunner<int32_t> r(kExecuteInterpreted);
const byte kExpectedValue = 109;
// return(kExpectedValue)
BUILD(r, WASM_I8(kExpectedValue));
CHECK_EQ(kExpectedValue, r.Call());
}
TEST(Run_WasmIfElse) {
WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Int32());
BUILD(r, WASM_IF_ELSE(WASM_GET_LOCAL(0), WASM_I8(9), WASM_I8(10)));
CHECK_EQ(10, r.Call(0));
CHECK_EQ(9, r.Call(1));
}
TEST(Run_WasmIfReturn) {
WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Int32());
BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_RETURN1(WASM_I8(77))), WASM_I8(65));
CHECK_EQ(65, r.Call(0));
CHECK_EQ(77, r.Call(1));
}
TEST(Run_WasmNopsN) {
const int kMaxNops = 10;
byte code[kMaxNops + 2];
for (int nops = 0; nops < kMaxNops; nops++) {
byte expected = static_cast<byte>(20 + nops);
memset(code, kExprNop, sizeof(code));
code[nops] = kExprI8Const;
code[nops + 1] = expected;
WasmRunner<int32_t> r(kExecuteInterpreted);
r.Build(code, code + nops + 2);
CHECK_EQ(expected, r.Call());
}
}
TEST(Run_WasmConstsN) {
const int kMaxConsts = 10;
byte code[kMaxConsts * 2];
for (int count = 1; count < kMaxConsts; count++) {
for (int i = 0; i < count; i++) {
code[i * 2] = kExprI8Const;
code[i * 2 + 1] = static_cast<byte>(count * 10 + i);
}
byte expected = static_cast<byte>(count * 11 - 1);
WasmRunner<int32_t> r(kExecuteInterpreted);
r.Build(code, code + (count * 2));
CHECK_EQ(expected, r.Call());
}
}
TEST(Run_WasmBlocksN) {
const int kMaxNops = 10;
const int kExtra = 4;
byte code[kMaxNops + kExtra];
for (int nops = 0; nops < kMaxNops; nops++) {
byte expected = static_cast<byte>(30 + nops);
memset(code, kExprNop, sizeof(code));
code[0] = kExprBlock;
code[1 + nops] = kExprI8Const;
code[1 + nops + 1] = expected;
code[1 + nops + 2] = kExprEnd;
WasmRunner<int32_t> r(kExecuteInterpreted);
r.Build(code, code + nops + kExtra);
CHECK_EQ(expected, r.Call());
}
}
TEST(Run_WasmBlockBreakN) {
const int kMaxNops = 10;
const int kExtra = 6;
byte code[kMaxNops + kExtra];
for (int nops = 0; nops < kMaxNops; nops++) {
// Place the break anywhere within the block.
for (int index = 0; index < nops; index++) {
memset(code, kExprNop, sizeof(code));
code[0] = kExprBlock;
code[sizeof(code) - 1] = kExprEnd;
int expected = nops * 11 + index;
code[1 + index + 0] = kExprI8Const;
code[1 + index + 1] = static_cast<byte>(expected);
code[1 + index + 2] = kExprBr;
code[1 + index + 3] = ARITY_1;
code[1 + index + 4] = 0;
WasmRunner<int32_t> r(kExecuteInterpreted);
r.Build(code, code + kMaxNops + kExtra);
CHECK_EQ(expected, r.Call());
}
}
}
TEST(Run_Wasm_nested_ifs_i) {
WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_IF_ELSE(
WASM_GET_LOCAL(0),
WASM_IF_ELSE(WASM_GET_LOCAL(1), WASM_I8(11), WASM_I8(12)),
WASM_IF_ELSE(WASM_GET_LOCAL(1), WASM_I8(13), WASM_I8(14))));
CHECK_EQ(11, r.Call(1, 1));
CHECK_EQ(12, r.Call(1, 0));
CHECK_EQ(13, r.Call(0, 1));
CHECK_EQ(14, r.Call(0, 0));
}
TEST(Step_I32Add) {
WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
WasmInterpreter* interpreter = r.interpreter();
interpreter->SetBreakpoint(r.function(), 0, true);
r.Call(1, 1);
interpreter->Run();
CHECK_EQ(2, interpreter->GetThread(0).GetReturnValue().to<int32_t>());
}
} // namespace wasm
} // namespace internal
} // namespace v8
...@@ -27,7 +27,7 @@ using namespace v8::internal::wasm; ...@@ -27,7 +27,7 @@ using namespace v8::internal::wasm;
#define RET_I8(x) kExprI8Const, x, kExprReturn, 1 #define RET_I8(x) kExprI8Const, x, kExprReturn, 1
WASM_EXEC_TEST(Int8Const) { WASM_EXEC_TEST(Int8Const) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
const byte kExpectedValue = 121; const byte kExpectedValue = 121;
// return(kExpectedValue) // return(kExpectedValue)
BUILD(r, WASM_I8(kExpectedValue)); BUILD(r, WASM_I8(kExpectedValue));
...@@ -35,7 +35,7 @@ WASM_EXEC_TEST(Int8Const) { ...@@ -35,7 +35,7 @@ WASM_EXEC_TEST(Int8Const) {
} }
WASM_EXEC_TEST(Int8Const_fallthru1) { WASM_EXEC_TEST(Int8Const_fallthru1) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
const byte kExpectedValue = 122; const byte kExpectedValue = 122;
// kExpectedValue // kExpectedValue
BUILD(r, WASM_I8(kExpectedValue)); BUILD(r, WASM_I8(kExpectedValue));
...@@ -43,7 +43,7 @@ WASM_EXEC_TEST(Int8Const_fallthru1) { ...@@ -43,7 +43,7 @@ WASM_EXEC_TEST(Int8Const_fallthru1) {
} }
WASM_EXEC_TEST(Int8Const_fallthru2) { WASM_EXEC_TEST(Int8Const_fallthru2) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
const byte kExpectedValue = 123; const byte kExpectedValue = 123;
// -99 kExpectedValue // -99 kExpectedValue
BUILD(r, WASM_I8(-99), WASM_I8(kExpectedValue)); BUILD(r, WASM_I8(-99), WASM_I8(kExpectedValue));
...@@ -52,7 +52,7 @@ WASM_EXEC_TEST(Int8Const_fallthru2) { ...@@ -52,7 +52,7 @@ WASM_EXEC_TEST(Int8Const_fallthru2) {
WASM_EXEC_TEST(Int8Const_all) { WASM_EXEC_TEST(Int8Const_all) {
for (int value = -128; value <= 127; value++) { for (int value = -128; value <= 127; value++) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return(value) // return(value)
BUILD(r, WASM_I8(value)); BUILD(r, WASM_I8(value));
int32_t result = r.Call(); int32_t result = r.Call();
...@@ -61,7 +61,7 @@ WASM_EXEC_TEST(Int8Const_all) { ...@@ -61,7 +61,7 @@ WASM_EXEC_TEST(Int8Const_all) {
} }
WASM_EXEC_TEST(Int32Const) { WASM_EXEC_TEST(Int32Const) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
const int32_t kExpectedValue = 0x11223344; const int32_t kExpectedValue = 0x11223344;
// return(kExpectedValue) // return(kExpectedValue)
BUILD(r, WASM_I32V_5(kExpectedValue)); BUILD(r, WASM_I32V_5(kExpectedValue));
...@@ -70,7 +70,7 @@ WASM_EXEC_TEST(Int32Const) { ...@@ -70,7 +70,7 @@ WASM_EXEC_TEST(Int32Const) {
WASM_EXEC_TEST(Int32Const_many) { WASM_EXEC_TEST(Int32Const_many) {
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
const int32_t kExpectedValue = *i; const int32_t kExpectedValue = *i;
// return(kExpectedValue) // return(kExpectedValue)
BUILD(r, WASM_I32V(kExpectedValue)); BUILD(r, WASM_I32V(kExpectedValue));
...@@ -79,7 +79,7 @@ WASM_EXEC_TEST(Int32Const_many) { ...@@ -79,7 +79,7 @@ WASM_EXEC_TEST(Int32Const_many) {
} }
WASM_EXEC_TEST(MemorySize) { WASM_EXEC_TEST(MemorySize) {
TestingModule module; TestingModule module(execution_mode);
WasmRunner<int32_t> r(&module); WasmRunner<int32_t> r(&module);
module.AddMemory(1024); module.AddMemory(1024);
BUILD(r, kExprMemorySize); BUILD(r, kExprMemorySize);
...@@ -87,49 +87,51 @@ WASM_EXEC_TEST(MemorySize) { ...@@ -87,49 +87,51 @@ WASM_EXEC_TEST(MemorySize) {
} }
WASM_EXEC_TEST(Int32Param0) { WASM_EXEC_TEST(Int32Param0) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// return(local[0]) // return(local[0])
BUILD(r, WASM_GET_LOCAL(0)); BUILD(r, WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
WASM_EXEC_TEST(Int32Param0_fallthru) { WASM_EXEC_TEST(Int32Param0_fallthru) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// local[0] // local[0]
BUILD(r, WASM_GET_LOCAL(0)); BUILD(r, WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
WASM_EXEC_TEST(Int32Param1) { WASM_EXEC_TEST(Int32Param1) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
// local[1] // local[1]
BUILD(r, WASM_GET_LOCAL(1)); BUILD(r, WASM_GET_LOCAL(1));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(-111, *i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(-111, *i)); }
} }
WASM_EXEC_TEST(Int32Add) { WASM_EXEC_TEST(Int32Add) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// 11 + 44 // 11 + 44
BUILD(r, WASM_I32_ADD(WASM_I8(11), WASM_I8(44))); BUILD(r, WASM_I32_ADD(WASM_I8(11), WASM_I8(44)));
CHECK_EQ(55, r.Call()); CHECK_EQ(55, r.Call());
} }
WASM_EXEC_TEST(Int32Add_P) { WASM_EXEC_TEST(Int32Add_P) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// p0 + 13 // p0 + 13
BUILD(r, WASM_I32_ADD(WASM_I8(13), WASM_GET_LOCAL(0))); BUILD(r, WASM_I32_ADD(WASM_I8(13), WASM_GET_LOCAL(0)));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i + 13, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i + 13, r.Call(*i)); }
} }
WASM_EXEC_TEST(Int32Add_P_fallthru) { WASM_EXEC_TEST(Int32Add_P_fallthru) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// p0 + 13 // p0 + 13
BUILD(r, WASM_I32_ADD(WASM_I8(13), WASM_GET_LOCAL(0))); BUILD(r, WASM_I32_ADD(WASM_I8(13), WASM_GET_LOCAL(0)));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i + 13, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i + 13, r.Call(*i)); }
} }
WASM_EXEC_TEST(Int32Add_P2) { WASM_EXEC_TEST(Int32Add_P2) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
// p0 + p1 // p0 + p1
BUILD(r, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
...@@ -142,7 +144,7 @@ WASM_EXEC_TEST(Int32Add_P2) { ...@@ -142,7 +144,7 @@ WASM_EXEC_TEST(Int32Add_P2) {
} }
WASM_EXEC_TEST(Float32Add) { WASM_EXEC_TEST(Float32Add) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// int(11.5f + 44.5f) // int(11.5f + 44.5f)
BUILD(r, BUILD(r,
WASM_I32_SCONVERT_F32(WASM_F32_ADD(WASM_F32(11.5f), WASM_F32(44.5f)))); WASM_I32_SCONVERT_F32(WASM_F32_ADD(WASM_F32(11.5f), WASM_F32(44.5f))));
...@@ -150,21 +152,23 @@ WASM_EXEC_TEST(Float32Add) { ...@@ -150,21 +152,23 @@ WASM_EXEC_TEST(Float32Add) {
} }
WASM_EXEC_TEST(Float64Add) { WASM_EXEC_TEST(Float64Add) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return int(13.5d + 43.5d) // return int(13.5d + 43.5d)
BUILD(r, WASM_I32_SCONVERT_F64(WASM_F64_ADD(WASM_F64(13.5), WASM_F64(43.5)))); BUILD(r, WASM_I32_SCONVERT_F64(WASM_F64_ADD(WASM_F64(13.5), WASM_F64(43.5))));
CHECK_EQ(57, r.Call()); CHECK_EQ(57, r.Call());
} }
void TestInt32Binop(WasmOpcode opcode, int32_t expected, int32_t a, int32_t b) { void TestInt32Binop(WasmExecutionMode execution_mode, WasmOpcode opcode,
int32_t expected, int32_t a, int32_t b) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// K op K // K op K
BUILD(r, WASM_BINOP(opcode, WASM_I32V(a), WASM_I32V(b))); BUILD(r, WASM_BINOP(opcode, WASM_I32V(a), WASM_I32V(b)));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
// a op b // a op b
BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(expected, r.Call(a, b)); CHECK_EQ(expected, r.Call(a, b));
...@@ -172,46 +176,48 @@ void TestInt32Binop(WasmOpcode opcode, int32_t expected, int32_t a, int32_t b) { ...@@ -172,46 +176,48 @@ void TestInt32Binop(WasmOpcode opcode, int32_t expected, int32_t a, int32_t b) {
} }
WASM_EXEC_TEST(Int32Binops) { WASM_EXEC_TEST(Int32Binops) {
TestInt32Binop(kExprI32Add, 88888888, 33333333, 55555555); TestInt32Binop(execution_mode, kExprI32Add, 88888888, 33333333, 55555555);
TestInt32Binop(kExprI32Sub, -1111111, 7777777, 8888888); TestInt32Binop(execution_mode, kExprI32Sub, -1111111, 7777777, 8888888);
TestInt32Binop(kExprI32Mul, 65130756, 88734, 734); TestInt32Binop(execution_mode, kExprI32Mul, 65130756, 88734, 734);
TestInt32Binop(kExprI32DivS, -66, -4777344, 72384); TestInt32Binop(execution_mode, kExprI32DivS, -66, -4777344, 72384);
TestInt32Binop(kExprI32DivU, 805306368, 0xF0000000, 5); TestInt32Binop(execution_mode, kExprI32DivU, 805306368, 0xF0000000, 5);
TestInt32Binop(kExprI32RemS, -3, -3003, 1000); TestInt32Binop(execution_mode, kExprI32RemS, -3, -3003, 1000);
TestInt32Binop(kExprI32RemU, 4, 4004, 1000); TestInt32Binop(execution_mode, kExprI32RemU, 4, 4004, 1000);
TestInt32Binop(kExprI32And, 0xEE, 0xFFEE, 0xFF0000FF); TestInt32Binop(execution_mode, kExprI32And, 0xEE, 0xFFEE, 0xFF0000FF);
TestInt32Binop(kExprI32Ior, 0xF0FF00FF, 0xF0F000EE, 0x000F0011); TestInt32Binop(execution_mode, kExprI32Ior, 0xF0FF00FF, 0xF0F000EE,
TestInt32Binop(kExprI32Xor, 0xABCDEF01, 0xABCDEFFF, 0xFE); 0x000F0011);
TestInt32Binop(kExprI32Shl, 0xA0000000, 0xA, 28); TestInt32Binop(execution_mode, kExprI32Xor, 0xABCDEF01, 0xABCDEFFF, 0xFE);
TestInt32Binop(kExprI32ShrU, 0x07000010, 0x70000100, 4); TestInt32Binop(execution_mode, kExprI32Shl, 0xA0000000, 0xA, 28);
TestInt32Binop(kExprI32ShrS, 0xFF000000, 0x80000000, 7); TestInt32Binop(execution_mode, kExprI32ShrU, 0x07000010, 0x70000100, 4);
TestInt32Binop(kExprI32Ror, 0x01000000, 0x80000000, 7); TestInt32Binop(execution_mode, kExprI32ShrS, 0xFF000000, 0x80000000, 7);
TestInt32Binop(kExprI32Ror, 0x01000000, 0x80000000, 39); TestInt32Binop(execution_mode, kExprI32Ror, 0x01000000, 0x80000000, 7);
TestInt32Binop(kExprI32Rol, 0x00000040, 0x80000000, 7); TestInt32Binop(execution_mode, kExprI32Ror, 0x01000000, 0x80000000, 39);
TestInt32Binop(kExprI32Rol, 0x00000040, 0x80000000, 39); TestInt32Binop(execution_mode, kExprI32Rol, 0x00000040, 0x80000000, 7);
TestInt32Binop(kExprI32Eq, 1, -99, -99); TestInt32Binop(execution_mode, kExprI32Rol, 0x00000040, 0x80000000, 39);
TestInt32Binop(kExprI32Ne, 0, -97, -97); TestInt32Binop(execution_mode, kExprI32Eq, 1, -99, -99);
TestInt32Binop(execution_mode, kExprI32Ne, 0, -97, -97);
TestInt32Binop(kExprI32LtS, 1, -4, 4);
TestInt32Binop(kExprI32LeS, 0, -2, -3); TestInt32Binop(execution_mode, kExprI32LtS, 1, -4, 4);
TestInt32Binop(kExprI32LtU, 1, 0, -6); TestInt32Binop(execution_mode, kExprI32LeS, 0, -2, -3);
TestInt32Binop(kExprI32LeU, 1, 98978, 0xF0000000); TestInt32Binop(execution_mode, kExprI32LtU, 1, 0, -6);
TestInt32Binop(execution_mode, kExprI32LeU, 1, 98978, 0xF0000000);
TestInt32Binop(kExprI32GtS, 1, 4, -4);
TestInt32Binop(kExprI32GeS, 0, -3, -2); TestInt32Binop(execution_mode, kExprI32GtS, 1, 4, -4);
TestInt32Binop(kExprI32GtU, 1, -6, 0); TestInt32Binop(execution_mode, kExprI32GeS, 0, -3, -2);
TestInt32Binop(kExprI32GeU, 1, 0xF0000000, 98978); TestInt32Binop(execution_mode, kExprI32GtU, 1, -6, 0);
} TestInt32Binop(execution_mode, kExprI32GeU, 1, 0xF0000000, 98978);
}
void TestInt32Unop(WasmOpcode opcode, int32_t expected, int32_t a) {
void TestInt32Unop(WasmExecutionMode execution_mode, WasmOpcode opcode,
int32_t expected, int32_t a) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return op K // return op K
BUILD(r, WASM_UNOP(opcode, WASM_I32V(a))); BUILD(r, WASM_UNOP(opcode, WASM_I32V(a)));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// return op a // return op a
BUILD(r, WASM_UNOP(opcode, WASM_GET_LOCAL(0))); BUILD(r, WASM_UNOP(opcode, WASM_GET_LOCAL(0)));
CHECK_EQ(expected, r.Call(a)); CHECK_EQ(expected, r.Call(a));
...@@ -219,95 +225,96 @@ void TestInt32Unop(WasmOpcode opcode, int32_t expected, int32_t a) { ...@@ -219,95 +225,96 @@ void TestInt32Unop(WasmOpcode opcode, int32_t expected, int32_t a) {
} }
WASM_EXEC_TEST(Int32Clz) { WASM_EXEC_TEST(Int32Clz) {
TestInt32Unop(kExprI32Clz, 0, 0x80001000); TestInt32Unop(execution_mode, kExprI32Clz, 0, 0x80001000);
TestInt32Unop(kExprI32Clz, 1, 0x40000500); TestInt32Unop(execution_mode, kExprI32Clz, 1, 0x40000500);
TestInt32Unop(kExprI32Clz, 2, 0x20000300); TestInt32Unop(execution_mode, kExprI32Clz, 2, 0x20000300);
TestInt32Unop(kExprI32Clz, 3, 0x10000003); TestInt32Unop(execution_mode, kExprI32Clz, 3, 0x10000003);
TestInt32Unop(kExprI32Clz, 4, 0x08050000); TestInt32Unop(execution_mode, kExprI32Clz, 4, 0x08050000);
TestInt32Unop(kExprI32Clz, 5, 0x04006000); TestInt32Unop(execution_mode, kExprI32Clz, 5, 0x04006000);
TestInt32Unop(kExprI32Clz, 6, 0x02000000); TestInt32Unop(execution_mode, kExprI32Clz, 6, 0x02000000);
TestInt32Unop(kExprI32Clz, 7, 0x010000a0); TestInt32Unop(execution_mode, kExprI32Clz, 7, 0x010000a0);
TestInt32Unop(kExprI32Clz, 8, 0x00800c00); TestInt32Unop(execution_mode, kExprI32Clz, 8, 0x00800c00);
TestInt32Unop(kExprI32Clz, 9, 0x00400000); TestInt32Unop(execution_mode, kExprI32Clz, 9, 0x00400000);
TestInt32Unop(kExprI32Clz, 10, 0x0020000d); TestInt32Unop(execution_mode, kExprI32Clz, 10, 0x0020000d);
TestInt32Unop(kExprI32Clz, 11, 0x00100f00); TestInt32Unop(execution_mode, kExprI32Clz, 11, 0x00100f00);
TestInt32Unop(kExprI32Clz, 12, 0x00080000); TestInt32Unop(execution_mode, kExprI32Clz, 12, 0x00080000);
TestInt32Unop(kExprI32Clz, 13, 0x00041000); TestInt32Unop(execution_mode, kExprI32Clz, 13, 0x00041000);
TestInt32Unop(kExprI32Clz, 14, 0x00020020); TestInt32Unop(execution_mode, kExprI32Clz, 14, 0x00020020);
TestInt32Unop(kExprI32Clz, 15, 0x00010300); TestInt32Unop(execution_mode, kExprI32Clz, 15, 0x00010300);
TestInt32Unop(kExprI32Clz, 16, 0x00008040); TestInt32Unop(execution_mode, kExprI32Clz, 16, 0x00008040);
TestInt32Unop(kExprI32Clz, 17, 0x00004005); TestInt32Unop(execution_mode, kExprI32Clz, 17, 0x00004005);
TestInt32Unop(kExprI32Clz, 18, 0x00002050); TestInt32Unop(execution_mode, kExprI32Clz, 18, 0x00002050);
TestInt32Unop(kExprI32Clz, 19, 0x00001700); TestInt32Unop(execution_mode, kExprI32Clz, 19, 0x00001700);
TestInt32Unop(kExprI32Clz, 20, 0x00000870); TestInt32Unop(execution_mode, kExprI32Clz, 20, 0x00000870);
TestInt32Unop(kExprI32Clz, 21, 0x00000405); TestInt32Unop(execution_mode, kExprI32Clz, 21, 0x00000405);
TestInt32Unop(kExprI32Clz, 22, 0x00000203); TestInt32Unop(execution_mode, kExprI32Clz, 22, 0x00000203);
TestInt32Unop(kExprI32Clz, 23, 0x00000101); TestInt32Unop(execution_mode, kExprI32Clz, 23, 0x00000101);
TestInt32Unop(kExprI32Clz, 24, 0x00000089); TestInt32Unop(execution_mode, kExprI32Clz, 24, 0x00000089);
TestInt32Unop(kExprI32Clz, 25, 0x00000041); TestInt32Unop(execution_mode, kExprI32Clz, 25, 0x00000041);
TestInt32Unop(kExprI32Clz, 26, 0x00000022); TestInt32Unop(execution_mode, kExprI32Clz, 26, 0x00000022);
TestInt32Unop(kExprI32Clz, 27, 0x00000013); TestInt32Unop(execution_mode, kExprI32Clz, 27, 0x00000013);
TestInt32Unop(kExprI32Clz, 28, 0x00000008); TestInt32Unop(execution_mode, kExprI32Clz, 28, 0x00000008);
TestInt32Unop(kExprI32Clz, 29, 0x00000004); TestInt32Unop(execution_mode, kExprI32Clz, 29, 0x00000004);
TestInt32Unop(kExprI32Clz, 30, 0x00000002); TestInt32Unop(execution_mode, kExprI32Clz, 30, 0x00000002);
TestInt32Unop(kExprI32Clz, 31, 0x00000001); TestInt32Unop(execution_mode, kExprI32Clz, 31, 0x00000001);
TestInt32Unop(kExprI32Clz, 32, 0x00000000); TestInt32Unop(execution_mode, kExprI32Clz, 32, 0x00000000);
} }
WASM_EXEC_TEST(Int32Ctz) { WASM_EXEC_TEST(Int32Ctz) {
TestInt32Unop(kExprI32Ctz, 32, 0x00000000); TestInt32Unop(execution_mode, kExprI32Ctz, 32, 0x00000000);
TestInt32Unop(kExprI32Ctz, 31, 0x80000000); TestInt32Unop(execution_mode, kExprI32Ctz, 31, 0x80000000);
TestInt32Unop(kExprI32Ctz, 30, 0x40000000); TestInt32Unop(execution_mode, kExprI32Ctz, 30, 0x40000000);
TestInt32Unop(kExprI32Ctz, 29, 0x20000000); TestInt32Unop(execution_mode, kExprI32Ctz, 29, 0x20000000);
TestInt32Unop(kExprI32Ctz, 28, 0x10000000); TestInt32Unop(execution_mode, kExprI32Ctz, 28, 0x10000000);
TestInt32Unop(kExprI32Ctz, 27, 0xa8000000); TestInt32Unop(execution_mode, kExprI32Ctz, 27, 0xa8000000);
TestInt32Unop(kExprI32Ctz, 26, 0xf4000000); TestInt32Unop(execution_mode, kExprI32Ctz, 26, 0xf4000000);
TestInt32Unop(kExprI32Ctz, 25, 0x62000000); TestInt32Unop(execution_mode, kExprI32Ctz, 25, 0x62000000);
TestInt32Unop(kExprI32Ctz, 24, 0x91000000); TestInt32Unop(execution_mode, kExprI32Ctz, 24, 0x91000000);
TestInt32Unop(kExprI32Ctz, 23, 0xcd800000); TestInt32Unop(execution_mode, kExprI32Ctz, 23, 0xcd800000);
TestInt32Unop(kExprI32Ctz, 22, 0x09400000); TestInt32Unop(execution_mode, kExprI32Ctz, 22, 0x09400000);
TestInt32Unop(kExprI32Ctz, 21, 0xaf200000); TestInt32Unop(execution_mode, kExprI32Ctz, 21, 0xaf200000);
TestInt32Unop(kExprI32Ctz, 20, 0xac100000); TestInt32Unop(execution_mode, kExprI32Ctz, 20, 0xac100000);
TestInt32Unop(kExprI32Ctz, 19, 0xe0b80000); TestInt32Unop(execution_mode, kExprI32Ctz, 19, 0xe0b80000);
TestInt32Unop(kExprI32Ctz, 18, 0x9ce40000); TestInt32Unop(execution_mode, kExprI32Ctz, 18, 0x9ce40000);
TestInt32Unop(kExprI32Ctz, 17, 0xc7920000); TestInt32Unop(execution_mode, kExprI32Ctz, 17, 0xc7920000);
TestInt32Unop(kExprI32Ctz, 16, 0xb8f10000); TestInt32Unop(execution_mode, kExprI32Ctz, 16, 0xb8f10000);
TestInt32Unop(kExprI32Ctz, 15, 0x3b9f8000); TestInt32Unop(execution_mode, kExprI32Ctz, 15, 0x3b9f8000);
TestInt32Unop(kExprI32Ctz, 14, 0xdb4c4000); TestInt32Unop(execution_mode, kExprI32Ctz, 14, 0xdb4c4000);
TestInt32Unop(kExprI32Ctz, 13, 0xe9a32000); TestInt32Unop(execution_mode, kExprI32Ctz, 13, 0xe9a32000);
TestInt32Unop(kExprI32Ctz, 12, 0xfca61000); TestInt32Unop(execution_mode, kExprI32Ctz, 12, 0xfca61000);
TestInt32Unop(kExprI32Ctz, 11, 0x6c8a7800); TestInt32Unop(execution_mode, kExprI32Ctz, 11, 0x6c8a7800);
TestInt32Unop(kExprI32Ctz, 10, 0x8ce5a400); TestInt32Unop(execution_mode, kExprI32Ctz, 10, 0x8ce5a400);
TestInt32Unop(kExprI32Ctz, 9, 0xcb7d0200); TestInt32Unop(execution_mode, kExprI32Ctz, 9, 0xcb7d0200);
TestInt32Unop(kExprI32Ctz, 8, 0xcb4dc100); TestInt32Unop(execution_mode, kExprI32Ctz, 8, 0xcb4dc100);
TestInt32Unop(kExprI32Ctz, 7, 0xdfbec580); TestInt32Unop(execution_mode, kExprI32Ctz, 7, 0xdfbec580);
TestInt32Unop(kExprI32Ctz, 6, 0x27a9db40); TestInt32Unop(execution_mode, kExprI32Ctz, 6, 0x27a9db40);
TestInt32Unop(kExprI32Ctz, 5, 0xde3bcb20); TestInt32Unop(execution_mode, kExprI32Ctz, 5, 0xde3bcb20);
TestInt32Unop(kExprI32Ctz, 4, 0xd7e8a610); TestInt32Unop(execution_mode, kExprI32Ctz, 4, 0xd7e8a610);
TestInt32Unop(kExprI32Ctz, 3, 0x9afdbc88); TestInt32Unop(execution_mode, kExprI32Ctz, 3, 0x9afdbc88);
TestInt32Unop(kExprI32Ctz, 2, 0x9afdbc84); TestInt32Unop(execution_mode, kExprI32Ctz, 2, 0x9afdbc84);
TestInt32Unop(kExprI32Ctz, 1, 0x9afdbc82); TestInt32Unop(execution_mode, kExprI32Ctz, 1, 0x9afdbc82);
TestInt32Unop(kExprI32Ctz, 0, 0x9afdbc81); TestInt32Unop(execution_mode, kExprI32Ctz, 0, 0x9afdbc81);
} }
WASM_EXEC_TEST(Int32Popcnt) { WASM_EXEC_TEST(Int32Popcnt) {
TestInt32Unop(kExprI32Popcnt, 32, 0xffffffff); TestInt32Unop(execution_mode, kExprI32Popcnt, 32, 0xffffffff);
TestInt32Unop(kExprI32Popcnt, 0, 0x00000000); TestInt32Unop(execution_mode, kExprI32Popcnt, 0, 0x00000000);
TestInt32Unop(kExprI32Popcnt, 1, 0x00008000); TestInt32Unop(execution_mode, kExprI32Popcnt, 1, 0x00008000);
TestInt32Unop(kExprI32Popcnt, 13, 0x12345678); TestInt32Unop(execution_mode, kExprI32Popcnt, 13, 0x12345678);
TestInt32Unop(kExprI32Popcnt, 19, 0xfedcba09); TestInt32Unop(execution_mode, kExprI32Popcnt, 19, 0xfedcba09);
} }
WASM_EXEC_TEST(I32Eqz) { WASM_EXEC_TEST(I32Eqz) {
TestInt32Unop(kExprI32Eqz, 0, 1); TestInt32Unop(execution_mode, kExprI32Eqz, 0, 1);
TestInt32Unop(kExprI32Eqz, 0, -1); TestInt32Unop(execution_mode, kExprI32Eqz, 0, -1);
TestInt32Unop(kExprI32Eqz, 0, -827343); TestInt32Unop(execution_mode, kExprI32Eqz, 0, -827343);
TestInt32Unop(kExprI32Eqz, 0, 8888888); TestInt32Unop(execution_mode, kExprI32Eqz, 0, 8888888);
TestInt32Unop(kExprI32Eqz, 1, 0); TestInt32Unop(execution_mode, kExprI32Eqz, 1, 0);
} }
WASM_EXEC_TEST(I32Shl) { WASM_EXEC_TEST(I32Shl) {
WasmRunner<uint32_t> r(MachineType::Uint32(), MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32(),
MachineType::Uint32());
BUILD(r, WASM_I32_SHL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I32_SHL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(i) {
...@@ -319,7 +326,8 @@ WASM_EXEC_TEST(I32Shl) { ...@@ -319,7 +326,8 @@ WASM_EXEC_TEST(I32Shl) {
} }
WASM_EXEC_TEST(I32Shr) { WASM_EXEC_TEST(I32Shr) {
WasmRunner<uint32_t> r(MachineType::Uint32(), MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32(),
MachineType::Uint32());
BUILD(r, WASM_I32_SHR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I32_SHR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(i) {
...@@ -331,7 +339,8 @@ WASM_EXEC_TEST(I32Shr) { ...@@ -331,7 +339,8 @@ WASM_EXEC_TEST(I32Shr) {
} }
WASM_EXEC_TEST(I32Sar) { WASM_EXEC_TEST(I32Sar) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_I32_SAR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I32_SAR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
...@@ -343,7 +352,8 @@ WASM_EXEC_TEST(I32Sar) { ...@@ -343,7 +352,8 @@ WASM_EXEC_TEST(I32Sar) {
} }
WASM_EXEC_TEST(Int32DivS_trap) { WASM_EXEC_TEST(Int32DivS_trap) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_I32_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I32_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min(); const int32_t kMin = std::numeric_limits<int32_t>::min();
CHECK_EQ(0, r.Call(0, 100)); CHECK_EQ(0, r.Call(0, 100));
...@@ -354,7 +364,8 @@ WASM_EXEC_TEST(Int32DivS_trap) { ...@@ -354,7 +364,8 @@ WASM_EXEC_TEST(Int32DivS_trap) {
} }
WASM_EXEC_TEST(Int32RemS_trap) { WASM_EXEC_TEST(Int32RemS_trap) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_I32_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I32_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min(); const int32_t kMin = std::numeric_limits<int32_t>::min();
CHECK_EQ(33, r.Call(133, 100)); CHECK_EQ(33, r.Call(133, 100));
...@@ -365,7 +376,8 @@ WASM_EXEC_TEST(Int32RemS_trap) { ...@@ -365,7 +376,8 @@ WASM_EXEC_TEST(Int32RemS_trap) {
} }
WASM_EXEC_TEST(Int32DivU_trap) { WASM_EXEC_TEST(Int32DivU_trap) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_I32_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I32_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min(); const int32_t kMin = std::numeric_limits<int32_t>::min();
CHECK_EQ(0, r.Call(0, 100)); CHECK_EQ(0, r.Call(0, 100));
...@@ -376,7 +388,8 @@ WASM_EXEC_TEST(Int32DivU_trap) { ...@@ -376,7 +388,8 @@ WASM_EXEC_TEST(Int32DivU_trap) {
} }
WASM_EXEC_TEST(Int32RemU_trap) { WASM_EXEC_TEST(Int32RemU_trap) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_I32_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_I32_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(17, r.Call(217, 100)); CHECK_EQ(17, r.Call(217, 100));
const int32_t kMin = std::numeric_limits<int32_t>::min(); const int32_t kMin = std::numeric_limits<int32_t>::min();
...@@ -388,7 +401,7 @@ WASM_EXEC_TEST(Int32RemU_trap) { ...@@ -388,7 +401,7 @@ WASM_EXEC_TEST(Int32RemU_trap) {
WASM_EXEC_TEST(Int32DivS_byzero_const) { WASM_EXEC_TEST(Int32DivS_byzero_const) {
for (int8_t denom = -2; denom < 8; denom++) { for (int8_t denom = -2; denom < 8; denom++) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, WASM_I32_DIVS(WASM_GET_LOCAL(0), WASM_I8(denom))); BUILD(r, WASM_I32_DIVS(WASM_GET_LOCAL(0), WASM_I8(denom)));
for (int32_t val = -7; val < 8; val++) { for (int32_t val = -7; val < 8; val++) {
if (denom == 0) { if (denom == 0) {
...@@ -402,7 +415,7 @@ WASM_EXEC_TEST(Int32DivS_byzero_const) { ...@@ -402,7 +415,7 @@ WASM_EXEC_TEST(Int32DivS_byzero_const) {
WASM_EXEC_TEST(Int32DivU_byzero_const) { WASM_EXEC_TEST(Int32DivU_byzero_const) {
for (uint32_t denom = 0xfffffffe; denom < 8; denom++) { for (uint32_t denom = 0xfffffffe; denom < 8; denom++) {
WasmRunner<uint32_t> r(MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32());
BUILD(r, WASM_I32_DIVU(WASM_GET_LOCAL(0), WASM_I32V_1(denom))); BUILD(r, WASM_I32_DIVU(WASM_GET_LOCAL(0), WASM_I32V_1(denom)));
for (uint32_t val = 0xfffffff0; val < 8; val++) { for (uint32_t val = 0xfffffff0; val < 8; val++) {
...@@ -416,7 +429,7 @@ WASM_EXEC_TEST(Int32DivU_byzero_const) { ...@@ -416,7 +429,7 @@ WASM_EXEC_TEST(Int32DivU_byzero_const) {
} }
WASM_EXEC_TEST(Int32DivS_trap_effect) { WASM_EXEC_TEST(Int32DivS_trap_effect) {
TestingModule module; TestingModule module(execution_mode);
module.AddMemoryElems<int32_t>(8); module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32());
...@@ -434,32 +447,36 @@ WASM_EXEC_TEST(Int32DivS_trap_effect) { ...@@ -434,32 +447,36 @@ WASM_EXEC_TEST(Int32DivS_trap_effect) {
CHECK_TRAP(r.Call(0, 0)); CHECK_TRAP(r.Call(0, 0));
} }
void TestFloat32Binop(WasmOpcode opcode, int32_t expected, float a, float b) { void TestFloat32Binop(WasmExecutionMode execution_mode, WasmOpcode opcode,
int32_t expected, float a, float b) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return K op K // return K op K
BUILD(r, WASM_BINOP(opcode, WASM_F32(a), WASM_F32(b))); BUILD(r, WASM_BINOP(opcode, WASM_F32(a), WASM_F32(b)));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int32_t> r(MachineType::Float32(), MachineType::Float32()); WasmRunner<int32_t> r(execution_mode, MachineType::Float32(),
MachineType::Float32());
// return a op b // return a op b
BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(expected, r.Call(a, b)); CHECK_EQ(expected, r.Call(a, b));
} }
} }
void TestFloat32BinopWithConvert(WasmOpcode opcode, int32_t expected, float a, void TestFloat32BinopWithConvert(WasmExecutionMode execution_mode,
WasmOpcode opcode, int32_t expected, float a,
float b) { float b) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return int(K op K) // return int(K op K)
BUILD(r, BUILD(r,
WASM_I32_SCONVERT_F32(WASM_BINOP(opcode, WASM_F32(a), WASM_F32(b)))); WASM_I32_SCONVERT_F32(WASM_BINOP(opcode, WASM_F32(a), WASM_F32(b))));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int32_t> r(MachineType::Float32(), MachineType::Float32()); WasmRunner<int32_t> r(execution_mode, MachineType::Float32(),
MachineType::Float32());
// return int(a op b) // return int(a op b)
BUILD(r, WASM_I32_SCONVERT_F32( BUILD(r, WASM_I32_SCONVERT_F32(
WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))); WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
...@@ -467,62 +484,68 @@ void TestFloat32BinopWithConvert(WasmOpcode opcode, int32_t expected, float a, ...@@ -467,62 +484,68 @@ void TestFloat32BinopWithConvert(WasmOpcode opcode, int32_t expected, float a,
} }
} }
void TestFloat32UnopWithConvert(WasmOpcode opcode, int32_t expected, float a) { void TestFloat32UnopWithConvert(WasmExecutionMode execution_mode,
WasmOpcode opcode, int32_t expected, float a) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return int(op(K)) // return int(op(K))
BUILD(r, WASM_I32_SCONVERT_F32(WASM_UNOP(opcode, WASM_F32(a)))); BUILD(r, WASM_I32_SCONVERT_F32(WASM_UNOP(opcode, WASM_F32(a))));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int32_t> r(MachineType::Float32()); WasmRunner<int32_t> r(execution_mode, MachineType::Float32());
// return int(op(a)) // return int(op(a))
BUILD(r, WASM_I32_SCONVERT_F32(WASM_UNOP(opcode, WASM_GET_LOCAL(0)))); BUILD(r, WASM_I32_SCONVERT_F32(WASM_UNOP(opcode, WASM_GET_LOCAL(0))));
CHECK_EQ(expected, r.Call(a)); CHECK_EQ(expected, r.Call(a));
} }
} }
void TestFloat64Binop(WasmOpcode opcode, int32_t expected, double a, double b) { void TestFloat64Binop(WasmExecutionMode execution_mode, WasmOpcode opcode,
int32_t expected, double a, double b) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return K op K // return K op K
BUILD(r, WASM_BINOP(opcode, WASM_F64(a), WASM_F64(b))); BUILD(r, WASM_BINOP(opcode, WASM_F64(a), WASM_F64(b)));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int32_t> r(MachineType::Float64(), MachineType::Float64()); WasmRunner<int32_t> r(execution_mode, MachineType::Float64(),
MachineType::Float64());
// return a op b // return a op b
BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(expected, r.Call(a, b)); CHECK_EQ(expected, r.Call(a, b));
} }
} }
void TestFloat64BinopWithConvert(WasmOpcode opcode, int32_t expected, double a, void TestFloat64BinopWithConvert(WasmExecutionMode execution_mode,
WasmOpcode opcode, int32_t expected, double a,
double b) { double b) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return int(K op K) // return int(K op K)
BUILD(r, BUILD(r,
WASM_I32_SCONVERT_F64(WASM_BINOP(opcode, WASM_F64(a), WASM_F64(b)))); WASM_I32_SCONVERT_F64(WASM_BINOP(opcode, WASM_F64(a), WASM_F64(b))));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int32_t> r(MachineType::Float64(), MachineType::Float64()); WasmRunner<int32_t> r(execution_mode, MachineType::Float64(),
MachineType::Float64());
BUILD(r, WASM_I32_SCONVERT_F64( BUILD(r, WASM_I32_SCONVERT_F64(
WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))); WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
CHECK_EQ(expected, r.Call(a, b)); CHECK_EQ(expected, r.Call(a, b));
} }
} }
void TestFloat64UnopWithConvert(WasmOpcode opcode, int32_t expected, double a) { void TestFloat64UnopWithConvert(WasmExecutionMode execution_mode,
WasmOpcode opcode, int32_t expected, double a) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// return int(op(K)) // return int(op(K))
BUILD(r, WASM_I32_SCONVERT_F64(WASM_UNOP(opcode, WASM_F64(a)))); BUILD(r, WASM_I32_SCONVERT_F64(WASM_UNOP(opcode, WASM_F64(a))));
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
{ {
WasmRunner<int32_t> r(MachineType::Float64()); WasmRunner<int32_t> r(execution_mode, MachineType::Float64());
// return int(op(a)) // return int(op(a))
BUILD(r, WASM_I32_SCONVERT_F64(WASM_UNOP(opcode, WASM_GET_LOCAL(0)))); BUILD(r, WASM_I32_SCONVERT_F64(WASM_UNOP(opcode, WASM_GET_LOCAL(0))));
CHECK_EQ(expected, r.Call(a)); CHECK_EQ(expected, r.Call(a));
...@@ -530,49 +553,50 @@ void TestFloat64UnopWithConvert(WasmOpcode opcode, int32_t expected, double a) { ...@@ -530,49 +553,50 @@ void TestFloat64UnopWithConvert(WasmOpcode opcode, int32_t expected, double a) {
} }
WASM_EXEC_TEST(Float32Binops) { WASM_EXEC_TEST(Float32Binops) {
TestFloat32Binop(kExprF32Eq, 1, 8.125f, 8.125f); TestFloat32Binop(execution_mode, kExprF32Eq, 1, 8.125f, 8.125f);
TestFloat32Binop(kExprF32Ne, 1, 8.125f, 8.127f); TestFloat32Binop(execution_mode, kExprF32Ne, 1, 8.125f, 8.127f);
TestFloat32Binop(kExprF32Lt, 1, -9.5f, -9.0f); TestFloat32Binop(execution_mode, kExprF32Lt, 1, -9.5f, -9.0f);
TestFloat32Binop(kExprF32Le, 1, -1111.0f, -1111.0f); TestFloat32Binop(execution_mode, kExprF32Le, 1, -1111.0f, -1111.0f);
TestFloat32Binop(kExprF32Gt, 1, -9.0f, -9.5f); TestFloat32Binop(execution_mode, kExprF32Gt, 1, -9.0f, -9.5f);
TestFloat32Binop(kExprF32Ge, 1, -1111.0f, -1111.0f); TestFloat32Binop(execution_mode, kExprF32Ge, 1, -1111.0f, -1111.0f);
TestFloat32BinopWithConvert(kExprF32Add, 10, 3.5f, 6.5f); TestFloat32BinopWithConvert(execution_mode, kExprF32Add, 10, 3.5f, 6.5f);
TestFloat32BinopWithConvert(kExprF32Sub, 2, 44.5f, 42.5f); TestFloat32BinopWithConvert(execution_mode, kExprF32Sub, 2, 44.5f, 42.5f);
TestFloat32BinopWithConvert(kExprF32Mul, -66, -132.1f, 0.5f); TestFloat32BinopWithConvert(execution_mode, kExprF32Mul, -66, -132.1f, 0.5f);
TestFloat32BinopWithConvert(kExprF32Div, 11, 22.1f, 2.0f); TestFloat32BinopWithConvert(execution_mode, kExprF32Div, 11, 22.1f, 2.0f);
} }
WASM_EXEC_TEST(Float32Unops) { WASM_EXEC_TEST(Float32Unops) {
TestFloat32UnopWithConvert(kExprF32Abs, 8, 8.125f); TestFloat32UnopWithConvert(execution_mode, kExprF32Abs, 8, 8.125f);
TestFloat32UnopWithConvert(kExprF32Abs, 9, -9.125f); TestFloat32UnopWithConvert(execution_mode, kExprF32Abs, 9, -9.125f);
TestFloat32UnopWithConvert(kExprF32Neg, -213, 213.125f); TestFloat32UnopWithConvert(execution_mode, kExprF32Neg, -213, 213.125f);
TestFloat32UnopWithConvert(kExprF32Sqrt, 12, 144.4f); TestFloat32UnopWithConvert(execution_mode, kExprF32Sqrt, 12, 144.4f);
} }
WASM_EXEC_TEST(Float64Binops) { WASM_EXEC_TEST(Float64Binops) {
TestFloat64Binop(kExprF64Eq, 1, 16.25, 16.25); TestFloat64Binop(execution_mode, kExprF64Eq, 1, 16.25, 16.25);
TestFloat64Binop(kExprF64Ne, 1, 16.25, 16.15); TestFloat64Binop(execution_mode, kExprF64Ne, 1, 16.25, 16.15);
TestFloat64Binop(kExprF64Lt, 1, -32.4, 11.7); TestFloat64Binop(execution_mode, kExprF64Lt, 1, -32.4, 11.7);
TestFloat64Binop(kExprF64Le, 1, -88.9, -88.9); TestFloat64Binop(execution_mode, kExprF64Le, 1, -88.9, -88.9);
TestFloat64Binop(kExprF64Gt, 1, 11.7, -32.4); TestFloat64Binop(execution_mode, kExprF64Gt, 1, 11.7, -32.4);
TestFloat64Binop(kExprF64Ge, 1, -88.9, -88.9); TestFloat64Binop(execution_mode, kExprF64Ge, 1, -88.9, -88.9);
TestFloat64BinopWithConvert(kExprF64Add, 100, 43.5, 56.5); TestFloat64BinopWithConvert(execution_mode, kExprF64Add, 100, 43.5, 56.5);
TestFloat64BinopWithConvert(kExprF64Sub, 200, 12200.1, 12000.1); TestFloat64BinopWithConvert(execution_mode, kExprF64Sub, 200, 12200.1,
TestFloat64BinopWithConvert(kExprF64Mul, -33, 134, -0.25); 12000.1);
TestFloat64BinopWithConvert(kExprF64Div, -1111, -2222.3, 2); TestFloat64BinopWithConvert(execution_mode, kExprF64Mul, -33, 134, -0.25);
TestFloat64BinopWithConvert(execution_mode, kExprF64Div, -1111, -2222.3, 2);
} }
WASM_EXEC_TEST(Float64Unops) { WASM_EXEC_TEST(Float64Unops) {
TestFloat64UnopWithConvert(kExprF64Abs, 108, 108.125); TestFloat64UnopWithConvert(execution_mode, kExprF64Abs, 108, 108.125);
TestFloat64UnopWithConvert(kExprF64Abs, 209, -209.125); TestFloat64UnopWithConvert(execution_mode, kExprF64Abs, 209, -209.125);
TestFloat64UnopWithConvert(kExprF64Neg, -209, 209.125); TestFloat64UnopWithConvert(execution_mode, kExprF64Neg, -209, 209.125);
TestFloat64UnopWithConvert(kExprF64Sqrt, 13, 169.4); TestFloat64UnopWithConvert(execution_mode, kExprF64Sqrt, 13, 169.4);
} }
WASM_EXEC_TEST(Float32Neg) { WASM_EXEC_TEST(Float32Neg) {
WasmRunner<float> r(MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_F32_NEG(WASM_GET_LOCAL(0))); BUILD(r, WASM_F32_NEG(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -582,14 +606,14 @@ WASM_EXEC_TEST(Float32Neg) { ...@@ -582,14 +606,14 @@ WASM_EXEC_TEST(Float32Neg) {
} }
WASM_EXEC_TEST(Float32SubMinusZero) { WASM_EXEC_TEST(Float32SubMinusZero) {
WasmRunner<float> r(MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_F32_SUB(WASM_F32(-0.0), WASM_GET_LOCAL(0))); BUILD(r, WASM_F32_SUB(WASM_F32(-0.0), WASM_GET_LOCAL(0)));
CHECK_EQ(0x7fe00000, bit_cast<uint32_t>(r.Call(bit_cast<float>(0x7fa00000)))); CHECK_EQ(0x7fe00000, bit_cast<uint32_t>(r.Call(bit_cast<float>(0x7fa00000))));
} }
WASM_EXEC_TEST(Float64SubMinusZero) { WASM_EXEC_TEST(Float64SubMinusZero) {
WasmRunner<double> r(MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_F64_SUB(WASM_F64(-0.0), WASM_GET_LOCAL(0))); BUILD(r, WASM_F64_SUB(WASM_F64(-0.0), WASM_GET_LOCAL(0)));
CHECK_EQ(0x7ff8123456789abc, CHECK_EQ(0x7ff8123456789abc,
...@@ -597,7 +621,7 @@ WASM_EXEC_TEST(Float64SubMinusZero) { ...@@ -597,7 +621,7 @@ WASM_EXEC_TEST(Float64SubMinusZero) {
} }
WASM_EXEC_TEST(Float64Neg) { WASM_EXEC_TEST(Float64Neg) {
WasmRunner<double> r(MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_F64_NEG(WASM_GET_LOCAL(0))); BUILD(r, WASM_F64_NEG(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -607,7 +631,7 @@ WASM_EXEC_TEST(Float64Neg) { ...@@ -607,7 +631,7 @@ WASM_EXEC_TEST(Float64Neg) {
} }
WASM_EXEC_TEST(IfElse_P) { WASM_EXEC_TEST(IfElse_P) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// if (p0) return 11; else return 22; // if (p0) return 11; else return 22;
BUILD(r, WASM_IF_ELSE(WASM_GET_LOCAL(0), // -- BUILD(r, WASM_IF_ELSE(WASM_GET_LOCAL(0), // --
WASM_I8(11), // -- WASM_I8(11), // --
...@@ -619,33 +643,37 @@ WASM_EXEC_TEST(IfElse_P) { ...@@ -619,33 +643,37 @@ WASM_EXEC_TEST(IfElse_P) {
} }
WASM_EXEC_TEST(If_empty1) { WASM_EXEC_TEST(If_empty1) {
WasmRunner<uint32_t> r(MachineType::Uint32(), MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32(),
MachineType::Uint32());
BUILD(r, WASM_GET_LOCAL(0), kExprIf, kExprEnd, WASM_GET_LOCAL(1)); BUILD(r, WASM_GET_LOCAL(0), kExprIf, kExprEnd, WASM_GET_LOCAL(1));
FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i - 9, *i)); } FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i - 9, *i)); }
} }
WASM_EXEC_TEST(IfElse_empty1) { WASM_EXEC_TEST(IfElse_empty1) {
WasmRunner<uint32_t> r(MachineType::Uint32(), MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32(),
MachineType::Uint32());
BUILD(r, WASM_GET_LOCAL(0), kExprIf, kExprElse, kExprEnd, WASM_GET_LOCAL(1)); BUILD(r, WASM_GET_LOCAL(0), kExprIf, kExprElse, kExprEnd, WASM_GET_LOCAL(1));
FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i - 8, *i)); } FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i - 8, *i)); }
} }
WASM_EXEC_TEST(IfElse_empty2) { WASM_EXEC_TEST(IfElse_empty2) {
WasmRunner<uint32_t> r(MachineType::Uint32(), MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32(),
MachineType::Uint32());
BUILD(r, WASM_GET_LOCAL(0), kExprIf, WASM_ZERO, kExprElse, kExprEnd, BUILD(r, WASM_GET_LOCAL(0), kExprIf, WASM_ZERO, kExprElse, kExprEnd,
WASM_GET_LOCAL(1)); WASM_GET_LOCAL(1));
FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i - 7, *i)); } FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i - 7, *i)); }
} }
WASM_EXEC_TEST(IfElse_empty3) { WASM_EXEC_TEST(IfElse_empty3) {
WasmRunner<uint32_t> r(MachineType::Uint32(), MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32(),
MachineType::Uint32());
BUILD(r, WASM_GET_LOCAL(0), kExprIf, kExprElse, WASM_ZERO, kExprEnd, BUILD(r, WASM_GET_LOCAL(0), kExprIf, kExprElse, WASM_ZERO, kExprEnd,
WASM_GET_LOCAL(1)); WASM_GET_LOCAL(1));
FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i - 6, *i)); } FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i - 6, *i)); }
} }
WASM_EXEC_TEST(If_chain) { WASM_EXEC_TEST(If_chain) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// if (p0) 13; if (p0) 14; 15 // if (p0) 13; if (p0) 14; 15
BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_I8(13)), BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_I8(13)),
WASM_IF(WASM_GET_LOCAL(0), WASM_I8(14)), WASM_I8(15)); WASM_IF(WASM_GET_LOCAL(0), WASM_I8(14)), WASM_I8(15));
...@@ -653,7 +681,8 @@ WASM_EXEC_TEST(If_chain) { ...@@ -653,7 +681,8 @@ WASM_EXEC_TEST(If_chain) {
} }
WASM_EXEC_TEST(If_chain_set) { WASM_EXEC_TEST(If_chain_set) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
// if (p0) p1 = 73; if (p0) p1 = 74; p1 // if (p0) p1 = 73; if (p0) p1 = 74; p1
BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_SET_LOCAL(1, WASM_I8(73))), BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_SET_LOCAL(1, WASM_I8(73))),
WASM_IF(WASM_GET_LOCAL(0), WASM_SET_LOCAL(1, WASM_I8(74))), WASM_IF(WASM_GET_LOCAL(0), WASM_SET_LOCAL(1, WASM_I8(74))),
...@@ -665,7 +694,7 @@ WASM_EXEC_TEST(If_chain_set) { ...@@ -665,7 +694,7 @@ WASM_EXEC_TEST(If_chain_set) {
} }
WASM_EXEC_TEST(IfElse_Unreachable1) { WASM_EXEC_TEST(IfElse_Unreachable1) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
// if (0) unreachable; else return 22; // if (0) unreachable; else return 22;
BUILD(r, WASM_IF_ELSE(WASM_ZERO, // -- BUILD(r, WASM_IF_ELSE(WASM_ZERO, // --
WASM_UNREACHABLE, // -- WASM_UNREACHABLE, // --
...@@ -674,21 +703,21 @@ WASM_EXEC_TEST(IfElse_Unreachable1) { ...@@ -674,21 +703,21 @@ WASM_EXEC_TEST(IfElse_Unreachable1) {
} }
WASM_EXEC_TEST(Return12) { WASM_EXEC_TEST(Return12) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
BUILD(r, RET_I8(12)); BUILD(r, RET_I8(12));
CHECK_EQ(12, r.Call()); CHECK_EQ(12, r.Call());
} }
WASM_EXEC_TEST(Return17) { WASM_EXEC_TEST(Return17) {
WasmRunner<int32_t> r; WasmRunner<int32_t> r(execution_mode);
BUILD(r, B1(RET_I8(17))); BUILD(r, B1(RET_I8(17)));
CHECK_EQ(17, r.Call()); CHECK_EQ(17, r.Call());
} }
WASM_EXEC_TEST(Return_I32) { WASM_EXEC_TEST(Return_I32) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, RET(WASM_GET_LOCAL(0))); BUILD(r, RET(WASM_GET_LOCAL(0)));
...@@ -696,7 +725,7 @@ WASM_EXEC_TEST(Return_I32) { ...@@ -696,7 +725,7 @@ WASM_EXEC_TEST(Return_I32) {
} }
WASM_EXEC_TEST(Return_F32) { WASM_EXEC_TEST(Return_F32) {
WasmRunner<float> r(MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32());
BUILD(r, RET(WASM_GET_LOCAL(0))); BUILD(r, RET(WASM_GET_LOCAL(0)));
...@@ -712,7 +741,7 @@ WASM_EXEC_TEST(Return_F32) { ...@@ -712,7 +741,7 @@ WASM_EXEC_TEST(Return_F32) {
} }
WASM_EXEC_TEST(Return_F64) { WASM_EXEC_TEST(Return_F64) {
WasmRunner<double> r(MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64());
BUILD(r, RET(WASM_GET_LOCAL(0))); BUILD(r, RET(WASM_GET_LOCAL(0)));
...@@ -728,7 +757,7 @@ WASM_EXEC_TEST(Return_F64) { ...@@ -728,7 +757,7 @@ WASM_EXEC_TEST(Return_F64) {
} }
WASM_EXEC_TEST(Select) { WASM_EXEC_TEST(Select) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// return select(11, 22, a); // return select(11, 22, a);
BUILD(r, WASM_SELECT(WASM_I8(11), WASM_I8(22), WASM_GET_LOCAL(0))); BUILD(r, WASM_SELECT(WASM_I8(11), WASM_I8(22), WASM_GET_LOCAL(0)));
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
...@@ -738,7 +767,7 @@ WASM_EXEC_TEST(Select) { ...@@ -738,7 +767,7 @@ WASM_EXEC_TEST(Select) {
} }
WASM_EXEC_TEST(Select_strict1) { WASM_EXEC_TEST(Select_strict1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// select(a=0, a=1, a=2); return a // select(a=0, a=1, a=2); return a
BUILD(r, B2(WASM_SELECT(WASM_SET_LOCAL(0, WASM_I8(0)), BUILD(r, B2(WASM_SELECT(WASM_SET_LOCAL(0, WASM_I8(0)),
WASM_SET_LOCAL(0, WASM_I8(1)), WASM_SET_LOCAL(0, WASM_I8(1)),
...@@ -748,7 +777,7 @@ WASM_EXEC_TEST(Select_strict1) { ...@@ -748,7 +777,7 @@ WASM_EXEC_TEST(Select_strict1) {
} }
WASM_EXEC_TEST(Select_strict2) { WASM_EXEC_TEST(Select_strict2) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
r.AllocateLocal(kAstI32); r.AllocateLocal(kAstI32);
r.AllocateLocal(kAstI32); r.AllocateLocal(kAstI32);
// select(b=5, c=6, a) // select(b=5, c=6, a)
...@@ -761,7 +790,7 @@ WASM_EXEC_TEST(Select_strict2) { ...@@ -761,7 +790,7 @@ WASM_EXEC_TEST(Select_strict2) {
} }
WASM_EXEC_TEST(Select_strict3) { WASM_EXEC_TEST(Select_strict3) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
r.AllocateLocal(kAstI32); r.AllocateLocal(kAstI32);
r.AllocateLocal(kAstI32); r.AllocateLocal(kAstI32);
// select(b=5, c=6, a=b) // select(b=5, c=6, a=b)
...@@ -775,7 +804,7 @@ WASM_EXEC_TEST(Select_strict3) { ...@@ -775,7 +804,7 @@ WASM_EXEC_TEST(Select_strict3) {
} }
WASM_EXEC_TEST(BrIf_strict) { WASM_EXEC_TEST(BrIf_strict) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD( BUILD(
r, r,
B2(B1(WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_SET_LOCAL(0, WASM_I8(99)))), B2(B1(WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_SET_LOCAL(0, WASM_I8(99)))),
...@@ -785,14 +814,14 @@ WASM_EXEC_TEST(BrIf_strict) { ...@@ -785,14 +814,14 @@ WASM_EXEC_TEST(BrIf_strict) {
} }
WASM_EXEC_TEST(BrTable0a) { WASM_EXEC_TEST(BrTable0a) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, BUILD(r,
B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 0, BR_TARGET(0))), WASM_I8(91))); B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 0, BR_TARGET(0))), WASM_I8(91)));
FOR_INT32_INPUTS(i) { CHECK_EQ(91, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(91, r.Call(*i)); }
} }
WASM_EXEC_TEST(BrTable0b) { WASM_EXEC_TEST(BrTable0b) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, BUILD(r,
B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 1, BR_TARGET(0), BR_TARGET(0))), B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 1, BR_TARGET(0), BR_TARGET(0))),
WASM_I8(92))); WASM_I8(92)));
...@@ -800,7 +829,7 @@ WASM_EXEC_TEST(BrTable0b) { ...@@ -800,7 +829,7 @@ WASM_EXEC_TEST(BrTable0b) {
} }
WASM_EXEC_TEST(BrTable0c) { WASM_EXEC_TEST(BrTable0c) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD( BUILD(
r, r,
B2(B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 1, BR_TARGET(0), BR_TARGET(1))), B2(B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 1, BR_TARGET(0), BR_TARGET(1))),
...@@ -813,13 +842,13 @@ WASM_EXEC_TEST(BrTable0c) { ...@@ -813,13 +842,13 @@ WASM_EXEC_TEST(BrTable0c) {
} }
WASM_EXEC_TEST(BrTable1) { WASM_EXEC_TEST(BrTable1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 0, BR_TARGET(0))), RET_I8(93)); BUILD(r, B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 0, BR_TARGET(0))), RET_I8(93));
FOR_INT32_INPUTS(i) { CHECK_EQ(93, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(93, r.Call(*i)); }
} }
WASM_EXEC_TEST(BrTable_loop) { WASM_EXEC_TEST(BrTable_loop) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, BUILD(r,
B2(WASM_LOOP(1, WASM_BR_TABLE(WASM_INC_LOCAL_BY(0, 1), 2, BR_TARGET(2), B2(WASM_LOOP(1, WASM_BR_TABLE(WASM_INC_LOCAL_BY(0, 1), 2, BR_TARGET(2),
BR_TARGET(1), BR_TARGET(0))), BR_TARGET(1), BR_TARGET(0))),
...@@ -833,7 +862,7 @@ WASM_EXEC_TEST(BrTable_loop) { ...@@ -833,7 +862,7 @@ WASM_EXEC_TEST(BrTable_loop) {
} }
WASM_EXEC_TEST(BrTable_br) { WASM_EXEC_TEST(BrTable_br) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, BUILD(r,
B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 1, BR_TARGET(1), BR_TARGET(0))), B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 1, BR_TARGET(1), BR_TARGET(0))),
RET_I8(91)), RET_I8(91)),
...@@ -845,7 +874,7 @@ WASM_EXEC_TEST(BrTable_br) { ...@@ -845,7 +874,7 @@ WASM_EXEC_TEST(BrTable_br) {
} }
WASM_EXEC_TEST(BrTable_br2) { WASM_EXEC_TEST(BrTable_br2) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(B2(B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 3, BR_TARGET(1), BUILD(r, B2(B2(B2(B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 3, BR_TARGET(1),
BR_TARGET(2), BR_TARGET(3), BR_TARGET(0))), BR_TARGET(2), BR_TARGET(3), BR_TARGET(0))),
...@@ -876,7 +905,7 @@ WASM_EXEC_TEST(BrTable4) { ...@@ -876,7 +905,7 @@ WASM_EXEC_TEST(BrTable4) {
RET_I8(73)), RET_I8(73)),
WASM_I8(75)}; WASM_I8(75)};
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
r.Build(code, code + arraysize(code)); r.Build(code, code + arraysize(code));
for (int x = -3; x < 50; x++) { for (int x = -3; x < 50; x++) {
...@@ -906,7 +935,7 @@ WASM_EXEC_TEST(BrTable4x4) { ...@@ -906,7 +935,7 @@ WASM_EXEC_TEST(BrTable4x4) {
RET_I8(53)), RET_I8(53)),
WASM_I8(55)}; WASM_I8(55)};
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
r.Build(code, code + arraysize(code)); r.Build(code, code + arraysize(code));
for (int x = -6; x < 47; x++) { for (int x = -6; x < 47; x++) {
...@@ -931,7 +960,8 @@ WASM_EXEC_TEST(BrTable4_fallthru) { ...@@ -931,7 +960,8 @@ WASM_EXEC_TEST(BrTable4_fallthru) {
WASM_INC_LOCAL_BY(1, 8)), WASM_INC_LOCAL_BY(1, 8)),
WASM_GET_LOCAL(1)}; WASM_GET_LOCAL(1)};
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
r.Build(code, code + arraysize(code)); r.Build(code, code + arraysize(code));
CHECK_EQ(15, r.Call(0, 0)); CHECK_EQ(15, r.Call(0, 0));
...@@ -948,7 +978,7 @@ WASM_EXEC_TEST(BrTable4_fallthru) { ...@@ -948,7 +978,7 @@ WASM_EXEC_TEST(BrTable4_fallthru) {
} }
WASM_EXEC_TEST(F32ReinterpretI32) { WASM_EXEC_TEST(F32ReinterpretI32) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(8); int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module); WasmRunner<int32_t> r(&module);
...@@ -963,7 +993,7 @@ WASM_EXEC_TEST(F32ReinterpretI32) { ...@@ -963,7 +993,7 @@ WASM_EXEC_TEST(F32ReinterpretI32) {
} }
WASM_EXEC_TEST(I32ReinterpretF32) { WASM_EXEC_TEST(I32ReinterpretF32) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(8); int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
...@@ -980,7 +1010,7 @@ WASM_EXEC_TEST(I32ReinterpretF32) { ...@@ -980,7 +1010,7 @@ WASM_EXEC_TEST(I32ReinterpretF32) {
} }
WASM_EXEC_TEST(ReturnStore) { WASM_EXEC_TEST(ReturnStore) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(8); int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module); WasmRunner<int32_t> r(&module);
...@@ -999,7 +1029,7 @@ WASM_EXEC_TEST(VoidReturn1) { ...@@ -999,7 +1029,7 @@ WASM_EXEC_TEST(VoidReturn1) {
// Build the test function. // Build the test function.
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t(sigs.v_v(), &module); WasmFunctionCompiler t(sigs.v_v(), &module);
BUILD(t, kExprNop); BUILD(t, kExprNop);
uint32_t index = t.CompileAndAdd(); uint32_t index = t.CompileAndAdd();
...@@ -1017,7 +1047,7 @@ WASM_EXEC_TEST(VoidReturn2) { ...@@ -1017,7 +1047,7 @@ WASM_EXEC_TEST(VoidReturn2) {
// We use a wrapper function because WasmRunner<void> does not exist. // We use a wrapper function because WasmRunner<void> does not exist.
// Build the test function. // Build the test function.
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t(sigs.v_v(), &module); WasmFunctionCompiler t(sigs.v_v(), &module);
BUILD(t, WASM_RETURN0); BUILD(t, WASM_RETURN0);
uint32_t index = t.CompileAndAdd(); uint32_t index = t.CompileAndAdd();
...@@ -1032,37 +1062,38 @@ WASM_EXEC_TEST(VoidReturn2) { ...@@ -1032,37 +1062,38 @@ WASM_EXEC_TEST(VoidReturn2) {
} }
WASM_EXEC_TEST(Block_empty) { WASM_EXEC_TEST(Block_empty) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, kExprBlock, kExprEnd, WASM_GET_LOCAL(0)); BUILD(r, kExprBlock, kExprEnd, WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
WASM_EXEC_TEST(Block_empty_br1) { WASM_EXEC_TEST(Block_empty_br1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B1(WASM_BR(0)), WASM_GET_LOCAL(0)); BUILD(r, B1(WASM_BR(0)), WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
WASM_EXEC_TEST(Block_empty_brif1) { WASM_EXEC_TEST(Block_empty_brif1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B1(WASM_BR_IF(0, WASM_ZERO)), WASM_GET_LOCAL(0)); BUILD(r, B1(WASM_BR_IF(0, WASM_ZERO)), WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
WASM_EXEC_TEST(Block_empty_brif2) { WASM_EXEC_TEST(Block_empty_brif2) {
WasmRunner<uint32_t> r(MachineType::Uint32(), MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32(),
MachineType::Uint32());
BUILD(r, B1(WASM_BR_IF(0, WASM_GET_LOCAL(1))), WASM_GET_LOCAL(0)); BUILD(r, B1(WASM_BR_IF(0, WASM_GET_LOCAL(1))), WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i, *i + 1)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i, *i + 1)); }
} }
WASM_EXEC_TEST(Block_br2) { WASM_EXEC_TEST(Block_br2) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B1(WASM_BRV(0, WASM_GET_LOCAL(0)))); BUILD(r, B1(WASM_BRV(0, WASM_GET_LOCAL(0))));
FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
WASM_EXEC_TEST(Block_If_P) { WASM_EXEC_TEST(Block_If_P) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// { if (p0) return 51; return 52; } // { if (p0) return 51; return 52; }
BUILD(r, B2( // -- BUILD(r, B2( // --
WASM_IF(WASM_GET_LOCAL(0), // -- WASM_IF(WASM_GET_LOCAL(0), // --
...@@ -1075,31 +1106,32 @@ WASM_EXEC_TEST(Block_If_P) { ...@@ -1075,31 +1106,32 @@ WASM_EXEC_TEST(Block_If_P) {
} }
WASM_EXEC_TEST(Loop_empty) { WASM_EXEC_TEST(Loop_empty) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, kExprLoop, kExprEnd, WASM_GET_LOCAL(0)); BUILD(r, kExprLoop, kExprEnd, WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
WASM_EXEC_TEST(Loop_empty_br1) { WASM_EXEC_TEST(Loop_empty_br1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, WASM_LOOP(1, WASM_BR(1)), WASM_GET_LOCAL(0)); BUILD(r, WASM_LOOP(1, WASM_BR(1)), WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
WASM_EXEC_TEST(Loop_empty_brif1) { WASM_EXEC_TEST(Loop_empty_brif1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, WASM_LOOP(1, WASM_BR_IF(1, WASM_ZERO)), WASM_GET_LOCAL(0)); BUILD(r, WASM_LOOP(1, WASM_BR_IF(1, WASM_ZERO)), WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); }
} }
WASM_EXEC_TEST(Loop_empty_brif2) { WASM_EXEC_TEST(Loop_empty_brif2) {
WasmRunner<uint32_t> r(MachineType::Uint32(), MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32(),
MachineType::Uint32());
BUILD(r, WASM_LOOP(1, WASM_BR_IF(1, WASM_GET_LOCAL(1))), WASM_GET_LOCAL(0)); BUILD(r, WASM_LOOP(1, WASM_BR_IF(1, WASM_GET_LOCAL(1))), WASM_GET_LOCAL(0));
FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i, *i + 1)); } FOR_UINT32_INPUTS(i) { CHECK_EQ(*i, r.Call(*i, *i + 1)); }
} }
WASM_EXEC_TEST(Block_BrIf_P) { WASM_EXEC_TEST(Block_BrIf_P) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_BRV_IF(0, WASM_I8(51), WASM_GET_LOCAL(0)), WASM_I8(52))); BUILD(r, B2(WASM_BRV_IF(0, WASM_I8(51), WASM_GET_LOCAL(0)), WASM_I8(52)));
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
int32_t expected = *i ? 51 : 52; int32_t expected = *i ? 51 : 52;
...@@ -1108,7 +1140,7 @@ WASM_EXEC_TEST(Block_BrIf_P) { ...@@ -1108,7 +1140,7 @@ WASM_EXEC_TEST(Block_BrIf_P) {
} }
WASM_EXEC_TEST(Block_IfElse_P_assign) { WASM_EXEC_TEST(Block_IfElse_P_assign) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// { if (p0) p0 = 71; else p0 = 72; return p0; } // { if (p0) p0 = 71; else p0 = 72; return p0; }
BUILD(r, B2( // -- BUILD(r, B2( // --
WASM_IF_ELSE(WASM_GET_LOCAL(0), // -- WASM_IF_ELSE(WASM_GET_LOCAL(0), // --
...@@ -1122,7 +1154,7 @@ WASM_EXEC_TEST(Block_IfElse_P_assign) { ...@@ -1122,7 +1154,7 @@ WASM_EXEC_TEST(Block_IfElse_P_assign) {
} }
WASM_EXEC_TEST(Block_IfElse_P_return) { WASM_EXEC_TEST(Block_IfElse_P_return) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// if (p0) return 81; else return 82; // if (p0) return 81; else return 82;
BUILD(r, // -- BUILD(r, // --
WASM_IF_ELSE(WASM_GET_LOCAL(0), // -- WASM_IF_ELSE(WASM_GET_LOCAL(0), // --
...@@ -1135,7 +1167,7 @@ WASM_EXEC_TEST(Block_IfElse_P_return) { ...@@ -1135,7 +1167,7 @@ WASM_EXEC_TEST(Block_IfElse_P_return) {
} }
WASM_EXEC_TEST(Block_If_P_assign) { WASM_EXEC_TEST(Block_If_P_assign) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// { if (p0) p0 = 61; p0; } // { if (p0) p0 = 61; p0; }
BUILD(r, WASM_BLOCK( BUILD(r, WASM_BLOCK(
2, WASM_IF(WASM_GET_LOCAL(0), WASM_SET_LOCAL(0, WASM_I8(61))), 2, WASM_IF(WASM_GET_LOCAL(0), WASM_SET_LOCAL(0, WASM_I8(61))),
...@@ -1147,14 +1179,14 @@ WASM_EXEC_TEST(Block_If_P_assign) { ...@@ -1147,14 +1179,14 @@ WASM_EXEC_TEST(Block_If_P_assign) {
} }
WASM_EXEC_TEST(DanglingAssign) { WASM_EXEC_TEST(DanglingAssign) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// { return 0; p0 = 0; } // { return 0; p0 = 0; }
BUILD(r, B2(RET_I8(99), WASM_SET_LOCAL(0, WASM_ZERO))); BUILD(r, B2(RET_I8(99), WASM_SET_LOCAL(0, WASM_ZERO)));
CHECK_EQ(99, r.Call(1)); CHECK_EQ(99, r.Call(1));
} }
WASM_EXEC_TEST(ExprIf_P) { WASM_EXEC_TEST(ExprIf_P) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// p0 ? 11 : 22; // p0 ? 11 : 22;
BUILD(r, WASM_IF_ELSE(WASM_GET_LOCAL(0), // -- BUILD(r, WASM_IF_ELSE(WASM_GET_LOCAL(0), // --
WASM_I8(11), // -- WASM_I8(11), // --
...@@ -1166,7 +1198,7 @@ WASM_EXEC_TEST(ExprIf_P) { ...@@ -1166,7 +1198,7 @@ WASM_EXEC_TEST(ExprIf_P) {
} }
WASM_EXEC_TEST(ExprIf_P_fallthru) { WASM_EXEC_TEST(ExprIf_P_fallthru) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// p0 ? 11 : 22; // p0 ? 11 : 22;
BUILD(r, WASM_IF_ELSE(WASM_GET_LOCAL(0), // -- BUILD(r, WASM_IF_ELSE(WASM_GET_LOCAL(0), // --
WASM_I8(11), // -- WASM_I8(11), // --
...@@ -1178,7 +1210,7 @@ WASM_EXEC_TEST(ExprIf_P_fallthru) { ...@@ -1178,7 +1210,7 @@ WASM_EXEC_TEST(ExprIf_P_fallthru) {
} }
WASM_EXEC_TEST(CountDown) { WASM_EXEC_TEST(CountDown) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, BUILD(r,
WASM_BLOCK( WASM_BLOCK(
2, WASM_LOOP( 2, WASM_LOOP(
...@@ -1193,7 +1225,7 @@ WASM_EXEC_TEST(CountDown) { ...@@ -1193,7 +1225,7 @@ WASM_EXEC_TEST(CountDown) {
} }
WASM_EXEC_TEST(CountDown_fallthru) { WASM_EXEC_TEST(CountDown_fallthru) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, BUILD(r,
WASM_BLOCK( WASM_BLOCK(
2, WASM_LOOP(3, WASM_IF(WASM_NOT(WASM_GET_LOCAL(0)), WASM_BREAK(1)), 2, WASM_LOOP(3, WASM_IF(WASM_NOT(WASM_GET_LOCAL(0)), WASM_BREAK(1)),
...@@ -1207,7 +1239,7 @@ WASM_EXEC_TEST(CountDown_fallthru) { ...@@ -1207,7 +1239,7 @@ WASM_EXEC_TEST(CountDown_fallthru) {
} }
WASM_EXEC_TEST(WhileCountDown) { WASM_EXEC_TEST(WhileCountDown) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, WASM_BLOCK( BUILD(r, WASM_BLOCK(
2, WASM_WHILE(WASM_GET_LOCAL(0), 2, WASM_WHILE(WASM_GET_LOCAL(0),
WASM_SET_LOCAL(0, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_SET_LOCAL(0, WASM_I32_SUB(WASM_GET_LOCAL(0),
...@@ -1219,7 +1251,7 @@ WASM_EXEC_TEST(WhileCountDown) { ...@@ -1219,7 +1251,7 @@ WASM_EXEC_TEST(WhileCountDown) {
} }
WASM_EXEC_TEST(Loop_if_break1) { WASM_EXEC_TEST(Loop_if_break1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_LOOP(2, WASM_IF(WASM_GET_LOCAL(0), WASM_BREAK(1)), BUILD(r, B2(WASM_LOOP(2, WASM_IF(WASM_GET_LOCAL(0), WASM_BREAK(1)),
WASM_SET_LOCAL(0, WASM_I8(99))), WASM_SET_LOCAL(0, WASM_I8(99))),
WASM_GET_LOCAL(0))); WASM_GET_LOCAL(0)));
...@@ -1230,7 +1262,7 @@ WASM_EXEC_TEST(Loop_if_break1) { ...@@ -1230,7 +1262,7 @@ WASM_EXEC_TEST(Loop_if_break1) {
} }
WASM_EXEC_TEST(Loop_if_break2) { WASM_EXEC_TEST(Loop_if_break2) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_LOOP(2, WASM_BR_IF(1, WASM_GET_LOCAL(0)), BUILD(r, B2(WASM_LOOP(2, WASM_BR_IF(1, WASM_GET_LOCAL(0)),
WASM_SET_LOCAL(0, WASM_I8(99))), WASM_SET_LOCAL(0, WASM_I8(99))),
WASM_GET_LOCAL(0))); WASM_GET_LOCAL(0)));
...@@ -1241,7 +1273,7 @@ WASM_EXEC_TEST(Loop_if_break2) { ...@@ -1241,7 +1273,7 @@ WASM_EXEC_TEST(Loop_if_break2) {
} }
WASM_EXEC_TEST(Loop_if_break_fallthru) { WASM_EXEC_TEST(Loop_if_break_fallthru) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B1(WASM_LOOP(2, WASM_IF(WASM_GET_LOCAL(0), WASM_BREAK(1)), BUILD(r, B1(WASM_LOOP(2, WASM_IF(WASM_GET_LOCAL(0), WASM_BREAK(1)),
WASM_SET_LOCAL(0, WASM_I8(93)))), WASM_SET_LOCAL(0, WASM_I8(93)))),
WASM_GET_LOCAL(0)); WASM_GET_LOCAL(0));
...@@ -1252,7 +1284,7 @@ WASM_EXEC_TEST(Loop_if_break_fallthru) { ...@@ -1252,7 +1284,7 @@ WASM_EXEC_TEST(Loop_if_break_fallthru) {
} }
WASM_EXEC_TEST(IfBreak1) { WASM_EXEC_TEST(IfBreak1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_SEQ(WASM_BR(0), WASM_UNREACHABLE)), BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_SEQ(WASM_BR(0), WASM_UNREACHABLE)),
WASM_I8(91)); WASM_I8(91));
CHECK_EQ(91, r.Call(0)); CHECK_EQ(91, r.Call(0));
...@@ -1261,7 +1293,7 @@ WASM_EXEC_TEST(IfBreak1) { ...@@ -1261,7 +1293,7 @@ WASM_EXEC_TEST(IfBreak1) {
} }
WASM_EXEC_TEST(IfBreak2) { WASM_EXEC_TEST(IfBreak2) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_SEQ(WASM_BR(0), RET_I8(77))), BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_SEQ(WASM_BR(0), RET_I8(77))),
WASM_I8(81)); WASM_I8(81));
CHECK_EQ(81, r.Call(0)); CHECK_EQ(81, r.Call(0));
...@@ -1270,7 +1302,7 @@ WASM_EXEC_TEST(IfBreak2) { ...@@ -1270,7 +1302,7 @@ WASM_EXEC_TEST(IfBreak2) {
} }
WASM_EXEC_TEST(LoadMemI32) { WASM_EXEC_TEST(LoadMemI32) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(8); int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
module.RandomizeMemory(1111); module.RandomizeMemory(1111);
...@@ -1287,8 +1319,8 @@ WASM_EXEC_TEST(LoadMemI32) { ...@@ -1287,8 +1319,8 @@ WASM_EXEC_TEST(LoadMemI32) {
CHECK_EQ(77777777, r.Call(0)); CHECK_EQ(77777777, r.Call(0));
} }
WASM_EXEC_TEST(Run_Wasm_LoadMemI32_alignment) { WASM_EXEC_TEST(LoadMemI32_alignment) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(8); int32_t* memory = module.AddMemoryElems<int32_t>(8);
for (byte alignment = 0; alignment <= 2; alignment++) { for (byte alignment = 0; alignment <= 2; alignment++) {
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
...@@ -1308,8 +1340,8 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI32_alignment) { ...@@ -1308,8 +1340,8 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI32_alignment) {
} }
} }
WASM_EXEC_TEST(Run_Wasm_LoadMemI32_oob) { WASM_EXEC_TEST(LoadMemI32_oob) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(8); int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module, MachineType::Uint32()); WasmRunner<int32_t> r(&module, MachineType::Uint32());
module.RandomizeMemory(1111); module.RandomizeMemory(1111);
...@@ -1328,7 +1360,7 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI32_oob) { ...@@ -1328,7 +1360,7 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI32_oob) {
} }
WASM_EXEC_TEST(LoadMem_offset_oob) { WASM_EXEC_TEST(LoadMem_offset_oob) {
TestingModule module; TestingModule module(execution_mode);
module.AddMemoryElems<int32_t>(8); module.AddMemoryElems<int32_t>(8);
static const MachineType machineTypes[] = { static const MachineType machineTypes[] = {
...@@ -1354,7 +1386,7 @@ WASM_EXEC_TEST(LoadMem_offset_oob) { ...@@ -1354,7 +1386,7 @@ WASM_EXEC_TEST(LoadMem_offset_oob) {
} }
WASM_EXEC_TEST(LoadMemI32_offset) { WASM_EXEC_TEST(LoadMemI32_offset) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(4); int32_t* memory = module.AddMemoryElems<int32_t>(4);
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
module.RandomizeMemory(1111); module.RandomizeMemory(1111);
...@@ -1378,12 +1410,12 @@ WASM_EXEC_TEST(LoadMemI32_offset) { ...@@ -1378,12 +1410,12 @@ WASM_EXEC_TEST(LoadMemI32_offset) {
CHECK_EQ(44444444, r.Call(8)); CHECK_EQ(44444444, r.Call(8));
} }
WASM_EXEC_TEST(Run_Wasm_LoadMemI32_const_oob_misaligned) { WASM_EXEC_TEST(LoadMemI32_const_oob_misaligned) {
const int kMemSize = 12; const int kMemSize = 12;
// TODO(titzer): Fix misaligned accesses on MIPS and re-enable. // TODO(titzer): Fix misaligned accesses on MIPS and re-enable.
for (int offset = 0; offset < kMemSize + 5; offset++) { for (int offset = 0; offset < kMemSize + 5; offset++) {
for (int index = 0; index < kMemSize + 5; index++) { for (int index = 0; index < kMemSize + 5; index++) {
TestingModule module; TestingModule module(execution_mode);
module.AddMemoryElems<byte>(kMemSize); module.AddMemoryElems<byte>(kMemSize);
WasmRunner<int32_t> r(&module); WasmRunner<int32_t> r(&module);
...@@ -1401,11 +1433,11 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI32_const_oob_misaligned) { ...@@ -1401,11 +1433,11 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI32_const_oob_misaligned) {
} }
} }
WASM_EXEC_TEST(Run_Wasm_LoadMemI32_const_oob) { WASM_EXEC_TEST(LoadMemI32_const_oob) {
const int kMemSize = 24; const int kMemSize = 24;
for (int offset = 0; offset < kMemSize + 5; offset += 4) { for (int offset = 0; offset < kMemSize + 5; offset += 4) {
for (int index = 0; index < kMemSize + 5; index += 4) { for (int index = 0; index < kMemSize + 5; index += 4) {
TestingModule module; TestingModule module(execution_mode);
module.AddMemoryElems<byte>(kMemSize); module.AddMemoryElems<byte>(kMemSize);
WasmRunner<int32_t> r(&module); WasmRunner<int32_t> r(&module);
...@@ -1423,8 +1455,8 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI32_const_oob) { ...@@ -1423,8 +1455,8 @@ WASM_EXEC_TEST(Run_Wasm_LoadMemI32_const_oob) {
} }
} }
WASM_EXEC_TEST(Run_Wasm_StoreMemI32_alignment) { WASM_EXEC_TEST(StoreMemI32_alignment) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(4); int32_t* memory = module.AddMemoryElems<int32_t>(4);
const int32_t kWritten = 0x12345678; const int32_t kWritten = 0x12345678;
...@@ -1440,8 +1472,8 @@ WASM_EXEC_TEST(Run_Wasm_StoreMemI32_alignment) { ...@@ -1440,8 +1472,8 @@ WASM_EXEC_TEST(Run_Wasm_StoreMemI32_alignment) {
} }
} }
WASM_EXEC_TEST(Run_Wasm_StoreMemI32_offset) { WASM_EXEC_TEST(StoreMemI32_offset) {
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(4); int32_t* memory = module.AddMemoryElems<int32_t>(4);
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
const int32_t kWritten = 0xaabbccdd; const int32_t kWritten = 0xaabbccdd;
...@@ -1464,7 +1496,7 @@ WASM_EXEC_TEST(Run_Wasm_StoreMemI32_offset) { ...@@ -1464,7 +1496,7 @@ WASM_EXEC_TEST(Run_Wasm_StoreMemI32_offset) {
} }
WASM_EXEC_TEST(StoreMem_offset_oob) { WASM_EXEC_TEST(StoreMem_offset_oob) {
TestingModule module; TestingModule module(execution_mode);
byte* memory = module.AddMemoryElems<byte>(32); byte* memory = module.AddMemoryElems<byte>(32);
#if WASM_64 #if WASM_64
...@@ -1501,7 +1533,7 @@ WASM_EXEC_TEST(StoreMem_offset_oob) { ...@@ -1501,7 +1533,7 @@ WASM_EXEC_TEST(StoreMem_offset_oob) {
WASM_EXEC_TEST(LoadMemI32_P) { WASM_EXEC_TEST(LoadMemI32_P) {
const int kNumElems = 8; const int kNumElems = 8;
TestingModule module; TestingModule module(execution_mode);
int32_t* memory = module.AddMemoryElems<int32_t>(kNumElems); int32_t* memory = module.AddMemoryElems<int32_t>(kNumElems);
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
module.RandomizeMemory(2222); module.RandomizeMemory(2222);
...@@ -1515,7 +1547,7 @@ WASM_EXEC_TEST(LoadMemI32_P) { ...@@ -1515,7 +1547,7 @@ WASM_EXEC_TEST(LoadMemI32_P) {
WASM_EXEC_TEST(MemI32_Sum) { WASM_EXEC_TEST(MemI32_Sum) {
const int kNumElems = 20; const int kNumElems = 20;
TestingModule module; TestingModule module(execution_mode);
uint32_t* memory = module.AddMemoryElems<uint32_t>(kNumElems); uint32_t* memory = module.AddMemoryElems<uint32_t>(kNumElems);
WasmRunner<uint32_t> r(&module, MachineType::Int32()); WasmRunner<uint32_t> r(&module, MachineType::Int32());
const byte kSum = r.AllocateLocal(kAstI32); const byte kSum = r.AllocateLocal(kAstI32);
...@@ -1547,7 +1579,7 @@ WASM_EXEC_TEST(MemI32_Sum) { ...@@ -1547,7 +1579,7 @@ WASM_EXEC_TEST(MemI32_Sum) {
WASM_EXEC_TEST(CheckMachIntsZero) { WASM_EXEC_TEST(CheckMachIntsZero) {
const int kNumElems = 55; const int kNumElems = 55;
TestingModule module; TestingModule module(execution_mode);
module.AddMemoryElems<uint32_t>(kNumElems); module.AddMemoryElems<uint32_t>(kNumElems);
WasmRunner<uint32_t> r(&module, MachineType::Int32()); WasmRunner<uint32_t> r(&module, MachineType::Int32());
...@@ -1562,7 +1594,7 @@ WASM_EXEC_TEST(CheckMachIntsZero) { ...@@ -1562,7 +1594,7 @@ WASM_EXEC_TEST(CheckMachIntsZero) {
WASM_EXEC_TEST(MemF32_Sum) { WASM_EXEC_TEST(MemF32_Sum) {
const int kSize = 5; const int kSize = 5;
TestingModule module; TestingModule module(execution_mode);
module.AddMemoryElems<float>(kSize); module.AddMemoryElems<float>(kSize);
float* buffer = module.raw_mem_start<float>(); float* buffer = module.raw_mem_start<float>();
buffer[0] = -99.25; buffer[0] = -99.25;
...@@ -1594,9 +1626,10 @@ WASM_EXEC_TEST(MemF32_Sum) { ...@@ -1594,9 +1626,10 @@ WASM_EXEC_TEST(MemF32_Sum) {
} }
template <typename T> template <typename T>
T GenerateAndRunFold(WasmOpcode binop, T* buffer, size_t size, T GenerateAndRunFold(WasmExecutionMode execution_mode, WasmOpcode binop,
LocalType astType, MachineType memType) { T* buffer, size_t size, LocalType astType,
TestingModule module; MachineType memType) {
TestingModule module(execution_mode);
module.AddMemoryElems<T>(size); module.AddMemoryElems<T>(size);
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
module.raw_mem_start<T>()[i] = buffer[i]; module.raw_mem_start<T>()[i] = buffer[i];
...@@ -1626,19 +1659,20 @@ T GenerateAndRunFold(WasmOpcode binop, T* buffer, size_t size, ...@@ -1626,19 +1659,20 @@ T GenerateAndRunFold(WasmOpcode binop, T* buffer, size_t size,
WASM_EXEC_TEST(MemF64_Mul) { WASM_EXEC_TEST(MemF64_Mul) {
const size_t kSize = 6; const size_t kSize = 6;
double buffer[kSize] = {1, 2, 2, 2, 2, 2}; double buffer[kSize] = {1, 2, 2, 2, 2, 2};
double result = GenerateAndRunFold<double>(kExprF64Mul, buffer, kSize, double result =
kAstF64, MachineType::Float64()); GenerateAndRunFold<double>(execution_mode, kExprF64Mul, buffer, kSize,
kAstF64, MachineType::Float64());
CHECK_EQ(32, result); CHECK_EQ(32, result);
} }
TEST(Build_Wasm_Infinite_Loop) { WASM_EXEC_TEST(Build_Wasm_Infinite_Loop) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// Only build the graph and compile, don't run. // Only build the graph and compile, don't run.
BUILD(r, WASM_INFINITE_LOOP); BUILD(r, WASM_INFINITE_LOOP);
} }
TEST(Build_Wasm_Infinite_Loop_effect) { WASM_EXEC_TEST(Build_Wasm_Infinite_Loop_effect) {
TestingModule module; TestingModule module(execution_mode);
module.AddMemoryElems<int8_t>(16); module.AddMemoryElems<int8_t>(16);
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
...@@ -1647,47 +1681,47 @@ TEST(Build_Wasm_Infinite_Loop_effect) { ...@@ -1647,47 +1681,47 @@ TEST(Build_Wasm_Infinite_Loop_effect) {
} }
WASM_EXEC_TEST(Unreachable0a) { WASM_EXEC_TEST(Unreachable0a) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_BRV(0, WASM_I8(9)), RET(WASM_GET_LOCAL(0)))); BUILD(r, B2(WASM_BRV(0, WASM_I8(9)), RET(WASM_GET_LOCAL(0))));
CHECK_EQ(9, r.Call(0)); CHECK_EQ(9, r.Call(0));
CHECK_EQ(9, r.Call(1)); CHECK_EQ(9, r.Call(1));
} }
WASM_EXEC_TEST(Unreachable0b) { WASM_EXEC_TEST(Unreachable0b) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_BRV(0, WASM_I8(7)), WASM_UNREACHABLE)); BUILD(r, B2(WASM_BRV(0, WASM_I8(7)), WASM_UNREACHABLE));
CHECK_EQ(7, r.Call(0)); CHECK_EQ(7, r.Call(0));
CHECK_EQ(7, r.Call(1)); CHECK_EQ(7, r.Call(1));
} }
TEST(Build_Wasm_Unreachable1) { TEST(Build_Wasm_Unreachable1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r, WASM_UNREACHABLE); BUILD(r, WASM_UNREACHABLE);
} }
TEST(Build_Wasm_Unreachable2) { TEST(Build_Wasm_Unreachable2) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r, WASM_UNREACHABLE, WASM_UNREACHABLE); BUILD(r, WASM_UNREACHABLE, WASM_UNREACHABLE);
} }
TEST(Build_Wasm_Unreachable3) { TEST(Build_Wasm_Unreachable3) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r, WASM_UNREACHABLE, WASM_UNREACHABLE, WASM_UNREACHABLE); BUILD(r, WASM_UNREACHABLE, WASM_UNREACHABLE, WASM_UNREACHABLE);
} }
TEST(Build_Wasm_UnreachableIf1) { TEST(Build_Wasm_UnreachableIf1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r, WASM_UNREACHABLE, WASM_IF(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))); BUILD(r, WASM_UNREACHABLE, WASM_IF(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0)));
} }
TEST(Build_Wasm_UnreachableIf2) { TEST(Build_Wasm_UnreachableIf2) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r, WASM_UNREACHABLE, BUILD(r, WASM_UNREACHABLE,
WASM_IF_ELSE(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_UNREACHABLE)); WASM_IF_ELSE(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_UNREACHABLE));
} }
WASM_EXEC_TEST(Unreachable_Load) { WASM_EXEC_TEST(Unreachable_Load) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_BRV(0, WASM_GET_LOCAL(0)), BUILD(r, B2(WASM_BRV(0, WASM_GET_LOCAL(0)),
WASM_LOAD_MEM(MachineType::Int8(), WASM_GET_LOCAL(0)))); WASM_LOAD_MEM(MachineType::Int8(), WASM_GET_LOCAL(0))));
CHECK_EQ(11, r.Call(11)); CHECK_EQ(11, r.Call(11));
...@@ -1695,14 +1729,14 @@ WASM_EXEC_TEST(Unreachable_Load) { ...@@ -1695,14 +1729,14 @@ WASM_EXEC_TEST(Unreachable_Load) {
} }
WASM_EXEC_TEST(Infinite_Loop_not_taken1) { WASM_EXEC_TEST(Infinite_Loop_not_taken1) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_IF(WASM_GET_LOCAL(0), WASM_INFINITE_LOOP), WASM_I8(45))); BUILD(r, B2(WASM_IF(WASM_GET_LOCAL(0), WASM_INFINITE_LOOP), WASM_I8(45)));
// Run the code, but don't go into the infinite loop. // Run the code, but don't go into the infinite loop.
CHECK_EQ(45, r.Call(0)); CHECK_EQ(45, r.Call(0));
} }
WASM_EXEC_TEST(Infinite_Loop_not_taken2) { WASM_EXEC_TEST(Infinite_Loop_not_taken2) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B1(WASM_IF_ELSE(WASM_GET_LOCAL(0), WASM_BRV(1, WASM_I8(45)), BUILD(r, B1(WASM_IF_ELSE(WASM_GET_LOCAL(0), WASM_BRV(1, WASM_I8(45)),
WASM_INFINITE_LOOP))); WASM_INFINITE_LOOP)));
// Run the code, but don't go into the infinite loop. // Run the code, but don't go into the infinite loop.
...@@ -1710,7 +1744,7 @@ WASM_EXEC_TEST(Infinite_Loop_not_taken2) { ...@@ -1710,7 +1744,7 @@ WASM_EXEC_TEST(Infinite_Loop_not_taken2) {
} }
WASM_EXEC_TEST(Infinite_Loop_not_taken2_brif) { WASM_EXEC_TEST(Infinite_Loop_not_taken2_brif) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, BUILD(r,
B2(WASM_BRV_IF(0, WASM_I8(45), WASM_GET_LOCAL(0)), WASM_INFINITE_LOOP)); B2(WASM_BRV_IF(0, WASM_I8(45), WASM_GET_LOCAL(0)), WASM_INFINITE_LOOP));
// Run the code, but don't go into the infinite loop. // Run the code, but don't go into the infinite loop.
...@@ -1753,7 +1787,7 @@ TEST(Build_Wasm_SimpleExprs) { ...@@ -1753,7 +1787,7 @@ TEST(Build_Wasm_SimpleExprs) {
} }
WASM_EXEC_TEST(Int32LoadInt8_signext) { WASM_EXEC_TEST(Int32LoadInt8_signext) {
TestingModule module; TestingModule module(execution_mode);
const int kNumElems = 16; const int kNumElems = 16;
int8_t* memory = module.AddMemoryElems<int8_t>(kNumElems); int8_t* memory = module.AddMemoryElems<int8_t>(kNumElems);
module.RandomizeMemory(); module.RandomizeMemory();
...@@ -1767,7 +1801,7 @@ WASM_EXEC_TEST(Int32LoadInt8_signext) { ...@@ -1767,7 +1801,7 @@ WASM_EXEC_TEST(Int32LoadInt8_signext) {
} }
WASM_EXEC_TEST(Int32LoadInt8_zeroext) { WASM_EXEC_TEST(Int32LoadInt8_zeroext) {
TestingModule module; TestingModule module(execution_mode);
const int kNumElems = 16; const int kNumElems = 16;
byte* memory = module.AddMemory(kNumElems); byte* memory = module.AddMemory(kNumElems);
module.RandomizeMemory(77); module.RandomizeMemory(77);
...@@ -1781,7 +1815,7 @@ WASM_EXEC_TEST(Int32LoadInt8_zeroext) { ...@@ -1781,7 +1815,7 @@ WASM_EXEC_TEST(Int32LoadInt8_zeroext) {
} }
WASM_EXEC_TEST(Int32LoadInt16_signext) { WASM_EXEC_TEST(Int32LoadInt16_signext) {
TestingModule module; TestingModule module(execution_mode);
const int kNumBytes = 16; const int kNumBytes = 16;
byte* memory = module.AddMemory(kNumBytes); byte* memory = module.AddMemory(kNumBytes);
module.RandomizeMemory(888); module.RandomizeMemory(888);
...@@ -1796,7 +1830,7 @@ WASM_EXEC_TEST(Int32LoadInt16_signext) { ...@@ -1796,7 +1830,7 @@ WASM_EXEC_TEST(Int32LoadInt16_signext) {
} }
WASM_EXEC_TEST(Int32LoadInt16_zeroext) { WASM_EXEC_TEST(Int32LoadInt16_zeroext) {
TestingModule module; TestingModule module(execution_mode);
const int kNumBytes = 16; const int kNumBytes = 16;
byte* memory = module.AddMemory(kNumBytes); byte* memory = module.AddMemory(kNumBytes);
module.RandomizeMemory(9999); module.RandomizeMemory(9999);
...@@ -1811,7 +1845,7 @@ WASM_EXEC_TEST(Int32LoadInt16_zeroext) { ...@@ -1811,7 +1845,7 @@ WASM_EXEC_TEST(Int32LoadInt16_zeroext) {
} }
WASM_EXEC_TEST(Int32Global) { WASM_EXEC_TEST(Int32Global) {
TestingModule module; TestingModule module(execution_mode);
int32_t* global = module.AddGlobal<int32_t>(MachineType::Int32()); int32_t* global = module.AddGlobal<int32_t>(MachineType::Int32());
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
// global = global + p0 // global = global + p0
...@@ -1828,7 +1862,7 @@ WASM_EXEC_TEST(Int32Global) { ...@@ -1828,7 +1862,7 @@ WASM_EXEC_TEST(Int32Global) {
WASM_EXEC_TEST(Int32Globals_DontAlias) { WASM_EXEC_TEST(Int32Globals_DontAlias) {
const int kNumGlobals = 3; const int kNumGlobals = 3;
TestingModule module; TestingModule module(execution_mode);
int32_t* globals[] = {module.AddGlobal<int32_t>(MachineType::Int32()), int32_t* globals[] = {module.AddGlobal<int32_t>(MachineType::Int32()),
module.AddGlobal<int32_t>(MachineType::Int32()), module.AddGlobal<int32_t>(MachineType::Int32()),
module.AddGlobal<int32_t>(MachineType::Int32())}; module.AddGlobal<int32_t>(MachineType::Int32())};
...@@ -1855,7 +1889,7 @@ WASM_EXEC_TEST(Int32Globals_DontAlias) { ...@@ -1855,7 +1889,7 @@ WASM_EXEC_TEST(Int32Globals_DontAlias) {
} }
WASM_EXEC_TEST(Float32Global) { WASM_EXEC_TEST(Float32Global) {
TestingModule module; TestingModule module(execution_mode);
float* global = module.AddGlobal<float>(MachineType::Float32()); float* global = module.AddGlobal<float>(MachineType::Float32());
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
// global = global + p0 // global = global + p0
...@@ -1873,7 +1907,7 @@ WASM_EXEC_TEST(Float32Global) { ...@@ -1873,7 +1907,7 @@ WASM_EXEC_TEST(Float32Global) {
} }
WASM_EXEC_TEST(Float64Global) { WASM_EXEC_TEST(Float64Global) {
TestingModule module; TestingModule module(execution_mode);
double* global = module.AddGlobal<double>(MachineType::Float64()); double* global = module.AddGlobal<double>(MachineType::Float64());
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
// global = global + p0 // global = global + p0
...@@ -1891,7 +1925,7 @@ WASM_EXEC_TEST(Float64Global) { ...@@ -1891,7 +1925,7 @@ WASM_EXEC_TEST(Float64Global) {
} }
WASM_EXEC_TEST(MixedGlobals) { WASM_EXEC_TEST(MixedGlobals) {
TestingModule module; TestingModule module(execution_mode);
int32_t* unused = module.AddGlobal<int32_t>(MachineType::Int32()); int32_t* unused = module.AddGlobal<int32_t>(MachineType::Int32());
byte* memory = module.AddMemory(32); byte* memory = module.AddMemory(32);
...@@ -1948,7 +1982,7 @@ WASM_EXEC_TEST(CallEmpty) { ...@@ -1948,7 +1982,7 @@ WASM_EXEC_TEST(CallEmpty) {
const int32_t kExpected = -414444; const int32_t kExpected = -414444;
// Build the target function. // Build the target function.
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t(sigs.i_v(), &module); WasmFunctionCompiler t(sigs.i_v(), &module);
BUILD(t, WASM_I32V_3(kExpected)); BUILD(t, WASM_I32V_3(kExpected));
uint32_t index = t.CompileAndAdd(); uint32_t index = t.CompileAndAdd();
...@@ -1966,7 +2000,7 @@ WASM_EXEC_TEST(CallF32StackParameter) { ...@@ -1966,7 +2000,7 @@ WASM_EXEC_TEST(CallF32StackParameter) {
LocalType param_types[20]; LocalType param_types[20];
for (int i = 0; i < 20; i++) param_types[i] = kAstF32; for (int i = 0; i < 20; i++) param_types[i] = kAstF32;
FunctionSig sig(1, 19, param_types); FunctionSig sig(1, 19, param_types);
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t(&sig, &module); WasmFunctionCompiler t(&sig, &module);
BUILD(t, WASM_GET_LOCAL(17)); BUILD(t, WASM_GET_LOCAL(17));
uint32_t index = t.CompileAndAdd(); uint32_t index = t.CompileAndAdd();
...@@ -1990,7 +2024,7 @@ WASM_EXEC_TEST(CallF64StackParameter) { ...@@ -1990,7 +2024,7 @@ WASM_EXEC_TEST(CallF64StackParameter) {
LocalType param_types[20]; LocalType param_types[20];
for (int i = 0; i < 20; i++) param_types[i] = kAstF64; for (int i = 0; i < 20; i++) param_types[i] = kAstF64;
FunctionSig sig(1, 19, param_types); FunctionSig sig(1, 19, param_types);
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t(&sig, &module); WasmFunctionCompiler t(&sig, &module);
BUILD(t, WASM_GET_LOCAL(17)); BUILD(t, WASM_GET_LOCAL(17));
uint32_t index = t.CompileAndAdd(); uint32_t index = t.CompileAndAdd();
...@@ -2015,7 +2049,7 @@ WASM_EXEC_TEST(CallVoid) { ...@@ -2015,7 +2049,7 @@ WASM_EXEC_TEST(CallVoid) {
const int32_t kExpected = -414444; const int32_t kExpected = -414444;
// Build the target function. // Build the target function.
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
module.AddMemory(16); module.AddMemory(16);
module.RandomizeMemory(); module.RandomizeMemory();
WasmFunctionCompiler t(sigs.v_v(), &module); WasmFunctionCompiler t(sigs.v_v(), &module);
...@@ -2036,7 +2070,7 @@ WASM_EXEC_TEST(CallVoid) { ...@@ -2036,7 +2070,7 @@ WASM_EXEC_TEST(CallVoid) {
WASM_EXEC_TEST(Call_Int32Add) { WASM_EXEC_TEST(Call_Int32Add) {
// Build the target function. // Build the target function.
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t(sigs.i_ii(), &module); WasmFunctionCompiler t(sigs.i_ii(), &module);
BUILD(t, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(t, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
uint32_t index = t.CompileAndAdd(); uint32_t index = t.CompileAndAdd();
...@@ -2056,7 +2090,7 @@ WASM_EXEC_TEST(Call_Int32Add) { ...@@ -2056,7 +2090,7 @@ WASM_EXEC_TEST(Call_Int32Add) {
WASM_EXEC_TEST(Call_Float32Sub) { WASM_EXEC_TEST(Call_Float32Sub) {
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t(sigs.f_ff(), &module); WasmFunctionCompiler t(sigs.f_ff(), &module);
// Build the target function. // Build the target function.
...@@ -2073,7 +2107,7 @@ WASM_EXEC_TEST(Call_Float32Sub) { ...@@ -2073,7 +2107,7 @@ WASM_EXEC_TEST(Call_Float32Sub) {
} }
WASM_EXEC_TEST(Call_Float64Sub) { WASM_EXEC_TEST(Call_Float64Sub) {
TestingModule module; TestingModule module(execution_mode);
double* memory = module.AddMemoryElems<double>(16); double* memory = module.AddMemoryElems<double>(16);
WasmRunner<int32_t> r(&module); WasmRunner<int32_t> r(&module);
...@@ -2106,7 +2140,7 @@ WASM_EXEC_TEST(Call_Float64Sub) { ...@@ -2106,7 +2140,7 @@ WASM_EXEC_TEST(Call_Float64Sub) {
for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \ for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \
} while (false) } while (false)
static void Run_WasmMixedCall_N(int start) { static void Run_WasmMixedCall_N(WasmExecutionMode execution_mode, int start) {
const int kExpected = 6333; const int kExpected = 6333;
const int kElemSize = 8; const int kElemSize = 8;
TestSignatures sigs; TestSignatures sigs;
...@@ -2130,7 +2164,7 @@ static void Run_WasmMixedCall_N(int start) { ...@@ -2130,7 +2164,7 @@ static void Run_WasmMixedCall_N(int start) {
for (int which = 0; which < num_params; which++) { for (int which = 0; which < num_params; which++) {
v8::base::AccountingAllocator allocator; v8::base::AccountingAllocator allocator;
Zone zone(&allocator); Zone zone(&allocator);
TestingModule module; TestingModule module(execution_mode);
module.AddMemory(1024); module.AddMemory(1024);
MachineType* memtypes = &mixed[start]; MachineType* memtypes = &mixed[start];
MachineType result = memtypes[which]; MachineType result = memtypes[which];
...@@ -2193,14 +2227,14 @@ static void Run_WasmMixedCall_N(int start) { ...@@ -2193,14 +2227,14 @@ static void Run_WasmMixedCall_N(int start) {
} }
} }
WASM_EXEC_TEST(MixedCall_0) { Run_WasmMixedCall_N(0); } WASM_EXEC_TEST(MixedCall_0) { Run_WasmMixedCall_N(execution_mode, 0); }
WASM_EXEC_TEST(MixedCall_1) { Run_WasmMixedCall_N(1); } WASM_EXEC_TEST(MixedCall_1) { Run_WasmMixedCall_N(execution_mode, 1); }
WASM_EXEC_TEST(MixedCall_2) { Run_WasmMixedCall_N(2); } WASM_EXEC_TEST(MixedCall_2) { Run_WasmMixedCall_N(execution_mode, 2); }
WASM_EXEC_TEST(MixedCall_3) { Run_WasmMixedCall_N(3); } WASM_EXEC_TEST(MixedCall_3) { Run_WasmMixedCall_N(execution_mode, 3); }
WASM_EXEC_TEST(AddCall) { WASM_EXEC_TEST(AddCall) {
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t1(sigs.i_ii(), &module); WasmFunctionCompiler t1(sigs.i_ii(), &module);
BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
t1.CompileAndAdd(); t1.CompileAndAdd();
...@@ -2209,9 +2243,9 @@ WASM_EXEC_TEST(AddCall) { ...@@ -2209,9 +2243,9 @@ WASM_EXEC_TEST(AddCall) {
byte local = r.AllocateLocal(kAstI32); byte local = r.AllocateLocal(kAstI32);
BUILD(r, B2(WASM_SET_LOCAL(local, WASM_I8(99)), BUILD(r, B2(WASM_SET_LOCAL(local, WASM_I8(99)),
WASM_I32_ADD( WASM_I32_ADD(
WASM_CALL_FUNCTION2(t1.function_index_, WASM_GET_LOCAL(0), WASM_CALL_FUNCTION2(t1.function_index(), WASM_GET_LOCAL(0),
WASM_GET_LOCAL(0)), WASM_GET_LOCAL(0)),
WASM_CALL_FUNCTION2(t1.function_index_, WASM_GET_LOCAL(1), WASM_CALL_FUNCTION2(t1.function_index(), WASM_GET_LOCAL(1),
WASM_GET_LOCAL(local))))); WASM_GET_LOCAL(local)))));
CHECK_EQ(198, r.Call(0)); CHECK_EQ(198, r.Call(0));
...@@ -2220,7 +2254,7 @@ WASM_EXEC_TEST(AddCall) { ...@@ -2220,7 +2254,7 @@ WASM_EXEC_TEST(AddCall) {
} }
WASM_EXEC_TEST(CountDown_expr) { WASM_EXEC_TEST(CountDown_expr) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, WASM_LOOP( BUILD(r, WASM_LOOP(
3, WASM_IF(WASM_NOT(WASM_GET_LOCAL(0)), 3, WASM_IF(WASM_NOT(WASM_GET_LOCAL(0)),
WASM_BREAKV(1, WASM_GET_LOCAL(0))), WASM_BREAKV(1, WASM_GET_LOCAL(0))),
...@@ -2232,35 +2266,35 @@ WASM_EXEC_TEST(CountDown_expr) { ...@@ -2232,35 +2266,35 @@ WASM_EXEC_TEST(CountDown_expr) {
} }
WASM_EXEC_TEST(ExprBlock2a) { WASM_EXEC_TEST(ExprBlock2a) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_IF(WASM_GET_LOCAL(0), WASM_BRV(1, WASM_I8(1))), WASM_I8(1))); BUILD(r, B2(WASM_IF(WASM_GET_LOCAL(0), WASM_BRV(1, WASM_I8(1))), WASM_I8(1)));
CHECK_EQ(1, r.Call(0)); CHECK_EQ(1, r.Call(0));
CHECK_EQ(1, r.Call(1)); CHECK_EQ(1, r.Call(1));
} }
WASM_EXEC_TEST(ExprBlock2b) { WASM_EXEC_TEST(ExprBlock2b) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_IF(WASM_GET_LOCAL(0), WASM_BRV(1, WASM_I8(1))), WASM_I8(2))); BUILD(r, B2(WASM_IF(WASM_GET_LOCAL(0), WASM_BRV(1, WASM_I8(1))), WASM_I8(2)));
CHECK_EQ(2, r.Call(0)); CHECK_EQ(2, r.Call(0));
CHECK_EQ(1, r.Call(1)); CHECK_EQ(1, r.Call(1));
} }
WASM_EXEC_TEST(ExprBlock2c) { WASM_EXEC_TEST(ExprBlock2c) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_BRV_IF(0, WASM_I8(1), WASM_GET_LOCAL(0)), WASM_I8(1))); BUILD(r, B2(WASM_BRV_IF(0, WASM_I8(1), WASM_GET_LOCAL(0)), WASM_I8(1)));
CHECK_EQ(1, r.Call(0)); CHECK_EQ(1, r.Call(0));
CHECK_EQ(1, r.Call(1)); CHECK_EQ(1, r.Call(1));
} }
WASM_EXEC_TEST(ExprBlock2d) { WASM_EXEC_TEST(ExprBlock2d) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B2(WASM_BRV_IF(0, WASM_I8(1), WASM_GET_LOCAL(0)), WASM_I8(2))); BUILD(r, B2(WASM_BRV_IF(0, WASM_I8(1), WASM_GET_LOCAL(0)), WASM_I8(2)));
CHECK_EQ(2, r.Call(0)); CHECK_EQ(2, r.Call(0));
CHECK_EQ(1, r.Call(1)); CHECK_EQ(1, r.Call(1));
} }
WASM_EXEC_TEST(ExprBlock_ManualSwitch) { WASM_EXEC_TEST(ExprBlock_ManualSwitch) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, WASM_BLOCK(6, WASM_IF(WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(1)), BUILD(r, WASM_BLOCK(6, WASM_IF(WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(1)),
WASM_BRV(1, WASM_I8(11))), WASM_BRV(1, WASM_I8(11))),
WASM_IF(WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(2)), WASM_IF(WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(2)),
...@@ -2282,7 +2316,7 @@ WASM_EXEC_TEST(ExprBlock_ManualSwitch) { ...@@ -2282,7 +2316,7 @@ WASM_EXEC_TEST(ExprBlock_ManualSwitch) {
} }
WASM_EXEC_TEST(ExprBlock_ManualSwitch_brif) { WASM_EXEC_TEST(ExprBlock_ManualSwitch_brif) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, BUILD(r,
WASM_BLOCK(6, WASM_BRV_IF(0, WASM_I8(11), WASM_BLOCK(6, WASM_BRV_IF(0, WASM_I8(11),
WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(1))), WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(1))),
...@@ -2305,7 +2339,8 @@ WASM_EXEC_TEST(ExprBlock_ManualSwitch_brif) { ...@@ -2305,7 +2339,8 @@ WASM_EXEC_TEST(ExprBlock_ManualSwitch_brif) {
} }
WASM_EXEC_TEST(nested_ifs) { WASM_EXEC_TEST(nested_ifs) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_IF_ELSE( BUILD(r, WASM_IF_ELSE(
WASM_GET_LOCAL(0), WASM_GET_LOCAL(0),
...@@ -2319,7 +2354,7 @@ WASM_EXEC_TEST(nested_ifs) { ...@@ -2319,7 +2354,7 @@ WASM_EXEC_TEST(nested_ifs) {
} }
WASM_EXEC_TEST(ExprBlock_if) { WASM_EXEC_TEST(ExprBlock_if) {
WasmRunner<int32_t> r(MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, B1(WASM_IF_ELSE(WASM_GET_LOCAL(0), WASM_BRV(0, WASM_I8(11)), BUILD(r, B1(WASM_IF_ELSE(WASM_GET_LOCAL(0), WASM_BRV(0, WASM_I8(11)),
WASM_BRV(1, WASM_I8(14))))); WASM_BRV(1, WASM_I8(14)))));
...@@ -2329,7 +2364,8 @@ WASM_EXEC_TEST(ExprBlock_if) { ...@@ -2329,7 +2364,8 @@ WASM_EXEC_TEST(ExprBlock_if) {
} }
WASM_EXEC_TEST(ExprBlock_nested_ifs) { WASM_EXEC_TEST(ExprBlock_nested_ifs) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_BLOCK( BUILD(r, WASM_BLOCK(
1, WASM_IF_ELSE( 1, WASM_IF_ELSE(
...@@ -2346,7 +2382,8 @@ WASM_EXEC_TEST(ExprBlock_nested_ifs) { ...@@ -2346,7 +2382,8 @@ WASM_EXEC_TEST(ExprBlock_nested_ifs) {
} }
WASM_EXEC_TEST(ExprLoop_nested_ifs) { WASM_EXEC_TEST(ExprLoop_nested_ifs) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_LOOP( BUILD(r, WASM_LOOP(
1, WASM_IF_ELSE( 1, WASM_IF_ELSE(
...@@ -2364,7 +2401,7 @@ WASM_EXEC_TEST(ExprLoop_nested_ifs) { ...@@ -2364,7 +2401,7 @@ WASM_EXEC_TEST(ExprLoop_nested_ifs) {
WASM_EXEC_TEST(SimpleCallIndirect) { WASM_EXEC_TEST(SimpleCallIndirect) {
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t1(sigs.i_ii(), &module); WasmFunctionCompiler t1(sigs.i_ii(), &module);
BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
...@@ -2395,7 +2432,7 @@ WASM_EXEC_TEST(SimpleCallIndirect) { ...@@ -2395,7 +2432,7 @@ WASM_EXEC_TEST(SimpleCallIndirect) {
WASM_EXEC_TEST(MultipleCallIndirect) { WASM_EXEC_TEST(MultipleCallIndirect) {
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
WasmFunctionCompiler t1(sigs.i_ii(), &module); WasmFunctionCompiler t1(sigs.i_ii(), &module);
BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
...@@ -2437,7 +2474,7 @@ WASM_EXEC_TEST(MultipleCallIndirect) { ...@@ -2437,7 +2474,7 @@ WASM_EXEC_TEST(MultipleCallIndirect) {
WASM_EXEC_TEST(CallIndirect_NoTable) { WASM_EXEC_TEST(CallIndirect_NoTable) {
TestSignatures sigs; TestSignatures sigs;
TestingModule module; TestingModule module(execution_mode);
// One function. // One function.
WasmFunctionCompiler t1(sigs.i_ii(), &module); WasmFunctionCompiler t1(sigs.i_ii(), &module);
...@@ -2458,63 +2495,64 @@ WASM_EXEC_TEST(CallIndirect_NoTable) { ...@@ -2458,63 +2495,64 @@ WASM_EXEC_TEST(CallIndirect_NoTable) {
} }
WASM_EXEC_TEST(F32Floor) { WASM_EXEC_TEST(F32Floor) {
WasmRunner<float> r(MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_F32_FLOOR(WASM_GET_LOCAL(0))); BUILD(r, WASM_F32_FLOOR(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(floorf(*i), r.Call(*i)); } FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(floorf(*i), r.Call(*i)); }
} }
WASM_EXEC_TEST(F32Ceil) { WASM_EXEC_TEST(F32Ceil) {
WasmRunner<float> r(MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_F32_CEIL(WASM_GET_LOCAL(0))); BUILD(r, WASM_F32_CEIL(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(ceilf(*i), r.Call(*i)); } FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(ceilf(*i), r.Call(*i)); }
} }
WASM_EXEC_TEST(F32Trunc) { WASM_EXEC_TEST(F32Trunc) {
WasmRunner<float> r(MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_F32_TRUNC(WASM_GET_LOCAL(0))); BUILD(r, WASM_F32_TRUNC(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(truncf(*i), r.Call(*i)); } FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(truncf(*i), r.Call(*i)); }
} }
WASM_EXEC_TEST(F32NearestInt) { WASM_EXEC_TEST(F32NearestInt) {
WasmRunner<float> r(MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_F32_NEARESTINT(WASM_GET_LOCAL(0))); BUILD(r, WASM_F32_NEARESTINT(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(nearbyintf(*i), r.Call(*i)); } FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(nearbyintf(*i), r.Call(*i)); }
} }
WASM_EXEC_TEST(F64Floor) { WASM_EXEC_TEST(F64Floor) {
WasmRunner<double> r(MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_F64_FLOOR(WASM_GET_LOCAL(0))); BUILD(r, WASM_F64_FLOOR(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(floor(*i), r.Call(*i)); } FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(floor(*i), r.Call(*i)); }
} }
WASM_EXEC_TEST(F64Ceil) { WASM_EXEC_TEST(F64Ceil) {
WasmRunner<double> r(MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_F64_CEIL(WASM_GET_LOCAL(0))); BUILD(r, WASM_F64_CEIL(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ceil(*i), r.Call(*i)); } FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ceil(*i), r.Call(*i)); }
} }
WASM_EXEC_TEST(F64Trunc) { WASM_EXEC_TEST(F64Trunc) {
WasmRunner<double> r(MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_F64_TRUNC(WASM_GET_LOCAL(0))); BUILD(r, WASM_F64_TRUNC(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(trunc(*i), r.Call(*i)); } FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(trunc(*i), r.Call(*i)); }
} }
WASM_EXEC_TEST(F64NearestInt) { WASM_EXEC_TEST(F64NearestInt) {
WasmRunner<double> r(MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_F64_NEARESTINT(WASM_GET_LOCAL(0))); BUILD(r, WASM_F64_NEARESTINT(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(nearbyint(*i), r.Call(*i)); } FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(nearbyint(*i), r.Call(*i)); }
} }
WASM_EXEC_TEST(F32Min) { WASM_EXEC_TEST(F32Min) {
WasmRunner<float> r(MachineType::Float32(), MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32(),
MachineType::Float32());
BUILD(r, WASM_F32_MIN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_F32_MIN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -2537,7 +2575,8 @@ WASM_EXEC_TEST(F32Min) { ...@@ -2537,7 +2575,8 @@ WASM_EXEC_TEST(F32Min) {
} }
WASM_EXEC_TEST(F64Min) { WASM_EXEC_TEST(F64Min) {
WasmRunner<double> r(MachineType::Float64(), MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64(),
MachineType::Float64());
BUILD(r, WASM_F64_MIN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_F64_MIN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -2560,7 +2599,8 @@ WASM_EXEC_TEST(F64Min) { ...@@ -2560,7 +2599,8 @@ WASM_EXEC_TEST(F64Min) {
} }
WASM_EXEC_TEST(F32Max) { WASM_EXEC_TEST(F32Max) {
WasmRunner<float> r(MachineType::Float32(), MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32(),
MachineType::Float32());
BUILD(r, WASM_F32_MAX(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_F32_MAX(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -2583,7 +2623,8 @@ WASM_EXEC_TEST(F32Max) { ...@@ -2583,7 +2623,8 @@ WASM_EXEC_TEST(F32Max) {
} }
WASM_EXEC_TEST(F64Max) { WASM_EXEC_TEST(F64Max) {
WasmRunner<double> r(MachineType::Float64(), MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64(),
MachineType::Float64());
BUILD(r, WASM_F64_MAX(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_F64_MAX(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -2611,13 +2652,13 @@ WASM_EXEC_TEST(F64Max) { ...@@ -2611,13 +2652,13 @@ WASM_EXEC_TEST(F64Max) {
WASM_EXEC_TEST(F32Min_Snan) { WASM_EXEC_TEST(F32Min_Snan) {
// Test that the instruction does not return a signalling NaN. // Test that the instruction does not return a signalling NaN.
{ {
WasmRunner<float> r; WasmRunner<float> r(execution_mode);
BUILD(r, BUILD(r,
WASM_F32_MIN(WASM_F32(bit_cast<float>(0xff80f1e2)), WASM_F32(57.67))); WASM_F32_MIN(WASM_F32(bit_cast<float>(0xff80f1e2)), WASM_F32(57.67)));
CHECK_EQ(0xffc0f1e2, bit_cast<uint32_t>(r.Call())); CHECK_EQ(0xffc0f1e2, bit_cast<uint32_t>(r.Call()));
} }
{ {
WasmRunner<float> r; WasmRunner<float> r(execution_mode);
BUILD(r, BUILD(r,
WASM_F32_MIN(WASM_F32(45.73), WASM_F32(bit_cast<float>(0x7f80f1e2)))); WASM_F32_MIN(WASM_F32(45.73), WASM_F32(bit_cast<float>(0x7f80f1e2))));
CHECK_EQ(0x7fc0f1e2, bit_cast<uint32_t>(r.Call())); CHECK_EQ(0x7fc0f1e2, bit_cast<uint32_t>(r.Call()));
...@@ -2627,13 +2668,13 @@ WASM_EXEC_TEST(F32Min_Snan) { ...@@ -2627,13 +2668,13 @@ WASM_EXEC_TEST(F32Min_Snan) {
WASM_EXEC_TEST(F32Max_Snan) { WASM_EXEC_TEST(F32Max_Snan) {
// Test that the instruction does not return a signalling NaN. // Test that the instruction does not return a signalling NaN.
{ {
WasmRunner<float> r; WasmRunner<float> r(execution_mode);
BUILD(r, BUILD(r,
WASM_F32_MAX(WASM_F32(bit_cast<float>(0xff80f1e2)), WASM_F32(57.67))); WASM_F32_MAX(WASM_F32(bit_cast<float>(0xff80f1e2)), WASM_F32(57.67)));
CHECK_EQ(0xffc0f1e2, bit_cast<uint32_t>(r.Call())); CHECK_EQ(0xffc0f1e2, bit_cast<uint32_t>(r.Call()));
} }
{ {
WasmRunner<float> r; WasmRunner<float> r(execution_mode);
BUILD(r, BUILD(r,
WASM_F32_MAX(WASM_F32(45.73), WASM_F32(bit_cast<float>(0x7f80f1e2)))); WASM_F32_MAX(WASM_F32(45.73), WASM_F32(bit_cast<float>(0x7f80f1e2))));
CHECK_EQ(0x7fc0f1e2, bit_cast<uint32_t>(r.Call())); CHECK_EQ(0x7fc0f1e2, bit_cast<uint32_t>(r.Call()));
...@@ -2643,13 +2684,13 @@ WASM_EXEC_TEST(F32Max_Snan) { ...@@ -2643,13 +2684,13 @@ WASM_EXEC_TEST(F32Max_Snan) {
WASM_EXEC_TEST(F64Min_Snan) { WASM_EXEC_TEST(F64Min_Snan) {
// Test that the instruction does not return a signalling NaN. // Test that the instruction does not return a signalling NaN.
{ {
WasmRunner<double> r; WasmRunner<double> r(execution_mode);
BUILD(r, WASM_F64_MIN(WASM_F64(bit_cast<double>(0xfff000000000f1e2)), BUILD(r, WASM_F64_MIN(WASM_F64(bit_cast<double>(0xfff000000000f1e2)),
WASM_F64(57.67))); WASM_F64(57.67)));
CHECK_EQ(0xfff800000000f1e2, bit_cast<uint64_t>(r.Call())); CHECK_EQ(0xfff800000000f1e2, bit_cast<uint64_t>(r.Call()));
} }
{ {
WasmRunner<double> r; WasmRunner<double> r(execution_mode);
BUILD(r, WASM_F64_MIN(WASM_F64(45.73), BUILD(r, WASM_F64_MIN(WASM_F64(45.73),
WASM_F64(bit_cast<double>(0x7ff000000000f1e2)))); WASM_F64(bit_cast<double>(0x7ff000000000f1e2))));
CHECK_EQ(0x7ff800000000f1e2, bit_cast<uint64_t>(r.Call())); CHECK_EQ(0x7ff800000000f1e2, bit_cast<uint64_t>(r.Call()));
...@@ -2659,13 +2700,13 @@ WASM_EXEC_TEST(F64Min_Snan) { ...@@ -2659,13 +2700,13 @@ WASM_EXEC_TEST(F64Min_Snan) {
WASM_EXEC_TEST(F64Max_Snan) { WASM_EXEC_TEST(F64Max_Snan) {
// Test that the instruction does not return a signalling NaN. // Test that the instruction does not return a signalling NaN.
{ {
WasmRunner<double> r; WasmRunner<double> r(execution_mode);
BUILD(r, WASM_F64_MAX(WASM_F64(bit_cast<double>(0xfff000000000f1e2)), BUILD(r, WASM_F64_MAX(WASM_F64(bit_cast<double>(0xfff000000000f1e2)),
WASM_F64(57.67))); WASM_F64(57.67)));
CHECK_EQ(0xfff800000000f1e2, bit_cast<uint64_t>(r.Call())); CHECK_EQ(0xfff800000000f1e2, bit_cast<uint64_t>(r.Call()));
} }
{ {
WasmRunner<double> r; WasmRunner<double> r(execution_mode);
BUILD(r, WASM_F64_MAX(WASM_F64(45.73), BUILD(r, WASM_F64_MAX(WASM_F64(45.73),
WASM_F64(bit_cast<double>(0x7ff000000000f1e2)))); WASM_F64(bit_cast<double>(0x7ff000000000f1e2))));
CHECK_EQ(0x7ff800000000f1e2, bit_cast<uint64_t>(r.Call())); CHECK_EQ(0x7ff800000000f1e2, bit_cast<uint64_t>(r.Call()));
...@@ -2675,7 +2716,7 @@ WASM_EXEC_TEST(F64Max_Snan) { ...@@ -2675,7 +2716,7 @@ WASM_EXEC_TEST(F64Max_Snan) {
#endif #endif
WASM_EXEC_TEST(I32SConvertF32) { WASM_EXEC_TEST(I32SConvertF32) {
WasmRunner<int32_t> r(MachineType::Float32()); WasmRunner<int32_t> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_I32_SCONVERT_F32(WASM_GET_LOCAL(0))); BUILD(r, WASM_I32_SCONVERT_F32(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -2689,7 +2730,7 @@ WASM_EXEC_TEST(I32SConvertF32) { ...@@ -2689,7 +2730,7 @@ WASM_EXEC_TEST(I32SConvertF32) {
} }
WASM_EXEC_TEST(I32SConvertF64) { WASM_EXEC_TEST(I32SConvertF64) {
WasmRunner<int32_t> r(MachineType::Float64()); WasmRunner<int32_t> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_I32_SCONVERT_F64(WASM_GET_LOCAL(0))); BUILD(r, WASM_I32_SCONVERT_F64(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -2703,7 +2744,7 @@ WASM_EXEC_TEST(I32SConvertF64) { ...@@ -2703,7 +2744,7 @@ WASM_EXEC_TEST(I32SConvertF64) {
} }
WASM_EXEC_TEST(I32UConvertF32) { WASM_EXEC_TEST(I32UConvertF32) {
WasmRunner<uint32_t> r(MachineType::Float32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Float32());
BUILD(r, WASM_I32_UCONVERT_F32(WASM_GET_LOCAL(0))); BUILD(r, WASM_I32_UCONVERT_F32(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -2716,7 +2757,7 @@ WASM_EXEC_TEST(I32UConvertF32) { ...@@ -2716,7 +2757,7 @@ WASM_EXEC_TEST(I32UConvertF32) {
} }
WASM_EXEC_TEST(I32UConvertF64) { WASM_EXEC_TEST(I32UConvertF64) {
WasmRunner<uint32_t> r(MachineType::Float64()); WasmRunner<uint32_t> r(execution_mode, MachineType::Float64());
BUILD(r, WASM_I32_UCONVERT_F64(WASM_GET_LOCAL(0))); BUILD(r, WASM_I32_UCONVERT_F64(WASM_GET_LOCAL(0)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -2729,7 +2770,8 @@ WASM_EXEC_TEST(I32UConvertF64) { ...@@ -2729,7 +2770,8 @@ WASM_EXEC_TEST(I32UConvertF64) {
} }
WASM_EXEC_TEST(F64CopySign) { WASM_EXEC_TEST(F64CopySign) {
WasmRunner<double> r(MachineType::Float64(), MachineType::Float64()); WasmRunner<double> r(execution_mode, MachineType::Float64(),
MachineType::Float64());
BUILD(r, WASM_F64_COPYSIGN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_F64_COPYSIGN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
...@@ -2738,7 +2780,8 @@ WASM_EXEC_TEST(F64CopySign) { ...@@ -2738,7 +2780,8 @@ WASM_EXEC_TEST(F64CopySign) {
} }
WASM_EXEC_TEST(F32CopySign) { WASM_EXEC_TEST(F32CopySign) {
WasmRunner<float> r(MachineType::Float32(), MachineType::Float32()); WasmRunner<float> r(execution_mode, MachineType::Float32(),
MachineType::Float32());
BUILD(r, WASM_F32_COPYSIGN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); BUILD(r, WASM_F32_COPYSIGN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_FLOAT32_INPUTS(i) { FOR_FLOAT32_INPUTS(i) {
...@@ -2754,7 +2797,7 @@ void CompileCallIndirectMany(LocalType param) { ...@@ -2754,7 +2797,7 @@ void CompileCallIndirectMany(LocalType param) {
v8::base::AccountingAllocator allocator; v8::base::AccountingAllocator allocator;
Zone zone(&allocator); Zone zone(&allocator);
HandleScope scope(CcTest::InitIsolateOnce()); HandleScope scope(CcTest::InitIsolateOnce());
TestingModule module; TestingModule module(kExecuteCompiled);
FunctionSig* sig = sigs.many(&zone, kAstStmt, param, num_params); FunctionSig* sig = sigs.many(&zone, kAstStmt, param, num_params);
module.AddSignature(sig); module.AddSignature(sig);
...@@ -2786,7 +2829,8 @@ TEST(Compile_Wasm_CallIndirect_Many_f32) { CompileCallIndirectMany(kAstF32); } ...@@ -2786,7 +2829,8 @@ TEST(Compile_Wasm_CallIndirect_Many_f32) { CompileCallIndirectMany(kAstF32); }
TEST(Compile_Wasm_CallIndirect_Many_f64) { CompileCallIndirectMany(kAstF64); } TEST(Compile_Wasm_CallIndirect_Many_f64) { CompileCallIndirectMany(kAstF64); }
WASM_EXEC_TEST(Int32RemS_dead) { WASM_EXEC_TEST(Int32RemS_dead) {
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); WasmRunner<int32_t> r(execution_mode, MachineType::Int32(),
MachineType::Int32());
BUILD(r, WASM_I32_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)), WASM_ZERO); BUILD(r, WASM_I32_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)), WASM_ZERO);
const int32_t kMin = std::numeric_limits<int32_t>::min(); const int32_t kMin = std::numeric_limits<int32_t>::min();
CHECK_EQ(0, r.Call(133, 100)); CHECK_EQ(0, r.Call(133, 100));
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "src/base/accounting-allocator.h"
#include "src/base/utils/random-number-generator.h" #include "src/base/utils/random-number-generator.h"
#include "src/compiler/graph-visualizer.h" #include "src/compiler/graph-visualizer.h"
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
#include "src/compiler/zone-pool.h" #include "src/compiler/zone-pool.h"
#include "src/wasm/ast-decoder.h" #include "src/wasm/ast-decoder.h"
#include "src/wasm/wasm-interpreter.h"
#include "src/wasm/wasm-js.h" #include "src/wasm/wasm-js.h"
#include "src/wasm/wasm-macro-gen.h" #include "src/wasm/wasm-macro-gen.h"
#include "src/wasm/wasm-module.h" #include "src/wasm/wasm-module.h"
...@@ -40,6 +42,8 @@ ...@@ -40,6 +42,8 @@
static const uint32_t kMaxFunctions = 10; static const uint32_t kMaxFunctions = 10;
enum WasmExecutionMode { kExecuteInterpreted, kExecuteCompiled };
// TODO(titzer): check traps more robustly in tests. // TODO(titzer): check traps more robustly in tests.
// Currently, in tests, we just return 0xdeadbeef from the function in which // Currently, in tests, we just return 0xdeadbeef from the function in which
// the trap occurs if the runtime context is not available to throw a JavaScript // the trap occurs if the runtime context is not available to throw a JavaScript
...@@ -72,10 +76,14 @@ const uint32_t kMaxGlobalsSize = 128; ...@@ -72,10 +76,14 @@ const uint32_t kMaxGlobalsSize = 128;
// {WasmModuleInstance}. // {WasmModuleInstance}.
class TestingModule : public ModuleEnv { class TestingModule : public ModuleEnv {
public: public:
TestingModule() explicit TestingModule(WasmExecutionMode mode = kExecuteCompiled)
: instance_(&module_), : execution_mode_(mode),
instance_(&module_),
isolate_(CcTest::InitIsolateOnce()), isolate_(CcTest::InitIsolateOnce()),
global_offset(0) { global_offset(0),
interpreter_(mode == kExecuteInterpreted
? new WasmInterpreter(&instance_, &allocator_)
: nullptr) {
module = &module_; module = &module_;
instance = &instance_; instance = &instance_;
instance->module = &module_; instance->module = &module_;
...@@ -92,6 +100,7 @@ class TestingModule : public ModuleEnv { ...@@ -92,6 +100,7 @@ class TestingModule : public ModuleEnv {
if (instance->mem_start) { if (instance->mem_start) {
free(instance->mem_start); free(instance->mem_start);
} }
if (interpreter_) delete interpreter_;
} }
byte* AddMemory(size_t size) { byte* AddMemory(size_t size) {
...@@ -172,6 +181,11 @@ class TestingModule : public ModuleEnv { ...@@ -172,6 +181,11 @@ class TestingModule : public ModuleEnv {
uint32_t index = static_cast<uint32_t>(module->functions.size()); uint32_t index = static_cast<uint32_t>(module->functions.size());
module_.functions.push_back({sig, index, 0, 0, 0, 0, 0, false}); module_.functions.push_back({sig, index, 0, 0, 0, 0, 0, false});
instance->function_code.push_back(code); instance->function_code.push_back(code);
if (interpreter_) {
const WasmFunction* function = &module->functions.back();
int interpreter_index = interpreter_->AddFunctionForTesting(function);
CHECK_EQ(index, static_cast<uint32_t>(interpreter_index));
}
DCHECK_LT(index, kMaxFunctions); // limited for testing. DCHECK_LT(index, kMaxFunctions); // limited for testing.
return index; return index;
} }
...@@ -225,12 +239,18 @@ class TestingModule : public ModuleEnv { ...@@ -225,12 +239,18 @@ class TestingModule : public ModuleEnv {
} }
WasmFunction* GetFunctionAt(int index) { return &module_.functions[index]; } WasmFunction* GetFunctionAt(int index) { return &module_.functions[index]; }
WasmInterpreter* interpreter() { return interpreter_; }
WasmExecutionMode execution_mode() { return execution_mode_; }
private: private:
WasmExecutionMode execution_mode_;
WasmModule module_; WasmModule module_;
WasmModuleInstance instance_; WasmModuleInstance instance_;
Isolate* isolate_; Isolate* isolate_;
v8::base::AccountingAllocator allocator_;
uint32_t global_offset; uint32_t global_offset;
V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data.
WasmInterpreter* interpreter_;
const WasmGlobal* AddGlobal(MachineType mem_type) { const WasmGlobal* AddGlobal(MachineType mem_type) {
byte size = WasmOpcodes::MemSize(mem_type); byte size = WasmOpcodes::MemSize(mem_type);
...@@ -409,14 +429,41 @@ class WasmFunctionWrapper : public HandleAndZoneScope, ...@@ -409,14 +429,41 @@ class WasmFunctionWrapper : public HandleAndZoneScope,
// A helper for compiling WASM functions for testing. This class can create a // A helper for compiling WASM functions for testing. This class can create a
// standalone function if {module} is NULL or a function within a // standalone function if {module} is NULL or a function within a
// {TestingModule}. It contains the internal state for compilation (i.e. // {TestingModule}. It contains the internal state for compilation (i.e.
// TurboFan graph) and, later, interpretation. // TurboFan graph) and interpretation (by adding to the interpreter manually).
class WasmFunctionCompiler : public HandleAndZoneScope, class WasmFunctionCompiler : public HandleAndZoneScope,
private GraphAndBuilders { private GraphAndBuilders {
public: public:
explicit WasmFunctionCompiler(
FunctionSig* sig, WasmExecutionMode mode,
Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>"))
: GraphAndBuilders(main_zone()),
execution_mode_(mode),
jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
nullptr, this->machine()),
sig(sig),
descriptor_(nullptr),
testing_module_(nullptr),
debug_name_(debug_name),
local_decls(main_zone(), sig),
source_position_table_(this->graph()),
interpreter_(nullptr) {
// Create our own function.
function_ = new WasmFunction();
function_->sig = sig;
function_->func_index = 0;
function_->sig_index = 0;
if (mode == kExecuteInterpreted) {
interpreter_ = new WasmInterpreter(nullptr, zone()->allocator());
int index = interpreter_->AddFunctionForTesting(function_);
CHECK_EQ(0, index);
}
}
explicit WasmFunctionCompiler( explicit WasmFunctionCompiler(
FunctionSig* sig, TestingModule* module, FunctionSig* sig, TestingModule* module,
Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>")) Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>"))
: GraphAndBuilders(main_zone()), : GraphAndBuilders(main_zone()),
execution_mode_(module->execution_mode()),
jsgraph(this->isolate(), this->graph(), this->common(), nullptr, jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
nullptr, this->machine()), nullptr, this->machine()),
sig(sig), sig(sig),
...@@ -424,23 +471,20 @@ class WasmFunctionCompiler : public HandleAndZoneScope, ...@@ -424,23 +471,20 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
testing_module_(module), testing_module_(module),
debug_name_(debug_name), debug_name_(debug_name),
local_decls(main_zone(), sig), local_decls(main_zone(), sig),
source_position_table_(this->graph()) { source_position_table_(this->graph()),
if (module) { interpreter_(module->interpreter()) {
// Get a new function from the testing module. // Get a new function from the testing module.
function_ = nullptr; int index = module->AddFunction(sig, Handle<Code>::null());
function_index_ = module->AddFunction(sig, Handle<Code>::null()); function_ = testing_module_->GetFunctionAt(index);
} else {
// Create our own function.
function_ = new WasmFunction();
function_->sig = sig;
function_index_ = 0;
}
} }
~WasmFunctionCompiler() { ~WasmFunctionCompiler() {
if (function_) delete function_; if (testing_module_) return; // testing module owns the below things.
delete function_;
if (interpreter_) delete interpreter_;
} }
WasmExecutionMode execution_mode_;
JSGraph jsgraph; JSGraph jsgraph;
FunctionSig* sig; FunctionSig* sig;
// The call descriptor is initialized when the function is compiled. // The call descriptor is initialized when the function is compiled.
...@@ -448,9 +492,9 @@ class WasmFunctionCompiler : public HandleAndZoneScope, ...@@ -448,9 +492,9 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
TestingModule* testing_module_; TestingModule* testing_module_;
Vector<const char> debug_name_; Vector<const char> debug_name_;
WasmFunction* function_; WasmFunction* function_;
int function_index_;
LocalDeclEncoder local_decls; LocalDeclEncoder local_decls;
SourcePositionTable source_position_table_; SourcePositionTable source_position_table_;
WasmInterpreter* interpreter_;
Isolate* isolate() { return main_isolate(); } Isolate* isolate() { return main_isolate(); }
Graph* graph() const { return main_graph_; } Graph* graph() const { return main_graph_; }
...@@ -463,13 +507,17 @@ class WasmFunctionCompiler : public HandleAndZoneScope, ...@@ -463,13 +507,17 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
} }
} }
CallDescriptor* descriptor() { return descriptor_; } CallDescriptor* descriptor() { return descriptor_; }
uint32_t function_index() { return function_->func_index; }
void Build(const byte* start, const byte* end) { void Build(const byte* start, const byte* end) {
// Build the TurboFan graph. // Build the TurboFan graph.
local_decls.Prepend(&start, &end); local_decls.Prepend(main_zone(), &start, &end);
TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig, TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig,
&source_position_table_, start, end); &source_position_table_, start, end);
delete[] start; if (interpreter_) {
// Add the code to the interpreter.
CHECK(interpreter_->SetFunctionCodeForTesting(function_, start, end));
}
} }
byte AllocateLocal(LocalType type) { byte AllocateLocal(LocalType type) {
...@@ -495,13 +543,13 @@ class WasmFunctionCompiler : public HandleAndZoneScope, ...@@ -495,13 +543,13 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
Handle<Code> code = info.code(); Handle<Code> code = info.code();
// Length is always 2, since usually <wasm_obj, func_index> is stored in the // Length is always 2, since usually <wasm_obj, func_index> is stored in
// deopt data. Here, we only store the function index. // the deopt data. Here, we only store the function index.
DCHECK(code->deoptimization_data() == nullptr || DCHECK(code->deoptimization_data() == nullptr ||
code->deoptimization_data()->length() == 0); code->deoptimization_data()->length() == 0);
Handle<FixedArray> deopt_data = Handle<FixedArray> deopt_data =
isolate()->factory()->NewFixedArray(2, TENURED); isolate()->factory()->NewFixedArray(2, TENURED);
deopt_data->set(1, Smi::FromInt(function_index_)); deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index())));
deopt_data->set_length(2); deopt_data->set_length(2);
code->set_deoptimization_data(*deopt_data); code->set_deoptimization_data(*deopt_data);
...@@ -517,15 +565,10 @@ class WasmFunctionCompiler : public HandleAndZoneScope, ...@@ -517,15 +565,10 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
uint32_t CompileAndAdd(uint16_t sig_index = 0) { uint32_t CompileAndAdd(uint16_t sig_index = 0) {
CHECK(testing_module_); CHECK(testing_module_);
function()->sig_index = sig_index; function_->sig_index = sig_index;
Handle<Code> code = Compile(); Handle<Code> code = Compile();
testing_module_->SetFunctionCode(function_index_, code); testing_module_->SetFunctionCode(function_index(), code);
return static_cast<uint32_t>(function_index_); return function_index();
}
WasmFunction* function() {
if (function_) return function_;
return testing_module_->GetFunctionAt(function_index_);
} }
// Set the context, such that e.g. runtime functions can be called. // Set the context, such that e.g. runtime functions can be called.
...@@ -544,7 +587,8 @@ class WasmFunctionCompiler : public HandleAndZoneScope, ...@@ -544,7 +587,8 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
template <typename ReturnType> template <typename ReturnType>
class WasmRunner { class WasmRunner {
public: public:
WasmRunner(MachineType p0 = MachineType::None(), WasmRunner(WasmExecutionMode execution_mode,
MachineType p0 = MachineType::None(),
MachineType p1 = MachineType::None(), MachineType p1 = MachineType::None(),
MachineType p2 = MachineType::None(), MachineType p2 = MachineType::None(),
MachineType p3 = MachineType::None()) MachineType p3 = MachineType::None())
...@@ -552,7 +596,7 @@ class WasmRunner { ...@@ -552,7 +596,7 @@ class WasmRunner {
compiled_(false), compiled_(false),
signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
GetParameterCount(p0, p1, p2, p3), storage_), GetParameterCount(p0, p1, p2, p3), storage_),
compiler_(&signature_, nullptr) { compiler_(&signature_, execution_mode) {
InitSigStorage(p0, p1, p2, p3); InitSigStorage(p0, p1, p2, p3);
} }
...@@ -595,51 +639,102 @@ class WasmRunner { ...@@ -595,51 +639,102 @@ class WasmRunner {
void Build(const byte* start, const byte* end) { void Build(const byte* start, const byte* end) {
CHECK(!compiled_); CHECK(!compiled_);
compiled_ = true; compiled_ = true;
// Build the TF graph within the compiler.
compiler_.Build(start, end); compiler_.Build(start, end);
// Generate code.
Handle<Code> code = compiler_.Compile();
if (compiler_.testing_module_) { if (!interpret()) {
// Update the table of function code in the module. // Compile machine code and install it into the module.
compiler_.testing_module_->SetFunctionCode(compiler_.function_index_, Handle<Code> code = compiler_.Compile();
code);
} if (compiler_.testing_module_) {
// Update the table of function code in the module.
compiler_.testing_module_->SetFunctionCode(
compiler_.function_->func_index, code);
}
wrapper_.SetInnerCode(code); wrapper_.SetInnerCode(code);
}
} }
ReturnType Call() { return Call(0, 0, 0, 0); } ReturnType Call() {
if (interpret()) {
return CallInterpreter(Vector<WasmVal>(nullptr, 0));
} else {
return Call(0, 0, 0, 0);
}
}
template <typename P0> template <typename P0>
ReturnType Call(P0 p0) { ReturnType Call(P0 p0) {
return Call(p0, 0, 0, 0); if (interpret()) {
WasmVal args[] = {WasmVal(p0)};
return CallInterpreter(ArrayVector(args));
} else {
return Call(p0, 0, 0, 0);
}
} }
template <typename P0, typename P1> template <typename P0, typename P1>
ReturnType Call(P0 p0, P1 p1) { ReturnType Call(P0 p0, P1 p1) {
return Call(p0, p1, 0, 0); if (interpret()) {
WasmVal args[] = {WasmVal(p0), WasmVal(p1)};
return CallInterpreter(ArrayVector(args));
} else {
return Call(p0, p1, 0, 0);
}
} }
template <typename P0, typename P1, typename P2> template <typename P0, typename P1, typename P2>
ReturnType Call(P0 p0, P1 p1, P2 p2) { ReturnType Call(P0 p0, P1 p1, P2 p2) {
return Call(p0, p1, p2, 0); if (interpret()) {
WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2)};
return CallInterpreter(ArrayVector(args));
} else {
return Call(p0, p1, p2, 0);
}
} }
template <typename P0, typename P1, typename P2, typename P3> template <typename P0, typename P1, typename P2, typename P3>
ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) {
CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), if (interpret()) {
wrapper_.GetWrapperCode(), wrapper_.signature()); WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2), WasmVal(p3)};
ReturnType return_value; return CallInterpreter(ArrayVector(args));
int32_t result = runner.Call<void*, void*, void*, void*, void*>( } else {
&p0, &p1, &p2, &p3, &return_value); CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result); wrapper_.GetWrapperCode(),
return return_value; wrapper_.signature());
ReturnType return_value;
int32_t result = runner.Call<void*, void*, void*, void*, void*>(
&p0, &p1, &p2, &p3, &return_value);
CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
return return_value;
}
}
ReturnType CallInterpreter(Vector<WasmVal> args) {
CHECK_EQ(args.length(),
static_cast<int>(compiler_.function_->sig->parameter_count()));
WasmInterpreter::Thread& thread = interpreter()->GetThread(0);
thread.Reset();
thread.PushFrame(compiler_.function_, args.start());
if (thread.Run() == WasmInterpreter::FINISHED) {
WasmVal val = thread.GetReturnValue();
return val.to<ReturnType>();
} else if (thread.state() == WasmInterpreter::TRAPPED) {
// TODO(titzer): return the correct trap code
int64_t result = 0xdeadbeefdeadbeef;
return static_cast<ReturnType>(result);
} else {
// TODO(titzer): falling off end
ReturnType val = 0;
return val;
}
} }
byte AllocateLocal(LocalType type) { return compiler_.AllocateLocal(type); } byte AllocateLocal(LocalType type) { return compiler_.AllocateLocal(type); }
WasmFunction* function() { return compiler_.function_; }
WasmInterpreter* interpreter() { return compiler_.interpreter_; }
protected: protected:
v8::base::AccountingAllocator allocator_; v8::base::AccountingAllocator allocator_;
Zone zone; Zone zone;
...@@ -649,6 +744,8 @@ class WasmRunner { ...@@ -649,6 +744,8 @@ class WasmRunner {
WasmFunctionCompiler compiler_; WasmFunctionCompiler compiler_;
WasmFunctionWrapper<ReturnType> wrapper_; WasmFunctionWrapper<ReturnType> wrapper_;
bool interpret() { return compiler_.execution_mode_ == kExecuteInterpreted; }
static size_t GetParameterCount(MachineType p0, MachineType p1, static size_t GetParameterCount(MachineType p0, MachineType p1,
MachineType p2, MachineType p3) { MachineType p2, MachineType p3) {
if (p0 == MachineType::None()) return 0; if (p0 == MachineType::None()) return 0;
...@@ -663,10 +760,11 @@ class WasmRunner { ...@@ -663,10 +760,11 @@ class WasmRunner {
// Currently only supports compiled tests, but a future // Currently only supports compiled tests, but a future
// RunWasmInterpreted_##name version will allow each test to also run in the // RunWasmInterpreted_##name version will allow each test to also run in the
// interpreter. // interpreter.
#define WASM_EXEC_TEST(name) \ #define WASM_EXEC_TEST(name) \
void RunWasm_##name(); \ void RunWasm_##name(WasmExecutionMode execution_mode); \
TEST(RunWasmCompiled_##name) { RunWasm_##name(); } \ TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \
void RunWasm_##name() TEST(RunWasmInterpreted_##name) { RunWasm_##name(kExecuteInterpreted); } \
void RunWasm_##name(WasmExecutionMode execution_mode)
} // namespace } // namespace
......
...@@ -119,6 +119,7 @@ ...@@ -119,6 +119,7 @@
'test-utils.h', 'test-utils.h',
'test-utils.cc', 'test-utils.cc',
'wasm/ast-decoder-unittest.cc', 'wasm/ast-decoder-unittest.cc',
'wasm/control-transfer-unittest.cc',
'wasm/decoder-unittest.cc', 'wasm/decoder-unittest.cc',
'wasm/encoder-unittest.cc', 'wasm/encoder-unittest.cc',
'wasm/leb-helper-unittest.cc', 'wasm/leb-helper-unittest.cc',
......
...@@ -82,7 +82,7 @@ class AstDecoderTest : public TestWithZone { ...@@ -82,7 +82,7 @@ class AstDecoderTest : public TestWithZone {
// verification failures. // verification failures.
void Verify(ErrorCode expected, FunctionSig* sig, const byte* start, void Verify(ErrorCode expected, FunctionSig* sig, const byte* start,
const byte* end) { const byte* end) {
local_decls.Prepend(&start, &end); local_decls.Prepend(zone(), &start, &end);
// Verify the code. // Verify the code.
TreeResult result = TreeResult result =
VerifyWasmCode(zone()->allocator(), module, sig, start, end); VerifyWasmCode(zone()->allocator(), module, sig, start, end);
...@@ -105,8 +105,6 @@ class AstDecoderTest : public TestWithZone { ...@@ -105,8 +105,6 @@ class AstDecoderTest : public TestWithZone {
} }
FATAL(str.str().c_str()); FATAL(str.str().c_str());
} }
delete[] start; // local_decls.Prepend() allocated a new buffer.
} }
void TestBinop(WasmOpcode opcode, FunctionSig* success) { void TestBinop(WasmOpcode opcode, FunctionSig* success) {
...@@ -2427,7 +2425,7 @@ TEST_F(LocalDeclDecoderTest, UseEncoder) { ...@@ -2427,7 +2425,7 @@ TEST_F(LocalDeclDecoderTest, UseEncoder) {
local_decls.AddLocals(5, kAstF32); local_decls.AddLocals(5, kAstF32);
local_decls.AddLocals(1337, kAstI32); local_decls.AddLocals(1337, kAstI32);
local_decls.AddLocals(212, kAstI64); local_decls.AddLocals(212, kAstI64);
local_decls.Prepend(&data, &end); local_decls.Prepend(zone(), &data, &end);
AstLocalDecls decls(zone()); AstLocalDecls decls(zone());
bool result = DecodeLocalDecls(decls, data, end); bool result = DecodeLocalDecls(decls, data, end);
...@@ -2439,7 +2437,6 @@ TEST_F(LocalDeclDecoderTest, UseEncoder) { ...@@ -2439,7 +2437,6 @@ TEST_F(LocalDeclDecoderTest, UseEncoder) {
pos = ExpectRun(map, pos, kAstF32, 5); pos = ExpectRun(map, pos, kAstF32, 5);
pos = ExpectRun(map, pos, kAstI32, 1337); pos = ExpectRun(map, pos, kAstI32, 1337);
pos = ExpectRun(map, pos, kAstI64, 212); pos = ExpectRun(map, pos, kAstI64, 212);
delete[] data;
} }
} // namespace wasm } // namespace wasm
......
// Copyright 2016 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.
#include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "src/v8.h"
#include "src/wasm/wasm-interpreter.h"
#include "src/wasm/wasm-macro-gen.h"
using testing::MakeMatcher;
using testing::Matcher;
using testing::MatcherInterface;
using testing::MatchResultListener;
using testing::StringMatchResultListener;
namespace v8 {
namespace internal {
namespace wasm {
#define B1(a) kExprBlock, a, kExprEnd
#define B2(a, b) kExprBlock, a, b, kExprEnd
#define B3(a, b, c) kExprBlock, a, b, c, kExprEnd
struct ExpectedTarget {
pc_t pc;
ControlTransfer expected;
};
// For nicer error messages.
class ControlTransferMatcher : public MatcherInterface<const ControlTransfer&> {
public:
explicit ControlTransferMatcher(pc_t pc, const ControlTransfer& expected)
: pc_(pc), expected_(expected) {}
void DescribeTo(std::ostream* os) const override {
*os << "@" << pc_ << " {pcdiff = " << expected_.pcdiff
<< ", spdiff = " << expected_.spdiff
<< ", action = " << expected_.action << "}";
}
bool MatchAndExplain(const ControlTransfer& input,
MatchResultListener* listener) const override {
if (input.pcdiff != expected_.pcdiff || input.spdiff != expected_.spdiff ||
input.action != expected_.action) {
*listener << "@" << pc_ << " {pcdiff = " << input.pcdiff
<< ", spdiff = " << input.spdiff
<< ", action = " << input.action << "}";
return false;
}
return true;
}
private:
pc_t pc_;
const ControlTransfer& expected_;
};
class ControlTransferTest : public TestWithZone {
public:
void CheckControlTransfers(const byte* start, const byte* end,
ExpectedTarget* expected_targets,
size_t num_targets) {
ControlTransferMap map =
WasmInterpreter::ComputeControlTransfersForTesting(zone(), start, end);
// Check all control targets in the map.
for (size_t i = 0; i < num_targets; i++) {
pc_t pc = expected_targets[i].pc;
auto it = map.find(pc);
if (it == map.end()) {
printf("expected control target @ +%zu\n", pc);
EXPECT_TRUE(false);
} else {
ControlTransfer& expected = expected_targets[i].expected;
ControlTransfer& target = it->second;
EXPECT_THAT(target,
MakeMatcher(new ControlTransferMatcher(pc, expected)));
}
}
// Check there are no other control targets.
for (pc_t pc = 0; start + pc < end; pc++) {
bool found = false;
for (size_t i = 0; i < num_targets; i++) {
if (expected_targets[i].pc == pc) {
found = true;
break;
}
}
if (found) continue;
if (map.find(pc) != map.end()) {
printf("expected no control @ +%zu\n", pc);
EXPECT_TRUE(false);
}
}
}
};
// Macro for simplifying tests below.
#define EXPECT_TARGETS(...) \
do { \
ExpectedTarget pairs[] = {__VA_ARGS__}; \
CheckControlTransfers(code, code + sizeof(code), pairs, arraysize(pairs)); \
} while (false)
TEST_F(ControlTransferTest, SimpleIf) {
byte code[] = {
kExprI32Const, // @0
0, // +1
kExprIf, // @2
kExprEnd // @3
};
EXPECT_TARGETS({2, {2, 0, ControlTransfer::kPushVoid}}, // --
{3, {1, 0, ControlTransfer::kPushVoid}});
}
TEST_F(ControlTransferTest, SimpleIf1) {
byte code[] = {
kExprI32Const, // @0
0, // +1
kExprIf, // @2
kExprNop, // @3
kExprEnd // @4
};
EXPECT_TARGETS({2, {3, 0, ControlTransfer::kPushVoid}}, // --
{4, {1, 1, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, SimpleIf2) {
byte code[] = {
kExprI32Const, // @0
0, // +1
kExprIf, // @2
kExprNop, // @3
kExprNop, // @4
kExprEnd // @5
};
EXPECT_TARGETS({2, {4, 0, ControlTransfer::kPushVoid}}, // --
{5, {1, 2, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, SimpleIfElse) {
byte code[] = {
kExprI32Const, // @0
0, // +1
kExprIf, // @2
kExprElse, // @3
kExprEnd // @4
};
EXPECT_TARGETS({2, {2, 0, ControlTransfer::kNoAction}}, // --
{3, {2, 0, ControlTransfer::kPushVoid}}, // --
{4, {1, 0, ControlTransfer::kPushVoid}});
}
TEST_F(ControlTransferTest, SimpleIfElse1) {
byte code[] = {
kExprI32Const, // @0
0, // +1
kExprIf, // @2
kExprNop, // @3
kExprElse, // @4
kExprNop, // @5
kExprEnd // @6
};
EXPECT_TARGETS({2, {3, 0, ControlTransfer::kNoAction}}, // --
{4, {3, 1, ControlTransfer::kPopAndRepush}}, // --
{6, {1, 1, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, IfBr) {
byte code[] = {
kExprI32Const, // @0
0, // +1
kExprIf, // @2
kExprBr, // @3
ARITY_0, // +1
0, // +1
kExprEnd // @6
};
EXPECT_TARGETS({2, {5, 0, ControlTransfer::kPushVoid}}, // --
{3, {4, 0, ControlTransfer::kPushVoid}}, // --
{6, {1, 1, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, IfBrElse) {
byte code[] = {
kExprI32Const, // @0
0, // +1
kExprIf, // @2
kExprBr, // @3
ARITY_0, // +1
0, // +1
kExprElse, // @6
kExprEnd // @7
};
EXPECT_TARGETS({2, {5, 0, ControlTransfer::kNoAction}}, // --
{3, {5, 0, ControlTransfer::kPushVoid}}, // --
{6, {2, 1, ControlTransfer::kPopAndRepush}}, // --
{7, {1, 0, ControlTransfer::kPushVoid}});
}
TEST_F(ControlTransferTest, IfElseBr) {
byte code[] = {
kExprI32Const, // @0
0, // +1
kExprIf, // @2
kExprNop, // @3
kExprElse, // @4
kExprBr, // @5
ARITY_0, // +1
0, // +1
kExprEnd // @8
};
EXPECT_TARGETS({2, {3, 0, ControlTransfer::kNoAction}}, // --
{4, {5, 1, ControlTransfer::kPopAndRepush}}, // --
{5, {4, 0, ControlTransfer::kPushVoid}}, // --
{8, {1, 1, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, BlockEmpty) {
byte code[] = {
kExprBlock, // @0
kExprEnd // @1
};
EXPECT_TARGETS({1, {1, 0, ControlTransfer::kPushVoid}});
}
TEST_F(ControlTransferTest, Br0) {
byte code[] = {
kExprBlock, // @0
kExprBr, // @1
ARITY_0, // +1
0, // +1
kExprEnd // @4
};
EXPECT_TARGETS({1, {4, 0, ControlTransfer::kPushVoid}},
{4, {1, 1, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, Br1) {
byte code[] = {
kExprBlock, // @0
kExprNop, // @1
kExprBr, // @2
ARITY_0, // +1
0, // +1
kExprEnd // @5
};
EXPECT_TARGETS({2, {4, 1, ControlTransfer::kPopAndRepush}}, // --
{5, {1, 2, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, Br2) {
byte code[] = {
kExprBlock, // @0
kExprNop, // @1
kExprNop, // @2
kExprBr, // @3
ARITY_0, // +1
0, // +1
kExprEnd // @6
};
EXPECT_TARGETS({3, {4, 2, ControlTransfer::kPopAndRepush}}, // --
{6, {1, 3, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, Br0b) {
byte code[] = {
kExprBlock, // @0
kExprBr, // @1
ARITY_0, // +1
0, // +1
kExprNop, // @4
kExprEnd // @5
};
EXPECT_TARGETS({1, {5, 0, ControlTransfer::kPushVoid}}, // --
{5, {1, 2, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, Br0c) {
byte code[] = {
kExprBlock, // @0
kExprBr, // @1
ARITY_0, // +1
0, // +1
kExprNop, // @4
kExprNop, // @5
kExprEnd // @6
};
EXPECT_TARGETS({1, {6, 0, ControlTransfer::kPushVoid}}, // --
{6, {1, 3, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, SimpleLoop1) {
byte code[] = {
kExprLoop, // @0
kExprBr, // @1
ARITY_0, // +1
0, // +1
kExprEnd // @4
};
EXPECT_TARGETS({1, {-1, 0, ControlTransfer::kNoAction}}, // --
{4, {1, 1, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, SimpleLoop2) {
byte code[] = {
kExprLoop, // @0
kExprNop, // @1
kExprBr, // @2
ARITY_0, // +1
0, // +1
kExprEnd // @5
};
EXPECT_TARGETS({2, {-2, 1, ControlTransfer::kNoAction}}, // --
{5, {1, 2, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, SimpleLoopExit1) {
byte code[] = {
kExprLoop, // @0
kExprBr, // @1
ARITY_0, // +1
1, // +1
kExprEnd // @4
};
EXPECT_TARGETS({1, {4, 0, ControlTransfer::kPushVoid}}, // --
{4, {1, 1, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, SimpleLoopExit2) {
byte code[] = {
kExprLoop, // @0
kExprNop, // @1
kExprBr, // @2
ARITY_0, // +1
1, // +1
kExprEnd // @5
};
EXPECT_TARGETS({2, {4, 1, ControlTransfer::kPopAndRepush}}, // --
{5, {1, 2, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, BrTable0) {
byte code[] = {
kExprBlock, // @0
kExprI8Const, // @1
0, // +1
kExprBrTable, // @3
ARITY_0, // +1
0, // +1
U32_LE(0), // +4
kExprEnd // @10
};
EXPECT_TARGETS({3, {8, 0, ControlTransfer::kPushVoid}}, // --
{10, {1, 1, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, BrTable1) {
byte code[] = {
kExprBlock, // @0
kExprI8Const, // @1
0, // +1
kExprBrTable, // @3
ARITY_0, // +1
1, // +1
U32_LE(0), // +4
U32_LE(0), // +4
kExprEnd // @14
};
EXPECT_TARGETS({3, {12, 0, ControlTransfer::kPushVoid}}, // --
{4, {11, 0, ControlTransfer::kPushVoid}}, // --
{14, {1, 1, ControlTransfer::kPopAndRepush}});
}
TEST_F(ControlTransferTest, BrTable2) {
byte code[] = {
kExprBlock, // @0
kExprBlock, // @1
kExprI8Const, // @2
0, // +1
kExprBrTable, // @4
ARITY_0, // +1
2, // +1
U32_LE(0), // +4
U32_LE(0), // +4
U32_LE(1), // +4
kExprEnd, // @19
kExprEnd // @19
};
EXPECT_TARGETS({4, {16, 0, ControlTransfer::kPushVoid}}, // --
{5, {15, 0, ControlTransfer::kPushVoid}}, // --
{6, {15, 0, ControlTransfer::kPushVoid}}, // --
{19, {1, 1, ControlTransfer::kPopAndRepush}}, // --
{20, {1, 1, ControlTransfer::kPopAndRepush}});
}
} // namespace wasm
} // namespace internal
} // namespace v8
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