[wasm][anyref] Implement decoding of new instructions

R=titzer@chromium.org

Bug: v8:7581
Change-Id: I66bf50bc1243cb5e4b9f2693febf91f74077a2f4
Reviewed-on: https://chromium-review.googlesource.com/978002
Reviewed-by: Ben Titzer <titzer@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52176}
This commit is contained in:
Andreas Haas 2018-03-23 11:53:57 +01:00 committed by Commit Bot
parent 52ee1aab52
commit 68b4026c20
8 changed files with 114 additions and 24 deletions

View File

@ -828,6 +828,8 @@ class LiftoffCompiler {
__ PushRegister(kWasmF64, reg);
}
void RefNull(Decoder* decoder, Value* result) { UNIMPLEMENTED(); }
void Drop(Decoder* decoder, const Value& value) {
__ DropStackSlot(&__ cache_state()->stack_state.back());
__ cache_state()->stack_state.pop_back();

View File

@ -605,6 +605,7 @@ struct ControlWithNamedConstructors : public ControlBase<Value> {
F(I64Const, Value* result, int64_t value) \
F(F32Const, Value* result, float value) \
F(F64Const, Value* result, double value) \
F(RefNull, Value* result) \
F(Drop, const Value& value) \
F(DoReturn, Vector<Value> values, bool implicit) \
F(GetLocal, Value* result, const LocalIndexOperand<validate>& operand) \
@ -707,6 +708,13 @@ class WasmDecoder : public Decoder {
case kLocalF64:
type = kWasmF64;
break;
case kLocalAnyRef:
if (FLAG_experimental_wasm_anyref) {
type = kWasmAnyRef;
break;
}
decoder->error(decoder->pc() - 1, "invalid local type");
return false;
case kLocalS128:
if (FLAG_experimental_wasm_simd) {
type = kWasmS128;
@ -1003,6 +1011,9 @@ class WasmDecoder : public Decoder {
ImmI64Operand<validate> operand(decoder, pc);
return 1 + operand.length;
}
case kExprRefNull: {
return 1;
}
case kExprGrowMemory:
case kExprMemorySize: {
MemoryIndexOperand<validate> operand(decoder, pc);
@ -1095,6 +1106,7 @@ class WasmDecoder : public Decoder {
case kExprI64Const:
case kExprF32Const:
case kExprF64Const:
case kExprRefNull:
case kExprMemorySize:
return {0, 1};
case kExprCallFunction: {
@ -1680,6 +1692,13 @@ class WasmFullDecoder : public WasmDecoder<validate> {
len = 1 + operand.length;
break;
}
case kExprRefNull: {
CHECK_PROTOTYPE_OPCODE(anyref);
auto* value = Push(kWasmAnyRef);
CALL_INTERFACE_IF_REACHABLE(RefNull, value);
len = 1;
break;
}
case kExprGetLocal: {
LocalIndexOperand<Decoder::kValidate> operand(this, this->pc_);
if (!this->Validate(this->pc_, operand)) break;
@ -2400,6 +2419,10 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (WasmOpcodes::IsSignExtensionOpcode(opcode)) {
RET_ON_PROTOTYPE_OPCODE(se);
}
if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
RET_ON_PROTOTYPE_OPCODE(anyref);
}
switch (sig->parameter_count()) {
case 1: {
auto val = Pop(0, sig->GetParam(0));

View File

@ -235,6 +235,10 @@ class WasmGraphBuildingInterface {
result->node = builder_->Float64Constant(value);
}
void RefNull(Decoder* decoder, Value* result) {
result->node = builder_->HeapConstant(Handle<HeapObject>::null());
}
void Drop(Decoder* decoder, const Value& value) {}
void DoReturn(Decoder* decoder, Vector<Value> values, bool implicit) {

View File

@ -22,6 +22,7 @@ namespace wasm {
#define CASE_I64_OP(name, str) CASE_OP(I64##name, "i64." str)
#define CASE_F32_OP(name, str) CASE_OP(F32##name, "f32." str)
#define CASE_F64_OP(name, str) CASE_OP(F64##name, "f64." str)
#define CASE_REF_OP(name, str) CASE_OP(Ref##name, "ref." str)
#define CASE_F32x4_OP(name, str) CASE_OP(F32x4##name, "f32x4." str)
#define CASE_I32x4_OP(name, str) CASE_OP(I32x4##name, "i32x4." str)
#define CASE_I16x8_OP(name, str) CASE_OP(I16x8##name, "i16x8." str)
@ -104,6 +105,9 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_FLOAT_OP(Min, "min")
CASE_FLOAT_OP(Max, "max")
CASE_FLOAT_OP(CopySign, "copysign")
CASE_REF_OP(Null, "null")
CASE_REF_OP(IsNull, "is_null")
CASE_REF_OP(Eq, "eq")
CASE_I32_OP(ConvertI64, "wrap/i64")
CASE_CONVERT_OP(Convert, INT, F32, "f32", "trunc")
CASE_CONVERT_OP(Convert, INT, F64, "f64", "trunc")
@ -273,6 +277,7 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
#undef CASE_I64_OP
#undef CASE_F32_OP
#undef CASE_F64_OP
#undef CASE_REF_OP
#undef CASE_F32x4_OP
#undef CASE_I32x4_OP
#undef CASE_I16x8_OP
@ -345,6 +350,16 @@ bool WasmOpcodes::IsSignExtensionOpcode(WasmOpcode opcode) {
}
}
bool WasmOpcodes::IsAnyRefOpcode(WasmOpcode opcode) {
switch (opcode) {
case kExprRefNull:
case kExprRefIsNull:
case kExprRefEq:
return true;
default:
return false;
}
}
std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) {
if (sig.return_count() == 0) os << "v";
for (auto ret : sig.returns()) {

View File

@ -66,7 +66,8 @@ using WasmName = Vector<const char>;
V(I32Const, 0x41, _) \
V(I64Const, 0x42, _) \
V(F32Const, 0x43, _) \
V(F64Const, 0x44, _)
V(F64Const, 0x44, _) \
V(RefNull, 0xd0, _)
// Load memory expressions.
#define FOREACH_LOAD_MEM_OPCODE(V) \
@ -231,7 +232,9 @@ using WasmName = Vector<const char>;
V(I32SExtendI16, 0xc1, i_i) \
V(I64SExtendI8, 0xc2, l_l) \
V(I64SExtendI16, 0xc3, l_l) \
V(I64SExtendI32, 0xc4, l_l)
V(I64SExtendI32, 0xc4, l_l) \
V(RefIsNull, 0xd1, i_r) \
V(RefEq, 0xd2, i_rr)
// For compatibility with Asm.js.
#define FOREACH_ASMJS_COMPAT_OPCODE(V) \
@ -246,26 +249,26 @@ using WasmName = Vector<const char>;
V(F64Atan2, 0xcd, d_dd) \
V(F64Pow, 0xce, d_dd) \
V(F64Mod, 0xcf, d_dd) \
V(I32AsmjsDivS, 0xd0, i_ii) \
V(I32AsmjsDivU, 0xd1, i_ii) \
V(I32AsmjsRemS, 0xd2, i_ii) \
V(I32AsmjsRemU, 0xd3, i_ii) \
V(I32AsmjsLoadMem8S, 0xd4, i_i) \
V(I32AsmjsLoadMem8U, 0xd5, i_i) \
V(I32AsmjsLoadMem16S, 0xd6, i_i) \
V(I32AsmjsLoadMem16U, 0xd7, i_i) \
V(I32AsmjsLoadMem, 0xd8, i_i) \
V(F32AsmjsLoadMem, 0xd9, f_i) \
V(F64AsmjsLoadMem, 0xda, d_i) \
V(I32AsmjsStoreMem8, 0xdb, i_ii) \
V(I32AsmjsStoreMem16, 0xdc, i_ii) \
V(I32AsmjsStoreMem, 0xdd, i_ii) \
V(F32AsmjsStoreMem, 0xde, f_if) \
V(F64AsmjsStoreMem, 0xdf, d_id) \
V(I32AsmjsSConvertF32, 0xe0, i_f) \
V(I32AsmjsUConvertF32, 0xe1, i_f) \
V(I32AsmjsSConvertF64, 0xe2, i_d) \
V(I32AsmjsUConvertF64, 0xe3, i_d)
V(I32AsmjsDivS, 0xd3, i_ii) \
V(I32AsmjsDivU, 0xd4, i_ii) \
V(I32AsmjsRemS, 0xd5, i_ii) \
V(I32AsmjsRemU, 0xd6, i_ii) \
V(I32AsmjsLoadMem8S, 0xd7, i_i) \
V(I32AsmjsLoadMem8U, 0xd8, i_i) \
V(I32AsmjsLoadMem16S, 0xd9, i_i) \
V(I32AsmjsLoadMem16U, 0xda, i_i) \
V(I32AsmjsLoadMem, 0xdb, i_i) \
V(F32AsmjsLoadMem, 0xdc, f_i) \
V(F64AsmjsLoadMem, 0xdd, d_i) \
V(I32AsmjsStoreMem8, 0xde, i_ii) \
V(I32AsmjsStoreMem16, 0xdf, i_ii) \
V(I32AsmjsStoreMem, 0xe0, i_ii) \
V(F32AsmjsStoreMem, 0xe1, f_if) \
V(F64AsmjsStoreMem, 0xe2, d_id) \
V(I32AsmjsSConvertF32, 0xe3, i_f) \
V(I32AsmjsUConvertF32, 0xe4, i_f) \
V(I32AsmjsSConvertF64, 0xe5, i_d) \
V(I32AsmjsUConvertF64, 0xe6, i_d)
#define FOREACH_SIMD_0_OPERAND_OPCODE(V) \
V(F32x4Splat, 0xfd00, s_f) \
@ -531,7 +534,9 @@ using WasmName = Vector<const char>;
V(v_il, kWasmStmt, kWasmI32, kWasmI64) \
V(l_il, kWasmI64, kWasmI32, kWasmI64) \
V(i_iii, kWasmI32, kWasmI32, kWasmI32, kWasmI32) \
V(l_ill, kWasmI64, kWasmI32, kWasmI64, kWasmI64)
V(l_ill, kWasmI64, kWasmI32, kWasmI64, kWasmI64) \
V(i_r, kWasmI32, kWasmAnyRef) \
V(i_rr, kWasmI32, kWasmAnyRef, kWasmAnyRef)
#define FOREACH_SIMD_SIGNATURE(V) \
V(s_s, kWasmS128, kWasmS128) \
@ -725,6 +730,7 @@ class V8_EXPORT_PRIVATE WasmOpcodes {
static bool IsPrefixOpcode(WasmOpcode opcode);
static bool IsControlOpcode(WasmOpcode opcode);
static bool IsSignExtensionOpcode(WasmOpcode opcode);
static bool IsAnyRefOpcode(WasmOpcode opcode);
// Check whether the given opcode always jumps, i.e. all instructions after
// this one in the current block are dead. Returns false for |end|.
static bool IsUnconditionalJump(WasmOpcode opcode);
@ -769,6 +775,8 @@ class V8_EXPORT_PRIVATE WasmOpcodes {
return MachineType::Float32();
case kWasmF64:
return MachineType::Float64();
case kWasmAnyRef:
return MachineType::TaggedPointer();
case kWasmS128:
return MachineType::Simd128();
case kWasmStmt:
@ -790,6 +798,8 @@ class V8_EXPORT_PRIVATE WasmOpcodes {
return kWasmF32;
case MachineRepresentation::kFloat64:
return kWasmF64;
case MachineRepresentation::kTaggedPointer:
return kWasmAnyRef;
case MachineRepresentation::kSimd128:
return kWasmS128;
default:
@ -807,6 +817,8 @@ class V8_EXPORT_PRIVATE WasmOpcodes {
return 'f';
case kWasmF64:
return 'd';
case kWasmAnyRef:
return 'r';
case kWasmS128:
return 's';
case kWasmStmt:
@ -828,6 +840,8 @@ class V8_EXPORT_PRIVATE WasmOpcodes {
return "f32";
case kWasmF64:
return "f64";
case kWasmAnyRef:
return "ref";
case kWasmS128:
return "s128";
case kWasmStmt:

View File

@ -1952,6 +1952,9 @@ static void TestBuildGraphForSimpleExpression(WasmOpcode opcode) {
// TODO(gdeepti): Enable this test for sign extension opcodes when lowering
// is enabled.
if (WasmOpcodes::IsSignExtensionOpcode(opcode)) return;
// TODO(ahaas): Enable this test for anyref opcodes when code generation for
// them is implemented.
if (WasmOpcodes::IsAnyRefOpcode(opcode)) return;
// Enable all optional operators.
compiler::CommonOperatorBuilder common(&zone);
compiler::MachineOperatorBuilder machine(

View File

@ -26,6 +26,8 @@ class TestSignatures {
sig_i_ff(1, 2, kIntFloatTypes4),
sig_i_d(1, 1, kIntDoubleTypes4),
sig_i_dd(1, 2, kIntDoubleTypes4),
sig_i_r(1, 1, kIntRefTypes4),
sig_i_rr(1, 2, kIntRefTypes4),
sig_l_v(1, 0, kLongTypes4),
sig_l_l(1, 1, kLongTypes4),
sig_l_ll(1, 2, kLongTypes4),
@ -34,6 +36,7 @@ class TestSignatures {
sig_f_ff(1, 2, kFloatTypes4),
sig_d_d(1, 1, kDoubleTypes4),
sig_d_dd(1, 2, kDoubleTypes4),
sig_r_v(1, 0, kRefTypes4),
sig_v_v(0, 0, kIntTypes4),
sig_v_i(0, 1, kIntTypes4),
sig_v_ii(0, 2, kIntTypes4),
@ -46,13 +49,16 @@ class TestSignatures {
for (int i = 0; i < 4; i++) kLongTypes4[i] = kWasmI64;
for (int i = 0; i < 4; i++) kFloatTypes4[i] = kWasmF32;
for (int i = 0; i < 4; i++) kDoubleTypes4[i] = kWasmF64;
for (int i = 0; i < 4; i++) kRefTypes4[i] = kWasmAnyRef;
for (int i = 0; i < 4; i++) kIntLongTypes4[i] = kWasmI64;
for (int i = 0; i < 4; i++) kIntFloatTypes4[i] = kWasmF32;
for (int i = 0; i < 4; i++) kIntDoubleTypes4[i] = kWasmF64;
for (int i = 0; i < 4; i++) kIntRefTypes4[i] = kWasmAnyRef;
for (int i = 0; i < 4; i++) kSimd128IntTypes4[i] = kWasmS128;
kIntLongTypes4[0] = kWasmI32;
kIntFloatTypes4[0] = kWasmI32;
kIntDoubleTypes4[0] = kWasmI32;
kIntRefTypes4[0] = kWasmI32;
kSimd128IntTypes4[1] = kWasmI32;
}
@ -70,12 +76,16 @@ class TestSignatures {
FunctionSig* l_l() { return &sig_l_l; }
FunctionSig* l_ll() { return &sig_l_ll; }
FunctionSig* i_ll() { return &sig_i_ll; }
FunctionSig* i_r() { return &sig_i_r; }
FunctionSig* i_rr() { return &sig_i_rr; }
FunctionSig* f_f() { return &sig_f_f; }
FunctionSig* f_ff() { return &sig_f_ff; }
FunctionSig* d_d() { return &sig_d_d; }
FunctionSig* d_dd() { return &sig_d_dd; }
FunctionSig* r_v() { return &sig_r_v; }
FunctionSig* v_v() { return &sig_v_v; }
FunctionSig* v_i() { return &sig_v_i; }
FunctionSig* v_ii() { return &sig_v_ii; }
@ -99,9 +109,11 @@ class TestSignatures {
ValueType kLongTypes4[4];
ValueType kFloatTypes4[4];
ValueType kDoubleTypes4[4];
ValueType kRefTypes4[4];
ValueType kIntLongTypes4[4];
ValueType kIntFloatTypes4[4];
ValueType kIntDoubleTypes4[4];
ValueType kIntRefTypes4[4];
ValueType kSimd128IntTypes4[4];
FunctionSig sig_i_v;
@ -113,6 +125,8 @@ class TestSignatures {
FunctionSig sig_i_ff;
FunctionSig sig_i_d;
FunctionSig sig_i_dd;
FunctionSig sig_i_r;
FunctionSig sig_i_rr;
FunctionSig sig_l_v;
FunctionSig sig_l_l;
@ -124,6 +138,8 @@ class TestSignatures {
FunctionSig sig_d_d;
FunctionSig sig_d_dd;
FunctionSig sig_r_v;
FunctionSig sig_v_v;
FunctionSig sig_v_i;
FunctionSig sig_v_ii;

View File

@ -36,7 +36,8 @@ static const byte kCodeGetLocal1[] = {kExprGetLocal, 1};
static const byte kCodeSetLocal0[] = {WASM_SET_LOCAL(0, WASM_ZERO)};
static const byte kCodeTeeLocal0[] = {WASM_TEE_LOCAL(0, WASM_ZERO)};
static const ValueType kValueTypes[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64};
static const ValueType kValueTypes[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64,
kWasmAnyRef};
static const MachineType machineTypes[] = {
MachineType::Int8(), MachineType::Uint8(), MachineType::Int16(),
MachineType::Uint16(), MachineType::Int32(), MachineType::Uint32(),
@ -260,6 +261,12 @@ TEST_F(FunctionBodyDecoderTest, Int32Const1) {
}
}
TEST_F(FunctionBodyDecoderTest, RefNull) {
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
byte code[] = {kExprRefNull};
EXPECT_VERIFIES_C(r_v, code);
}
TEST_F(FunctionBodyDecoderTest, EmptyFunction) {
byte code[] = {0};
Verify(true, sigs.v_v(), code, code, kAppendEnd);
@ -928,6 +935,7 @@ TEST_F(FunctionBodyDecoderTest, ReturnVoid3) {
EXPECT_FAILURE(v_v, kExprI64Const, 0);
EXPECT_FAILURE(v_v, kExprF32Const, 0, 0, 0, 0);
EXPECT_FAILURE(v_v, kExprF64Const, 0, 0, 0, 0, 0, 0, 0, 0);
EXPECT_FAILURE(v_v, kExprRefNull);
EXPECT_FAILURE(v_i, kExprGetLocal, 0);
}
@ -1228,6 +1236,7 @@ TEST_F(FunctionBodyDecoderTest, MacrosInt64) {
TEST_F(FunctionBodyDecoderTest, AllSimpleExpressions) {
EXPERIMENTAL_FLAG_SCOPE(se);
EXPERIMENTAL_FLAG_SCOPE(anyref);
// Test all simple expressions which are described by a signature.
#define DECODE_TEST(name, opcode, sig) \
{ \
@ -2777,6 +2786,7 @@ TEST_F(WasmOpcodeLengthTest, Statements) {
TEST_F(WasmOpcodeLengthTest, MiscExpressions) {
EXPECT_LENGTH(5, kExprF32Const);
EXPECT_LENGTH(9, kExprF64Const);
EXPECT_LENGTH(1, kExprRefNull);
EXPECT_LENGTH(2, kExprGetLocal);
EXPECT_LENGTH(2, kExprSetLocal);
EXPECT_LENGTH(2, kExprGetGlobal);
@ -2964,6 +2974,7 @@ TEST_F(WasmOpcodeLengthTest, SimpleExpressions) {
EXPECT_LENGTH(1, kExprF64ReinterpretI64);
EXPECT_LENGTH(1, kExprI32ReinterpretF32);
EXPECT_LENGTH(1, kExprI64ReinterpretF64);
EXPECT_LENGTH(1, kExprRefEq);
}
TEST_F(WasmOpcodeLengthTest, SimdExpressions) {
@ -3013,6 +3024,7 @@ TEST_F(LocalDeclDecoderTest, NoLocals) {
}
TEST_F(LocalDeclDecoderTest, OneLocal) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueType type = kValueTypes[i];
const byte data[] = {
@ -3028,6 +3040,7 @@ TEST_F(LocalDeclDecoderTest, OneLocal) {
}
TEST_F(LocalDeclDecoderTest, FiveLocals) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueType type = kValueTypes[i];
const byte data[] = {