Commit dbc8aa87 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm] Add type immediate to RefNull and RefIsNull instructions

With recent changes to the anyref proposal, null refs now have a type
immediate which declares the type of a null ref constant. Likewise,
the RefIsNull instruction is type aware now. This CL addresses these
proposal changes now.

R=jkummerow@chromium.org

Bug: v8:10556
Change-Id: I810dfa3a4ab4389afc9639f897cee5d43e9b62cb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2215172
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68141}
parent 490f3580
...@@ -128,81 +128,6 @@ struct WasmException; ...@@ -128,81 +128,6 @@ struct WasmException;
V(I64AtomicStore16U, Uint16) \ V(I64AtomicStore16U, Uint16) \
V(I64AtomicStore32U, Uint32) V(I64AtomicStore32U, Uint32)
// Helpers for decoding different kinds of immediates which follow bytecodes.
template <Decoder::ValidateFlag validate>
struct LocalIndexImmediate {
uint32_t index;
ValueType type = kWasmStmt;
uint32_t length;
inline LocalIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "local index");
}
};
template <Decoder::ValidateFlag validate>
struct ExceptionIndexImmediate {
uint32_t index;
const WasmException* exception = nullptr;
uint32_t length;
inline ExceptionIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "exception index");
}
};
template <Decoder::ValidateFlag validate>
struct ImmI32Immediate {
int32_t value;
uint32_t length;
inline ImmI32Immediate(Decoder* decoder, const byte* pc) {
value = decoder->read_i32v<validate>(pc + 1, &length, "immi32");
}
};
template <Decoder::ValidateFlag validate>
struct ImmI64Immediate {
int64_t value;
uint32_t length;
inline ImmI64Immediate(Decoder* decoder, const byte* pc) {
value = decoder->read_i64v<validate>(pc + 1, &length, "immi64");
}
};
template <Decoder::ValidateFlag validate>
struct ImmF32Immediate {
float value;
uint32_t length = 4;
inline ImmF32Immediate(Decoder* decoder, const byte* pc) {
// Avoid bit_cast because it might not preserve the signalling bit of a NaN.
uint32_t tmp = decoder->read_u32<validate>(pc + 1, "immf32");
memcpy(&value, &tmp, sizeof(value));
}
};
template <Decoder::ValidateFlag validate>
struct ImmF64Immediate {
double value;
uint32_t length = 8;
inline ImmF64Immediate(Decoder* decoder, const byte* pc) {
// Avoid bit_cast because it might not preserve the signalling bit of a NaN.
uint64_t tmp = decoder->read_u64<validate>(pc + 1, "immf64");
memcpy(&value, &tmp, sizeof(value));
}
};
template <Decoder::ValidateFlag validate>
struct GlobalIndexImmediate {
uint32_t index;
ValueType type = kWasmStmt;
const WasmGlobal* global = nullptr;
uint32_t length;
inline GlobalIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "global index");
}
};
namespace value_type_reader { namespace value_type_reader {
// Read a value type starting at address 'pc' in 'decoder'. // Read a value type starting at address 'pc' in 'decoder'.
...@@ -345,6 +270,94 @@ ValueType read_value_type(Decoder* decoder, const byte* pc, ...@@ -345,6 +270,94 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
} }
} // namespace value_type_reader } // namespace value_type_reader
// Helpers for decoding different kinds of immediates which follow bytecodes.
template <Decoder::ValidateFlag validate>
struct LocalIndexImmediate {
uint32_t index;
ValueType type = kWasmStmt;
uint32_t length;
inline LocalIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "local index");
}
};
template <Decoder::ValidateFlag validate>
struct ExceptionIndexImmediate {
uint32_t index;
const WasmException* exception = nullptr;
uint32_t length;
inline ExceptionIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "exception index");
}
};
template <Decoder::ValidateFlag validate>
struct ImmI32Immediate {
int32_t value;
uint32_t length;
inline ImmI32Immediate(Decoder* decoder, const byte* pc) {
value = decoder->read_i32v<validate>(pc + 1, &length, "immi32");
}
};
template <Decoder::ValidateFlag validate>
struct ImmI64Immediate {
int64_t value;
uint32_t length;
inline ImmI64Immediate(Decoder* decoder, const byte* pc) {
value = decoder->read_i64v<validate>(pc + 1, &length, "immi64");
}
};
template <Decoder::ValidateFlag validate>
struct ImmF32Immediate {
float value;
uint32_t length = 4;
inline ImmF32Immediate(Decoder* decoder, const byte* pc) {
// We can't use bit_cast here because calling any helper function that
// returns a float would potentially flip NaN bits per C++ semantics, so we
// have to inline the memcpy call directly.
uint32_t tmp = decoder->read_u32<validate>(pc + 1, "immf32");
memcpy(&value, &tmp, sizeof(value));
}
};
template <Decoder::ValidateFlag validate>
struct ImmF64Immediate {
double value;
uint32_t length = 8;
inline ImmF64Immediate(Decoder* decoder, const byte* pc) {
// Avoid bit_cast because it might not preserve the signalling bit of a NaN.
uint64_t tmp = decoder->read_u64<validate>(pc + 1, "immf64");
memcpy(&value, &tmp, sizeof(value));
}
};
template <Decoder::ValidateFlag validate>
struct RefNullImmediate {
ValueType type;
uint32_t length = 1;
inline RefNullImmediate(const WasmFeatures& enabled, Decoder* decoder,
const byte* pc) {
type = value_type_reader::read_value_type<validate>(decoder, pc + 1,
&length, enabled);
}
};
template <Decoder::ValidateFlag validate>
struct GlobalIndexImmediate {
uint32_t index;
ValueType type = kWasmStmt;
const WasmGlobal* global = nullptr;
uint32_t length;
inline GlobalIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "global index");
}
};
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct SelectTypeImmediate { struct SelectTypeImmediate {
uint32_t length; uint32_t length;
...@@ -1109,6 +1122,14 @@ class WasmDecoder : public Decoder { ...@@ -1109,6 +1122,14 @@ class WasmDecoder : public Decoder {
return true; return true;
} }
inline bool Validate(const byte* pc, RefNullImmediate<validate>& imm) {
if (!VALIDATE(imm.type.IsNullable())) {
errorf(pc + 1, "ref.null does not exist for %s", imm.type.type_name());
return false;
}
return true;
}
inline bool Complete(const byte* pc, ExceptionIndexImmediate<validate>& imm) { inline bool Complete(const byte* pc, ExceptionIndexImmediate<validate>& imm) {
if (!VALIDATE(imm.index < module_->exceptions.size())) return false; if (!VALIDATE(imm.index < module_->exceptions.size())) return false;
imm.exception = &module_->exceptions[imm.index]; imm.exception = &module_->exceptions[imm.index];
...@@ -1483,7 +1504,12 @@ class WasmDecoder : public Decoder { ...@@ -1483,7 +1504,12 @@ class WasmDecoder : public Decoder {
return 1 + imm.length; return 1 + imm.length;
} }
case kExprRefNull: { case kExprRefNull: {
return 1; RefNullImmediate<validate> imm(WasmFeatures::All(), decoder, pc);
return 1 + imm.length;
}
case kExprRefIsNull: {
RefNullImmediate<validate> imm(WasmFeatures::All(), decoder, pc);
return 1 + imm.length;
} }
case kExprRefFunc: { case kExprRefFunc: {
FunctionIndexImmediate<validate> imm(decoder, pc); FunctionIndexImmediate<validate> imm(decoder, pc);
...@@ -1682,6 +1708,7 @@ class WasmDecoder : public Decoder { ...@@ -1682,6 +1708,7 @@ class WasmDecoder : public Decoder {
case kExprMemoryGrow: case kExprMemoryGrow:
case kExprRefAsNonNull: case kExprRefAsNonNull:
case kExprBrOnNull: case kExprBrOnNull:
case kExprRefIsNull:
return {1, 1}; return {1, 1};
case kExprLocalSet: case kExprLocalSet:
case kExprGlobalSet: case kExprGlobalSet:
...@@ -2076,6 +2103,7 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2076,6 +2103,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
for (size_t i = 0; i < value_count; ++i) Push(sig->GetParam(i)); for (size_t i = 0; i < value_count; ++i) Push(sig->GetParam(i));
Vector<Value> values(stack_.data() + c->stack_depth, value_count); Vector<Value> values(stack_.data() + c->stack_depth, value_count);
TypeCheckBranchResult check_result = TypeCheckBranch(c, true); TypeCheckBranchResult check_result = TypeCheckBranch(c, true);
if (this->failed()) break;
if (V8_LIKELY(check_result == kReachableBranch)) { if (V8_LIKELY(check_result == kReachableBranch)) {
CALL_INTERFACE(BrOnException, exception, imm.index, imm.depth.depth, CALL_INTERFACE(BrOnException, exception, imm.index, imm.depth.depth,
values); values);
...@@ -2415,9 +2443,21 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2415,9 +2443,21 @@ class WasmFullDecoder : public WasmDecoder<validate> {
} }
case kExprRefNull: { case kExprRefNull: {
CHECK_PROTOTYPE_OPCODE(anyref); CHECK_PROTOTYPE_OPCODE(anyref);
Value* value = Push(kWasmNullRef); RefNullImmediate<validate> imm(this->enabled_, this, this->pc_);
if (!this->Validate(this->pc_, imm)) break;
Value* value = Push(imm.type);
CALL_INTERFACE_IF_REACHABLE(RefNull, value); CALL_INTERFACE_IF_REACHABLE(RefNull, value);
len = 1; len = 1 + imm.length;
break;
}
case kExprRefIsNull: {
CHECK_PROTOTYPE_OPCODE(anyref);
RefNullImmediate<validate> imm(this->enabled_, this, this->pc_);
if (!this->Validate(this->pc_, imm)) break;
Value value = Pop(0, imm.type);
Value* result = Push(kWasmI32);
CALL_INTERFACE_IF_REACHABLE(UnOp, opcode, value, result);
len = 1 + imm.length;
break; break;
} }
case kExprRefFunc: { case kExprRefFunc: {
...@@ -3697,9 +3737,7 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -3697,9 +3737,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
} }
void BuildSimplePrototypeOperator(WasmOpcode opcode) { void BuildSimplePrototypeOperator(WasmOpcode opcode) {
if (opcode == kExprRefIsNull) { if (opcode == kExprRefEq) {
RET_ON_PROTOTYPE_OPCODE(anyref);
} else if (opcode == kExprRefEq) {
RET_ON_PROTOTYPE_OPCODE(gc); RET_ON_PROTOTYPE_OPCODE(gc);
} }
const FunctionSig* sig = WasmOpcodes::Signature(opcode); const FunctionSig* sig = WasmOpcodes::Signature(opcode);
......
...@@ -122,12 +122,15 @@ ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) { ...@@ -122,12 +122,15 @@ ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
return kWasmF32; return kWasmF32;
case WasmInitExpr::kF64Const: case WasmInitExpr::kF64Const:
return kWasmF64; return kWasmF64;
case WasmInitExpr::kRefNullConst:
return kWasmNullRef;
case WasmInitExpr::kRefFuncConst: case WasmInitExpr::kRefFuncConst:
return kWasmFuncRef; return kWasmFuncRef;
case WasmInitExpr::kRefNullConst:
// It is not possible to retrieve the full {ValueType} of a {WasmInitExpr}
// of kind {kRefNullConst}. As WasmInitExpr of kind {krefNullConst} is
// only valid in globals, the {ValueType} has to be retrieved from the
// global definition itself.
UNREACHABLE();
} }
UNREACHABLE();
} }
// Reads a length-prefixed string, checking that it is within bounds. Returns // Reads a length-prefixed string, checking that it is within bounds. Returns
...@@ -1423,7 +1426,7 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1423,7 +1426,7 @@ class ModuleDecoderImpl : public Decoder {
global->type = consume_value_type(); global->type = consume_value_type();
global->mutability = consume_mutability(); global->mutability = consume_mutability();
const byte* pos = pc(); const byte* pos = pc();
global->init = consume_init_expr(module, kWasmStmt); global->init = consume_init_expr(module, global->type);
if (global->init.kind == WasmInitExpr::kGlobalIndex) { if (global->init.kind == WasmInitExpr::kGlobalIndex) {
uint32_t other_index = global->init.val.global_index; uint32_t other_index = global->init.val.global_index;
if (other_index >= index) { if (other_index >= index) {
...@@ -1438,12 +1441,6 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1438,12 +1441,6 @@ class ModuleDecoderImpl : public Decoder {
other_index, global->type.type_name(), other_index, global->type.type_name(),
module->globals[other_index].type.type_name()); module->globals[other_index].type.type_name());
} }
} else {
if (!TypeOf(module, global->init).IsSubTypeOf(global->type)) {
errorf(pos, "type error in global initialization, expected %s, got %s",
global->type.type_name(),
TypeOf(module, global->init).type_name());
}
} }
} }
...@@ -1698,8 +1695,19 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1698,8 +1695,19 @@ class ModuleDecoderImpl : public Decoder {
} }
case kExprRefNull: { case kExprRefNull: {
if (enabled_features_.has_anyref() || enabled_features_.has_eh()) { if (enabled_features_.has_anyref() || enabled_features_.has_eh()) {
RefNullImmediate<Decoder::kValidate> imm(WasmFeatures::All(), this,
pc() - 1);
if (!imm.type.IsReferenceType()) {
errorf(pc() - 1, "ref.null is not supported for %s",
imm.type.type_name());
break;
}
expr.kind = WasmInitExpr::kRefNullConst; expr.kind = WasmInitExpr::kRefNullConst;
len = 0; len = imm.length;
if (expected != kWasmStmt && !imm.type.IsSubTypeOf(expected)) {
errorf(pos, "type error in init expression, expected %s, got %s",
expected.type_name(), imm.type.type_name());
}
break; break;
} }
V8_FALLTHROUGH; V8_FALLTHROUGH;
...@@ -1730,7 +1738,10 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1730,7 +1738,10 @@ class ModuleDecoderImpl : public Decoder {
if (!expect_u8("end opcode", kExprEnd)) { if (!expect_u8("end opcode", kExprEnd)) {
expr.kind = WasmInitExpr::kNone; expr.kind = WasmInitExpr::kNone;
} }
if (expected != kWasmStmt && TypeOf(module, expr) != kWasmI32) {
// The type check of ref.null is special, and already done above.
if (expected != kWasmStmt && opcode != kExprRefNull &&
TypeOf(module, expr) != expected) {
errorf(pos, "type error in init expression, expected %s, got %s", errorf(pos, "type error in init expression, expected %s, got %s",
expected.type_name(), TypeOf(module, expr).type_name()); expected.type_name(), TypeOf(module, expr).type_name());
} }
...@@ -2049,9 +2060,13 @@ class ModuleDecoderImpl : public Decoder { ...@@ -2049,9 +2060,13 @@ class ModuleDecoderImpl : public Decoder {
uint8_t opcode = consume_u8("element opcode"); uint8_t opcode = consume_u8("element opcode");
if (failed()) return index; if (failed()) return index;
switch (opcode) { switch (opcode) {
case kExprRefNull: case kExprRefNull: {
RefNullImmediate<kValidate> imm(WasmFeatures::All(), this,
this->pc() - 1);
consume_bytes(imm.length, "ref.null immediate");
index = WasmElemSegment::kNullIndex; index = WasmElemSegment::kNullIndex;
break; break;
}
case kExprRefFunc: case kExprRefFunc:
index = consume_element_func_index(); index = consume_element_func_index();
if (failed()) return index; if (failed()) return index;
......
...@@ -134,6 +134,11 @@ class ValueType { ...@@ -134,6 +134,11 @@ class ValueType {
return kAnyRef <= kind() && kind() <= kEqRef; return kAnyRef <= kind() && kind() <= kEqRef;
} }
constexpr bool IsNullable() const {
return kind() == kAnyRef || kind() == kFuncRef || kind() == kExnRef ||
kind() == kOptRef;
}
// TODO(7748): Extend this with struct and function subtyping. // TODO(7748): Extend this with struct and function subtyping.
// Keep up to date with funcref vs. anyref subtyping. // Keep up to date with funcref vs. anyref subtyping.
static ValueType CommonSubType(ValueType a, ValueType b) { static ValueType CommonSubType(ValueType a, ValueType b) {
......
...@@ -3183,6 +3183,9 @@ class ThreadImpl { ...@@ -3183,6 +3183,9 @@ class ThreadImpl {
break; break;
} }
case kExprRefNull: { case kExprRefNull: {
RefNullImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(),
&decoder, code->at(pc));
len = 1 + imm.length;
Push(WasmValue(isolate_->factory()->null_value())); Push(WasmValue(isolate_->factory()->null_value()));
break; break;
} }
...@@ -3519,6 +3522,9 @@ class ThreadImpl { ...@@ -3519,6 +3522,9 @@ class ThreadImpl {
SIGN_EXTENSION_CASE(I64SExtendI32, int64_t, int32_t); SIGN_EXTENSION_CASE(I64SExtendI32, int64_t, int32_t);
#undef SIGN_EXTENSION_CASE #undef SIGN_EXTENSION_CASE
case kExprRefIsNull: { case kExprRefIsNull: {
RefNullImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(),
&decoder, code->at(pc));
len = 1 + imm.length;
HandleScope handle_scope(isolate_); // Avoid leaking handles. HandleScope handle_scope(isolate_); // Avoid leaking handles.
uint32_t result = Pop().to_anyref()->IsNull() ? 1 : 0; uint32_t result = Pop().to_anyref()->IsNull() ? 1 : 0;
Push(WasmValue(result)); Push(WasmValue(result));
......
...@@ -566,6 +566,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const { ...@@ -566,6 +566,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
break; break;
case WasmInitExpr::kRefNullConst: case WasmInitExpr::kRefNullConst:
buffer->write_u8(kExprRefNull); buffer->write_u8(kExprRefNull);
WriteValueType(buffer, global.type);
break; break;
case WasmInitExpr::kRefFuncConst: case WasmInitExpr::kRefFuncConst:
UNIMPLEMENTED(); UNIMPLEMENTED();
......
...@@ -62,6 +62,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&); ...@@ -62,6 +62,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
V(F32Const, 0x43, _) \ V(F32Const, 0x43, _) \
V(F64Const, 0x44, _) \ V(F64Const, 0x44, _) \
V(RefNull, 0xd0, _) \ V(RefNull, 0xd0, _) \
V(RefIsNull, 0xd1, _) \
V(RefFunc, 0xd2, _) \ V(RefFunc, 0xd2, _) \
V(RefAsNonNull, 0xd3, _) V(RefAsNonNull, 0xd3, _)
...@@ -231,7 +232,6 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&); ...@@ -231,7 +232,6 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
V(I64SExtendI32, 0xc4, l_l) V(I64SExtendI32, 0xc4, l_l)
#define FOREACH_SIMPLE_PROTOTYPE_OPCODE(V) \ #define FOREACH_SIMPLE_PROTOTYPE_OPCODE(V) \
V(RefIsNull, 0xd1, i_r) \
V(RefEq, 0xd5, i_rr) // made-up opcode, guessing future spec (GC) V(RefEq, 0xd5, i_rr) // made-up opcode, guessing future spec (GC)
// For compatibility with Asm.js. // For compatibility with Asm.js.
...@@ -765,13 +765,16 @@ struct WasmInitExpr { ...@@ -765,13 +765,16 @@ struct WasmInitExpr {
explicit WasmInitExpr(int64_t v) : kind(kI64Const) { val.i64_const = v; } explicit WasmInitExpr(int64_t v) : kind(kI64Const) { val.i64_const = v; }
explicit WasmInitExpr(float v) : kind(kF32Const) { val.f32_const = v; } explicit WasmInitExpr(float v) : kind(kF32Const) { val.f32_const = v; }
explicit WasmInitExpr(double v) : kind(kF64Const) { val.f64_const = v; } explicit WasmInitExpr(double v) : kind(kF64Const) { val.f64_const = v; }
explicit WasmInitExpr(WasmInitKind kind) : kind(kind) {
DCHECK_EQ(kind, kRefNullConst);
}
WasmInitExpr(WasmInitKind kind, uint32_t index) : kind(kind) { WasmInitExpr(WasmInitKind kind, uint32_t index) : kind(kind) {
if (kind == kGlobalIndex) { if (kind == kGlobalIndex) {
val.global_index = index; val.global_index = index;
} else if (kind == kRefFuncConst) { } else if (kind == kRefFuncConst) {
val.function_index = index; val.function_index = index;
} else if (kind == kRefNullConst) {
// Nothing to do.
} else { } else {
// For the other types, the other initializers should be used. // For the other types, the other initializers should be used.
UNREACHABLE(); UNREACHABLE();
......
...@@ -85,17 +85,19 @@ WASM_EXEC_TEST(BasicStruct) { ...@@ -85,17 +85,19 @@ WASM_EXEC_TEST(BasicStruct) {
// Test struct.set, ref.as_non_null, // Test struct.set, ref.as_non_null,
// struct refs types in globals and if-results. // struct refs types in globals and if-results.
uint32_t k_global_index = builder->AddGlobal(kOptRefType, true); uint32_t k_global_index = builder->AddGlobal(
kOptRefType, true, WasmInitExpr(WasmInitExpr::kRefNullConst));
WasmFunctionBuilder* k = builder->AddFunction(sigs.i_v()); WasmFunctionBuilder* k = builder->AddFunction(sigs.i_v());
uint32_t k_field_index = 0; uint32_t k_field_index = 0;
k->builder()->AddExport(CStrVector("k"), k); k->builder()->AddExport(CStrVector("k"), k);
byte k_code[] = { byte k_code[] = {
WASM_SET_GLOBAL(k_global_index, WASM_STRUCT_NEW(type_index, WASM_I32V(55), WASM_SET_GLOBAL(k_global_index, WASM_STRUCT_NEW(type_index, WASM_I32V(55),
WASM_I32V(66))), WASM_I32V(66))),
WASM_STRUCT_GET(type_index, k_field_index, WASM_STRUCT_GET(
WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R( type_index, k_field_index,
kOptRefType, WASM_I32V(1), WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(kOptRefType, WASM_I32V(1),
WASM_GET_GLOBAL(k_global_index), WASM_REF_NULL))), WASM_GET_GLOBAL(k_global_index),
WASM_REF_NULL_GC(type_index)))),
kExprEnd}; kExprEnd};
k->EmitCode(k_code, sizeof(k_code)); k->EmitCode(k_code, sizeof(k_code));
...@@ -147,13 +149,14 @@ WASM_EXEC_TEST(BasicStruct) { ...@@ -147,13 +149,14 @@ WASM_EXEC_TEST(BasicStruct) {
WASM_STRUCT_NEW(type_index, WASM_I32V(55), WASM_STRUCT_NEW(type_index, WASM_I32V(55),
WASM_I32V(66))), WASM_I32V(66))),
WASM_I32V(1)), WASM_I32V(1)),
WASM_I32_ADD( WASM_I32_ADD(WASM_I32_SHL( // false
WASM_I32_SHL( // false WASM_REF_EQ(WASM_GET_LOCAL(n_local_index),
WASM_REF_EQ(WASM_GET_LOCAL(n_local_index), WASM_REF_NULL), WASM_REF_NULL_GC(type_index)),
WASM_I32V(2)), WASM_I32V(2)),
WASM_I32_SHL(WASM_REF_EQ( // true WASM_I32_SHL(WASM_REF_EQ( // true
WASM_REF_NULL, WASM_REF_NULL), WASM_REF_NULL_GC(type_index),
WASM_I32V(3))))), WASM_REF_NULL_GC(type_index)),
WASM_I32V(3))))),
kExprEnd}; kExprEnd};
n->EmitCode(n_code, sizeof(n_code)); n->EmitCode(n_code, sizeof(n_code));
// Result: 0b1001 // Result: 0b1001
......
...@@ -348,19 +348,20 @@ TEST(MemoryGrowInvalidSize) { ...@@ -348,19 +348,20 @@ TEST(MemoryGrowInvalidSize) {
TEST(ReferenceTypeLocals) { TEST(ReferenceTypeLocals) {
{ {
WasmRunner<int32_t> r(ExecutionTier::kInterpreter); WasmRunner<int32_t> r(ExecutionTier::kInterpreter);
BUILD(r, WASM_REF_IS_NULL(WASM_REF_NULL)); BUILD(r, WASM_REF_IS_NULL(kLocalAnyRef, WASM_REF_NULL(kLocalAnyRef)));
CHECK_EQ(1, r.Call()); CHECK_EQ(1, r.Call());
} }
{ {
WasmRunner<int32_t> r(ExecutionTier::kInterpreter); WasmRunner<int32_t> r(ExecutionTier::kInterpreter);
r.AllocateLocal(kWasmAnyRef); r.AllocateLocal(kWasmAnyRef);
BUILD(r, WASM_REF_IS_NULL(WASM_GET_LOCAL(0))); BUILD(r, WASM_REF_IS_NULL(kLocalAnyRef, WASM_GET_LOCAL(0)));
CHECK_EQ(1, r.Call()); CHECK_EQ(1, r.Call());
} }
{ {
WasmRunner<int32_t> r(ExecutionTier::kInterpreter); WasmRunner<int32_t> r(ExecutionTier::kInterpreter);
r.AllocateLocal(kWasmAnyRef); r.AllocateLocal(kWasmAnyRef);
BUILD(r, WASM_REF_IS_NULL(WASM_TEE_LOCAL(0, WASM_REF_NULL))); BUILD(r, WASM_REF_IS_NULL(kLocalAnyRef,
WASM_TEE_LOCAL(0, WASM_REF_NULL(kLocalAnyRef))));
CHECK_EQ(1, r.Call()); CHECK_EQ(1, r.Call());
} }
} }
......
...@@ -432,9 +432,11 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) { ...@@ -432,9 +432,11 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_STRUCT_SET(typeidx, fieldidx, struct_obj, value) \ #define WASM_STRUCT_SET(typeidx, fieldidx, struct_obj, value) \
struct_obj, value, WASM_GC_OP(kExprStructSet), static_cast<byte>(typeidx), \ struct_obj, value, WASM_GC_OP(kExprStructSet), static_cast<byte>(typeidx), \
static_cast<byte>(fieldidx) static_cast<byte>(fieldidx)
#define WASM_REF_NULL kExprRefNull #define WASM_REF_NULL(type) kExprRefNull, static_cast<byte>(type)
#define WASM_REF_NULL_GC(type) \
kExprRefNull, kLocalOptRef, static_cast<byte>(type)
#define WASM_REF_FUNC(val) kExprRefFunc, val #define WASM_REF_FUNC(val) kExprRefFunc, val
#define WASM_REF_IS_NULL(val) val, kExprRefIsNull #define WASM_REF_IS_NULL(type, val) val, kExprRefIsNull, static_cast<byte>(type)
#define WASM_REF_AS_NON_NULL(val) val, kExprRefAsNonNull #define WASM_REF_AS_NON_NULL(val) val, kExprRefAsNonNull
#define WASM_REF_EQ(lhs, rhs) lhs, rhs, kExprRefEq #define WASM_REF_EQ(lhs, rhs) lhs, rhs, kExprRefEq
......
...@@ -13,11 +13,11 @@ load('test/mjsunit/wasm/wasm-module-builder.js'); ...@@ -13,11 +13,11 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
function create_builder(i) { function create_builder(i) {
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_i_r) builder.addFunction('main', kSig_i_r)
.addBody([ .addBody([
kExprLocalGet, 0, kExprRefIsNull, kExprLocalGet, 0, kExprRefIsNull, kWasmAnyRef, ...wasmI32Const(i),
...wasmI32Const(i), kExprI32Add
kExprI32Add]) ])
.exportFunc(); .exportFunc();
return builder; return builder;
} }
......
...@@ -36,7 +36,7 @@ let kSig_r_i = makeSig([kWasmI32], [kWasmAnyRef]); ...@@ -36,7 +36,7 @@ let kSig_r_i = makeSig([kWasmI32], [kWasmAnyRef]);
kExprLocalGet, 0, kExprLocalGet, 0,
kExprI32Eqz, kExprI32Eqz,
kExprIf, kWasmAnyRef, kExprIf, kWasmAnyRef,
kExprRefNull, kExprRefNull, kWasmAnyRef,
kExprElse, kExprElse,
kExprLocalGet, 1, kExprLocalGet, 1,
kExprEnd, kExprEnd,
......
...@@ -9,7 +9,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -9,7 +9,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function testAnyRefNull() { (function testAnyRefNull() {
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_r_v) builder.addFunction('main', kSig_r_v)
.addBody([kExprRefNull]) .addBody([kExprRefNull, kWasmAnyRef])
.exportFunc(); .exportFunc();
var wire_bytes = builder.toBuffer(); var wire_bytes = builder.toBuffer();
...@@ -24,7 +24,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -24,7 +24,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function testAnyRefIsNull() { (function testAnyRefIsNull() {
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_i_r) builder.addFunction('main', kSig_i_r)
.addBody([kExprLocalGet, 0, kExprRefIsNull]) .addBody([kExprLocalGet, 0, kExprRefIsNull, kWasmAnyRef])
.exportFunc(); .exportFunc();
var wire_bytes = builder.toBuffer(); var wire_bytes = builder.toBuffer();
......
...@@ -152,7 +152,7 @@ load('test/mjsunit/wasm/wasm-module-builder.js'); ...@@ -152,7 +152,7 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
const sig_index = builder.addType(kSig_a_a); const sig_index = builder.addType(kSig_a_a);
builder.addFunction('main', sig_index) builder.addFunction('main', sig_index)
.addBody([kExprRefNull, kExprLocalSet, 0, kExprLocalGet, 0]) .addBody([kExprRefNull, kWasmAnyFunc, kExprLocalSet, 0, kExprLocalGet, 0])
.exportFunc(); .exportFunc();
const main = builder.instantiate().exports.main; const main = builder.instantiate().exports.main;
...@@ -163,7 +163,9 @@ load('test/mjsunit/wasm/wasm-module-builder.js'); ...@@ -163,7 +163,9 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
print(arguments.callee.name); print(arguments.callee.name);
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
const sig_index = builder.addType(kSig_a_v); const sig_index = builder.addType(kSig_a_v);
builder.addFunction('main', sig_index).addBody([kExprRefNull]).exportFunc(); builder.addFunction('main', sig_index)
.addBody([kExprRefNull, kWasmAnyFunc])
.exportFunc();
const main = builder.instantiate().exports.main; const main = builder.instantiate().exports.main;
assertEquals(null, main()); assertEquals(null, main());
...@@ -174,7 +176,7 @@ load('test/mjsunit/wasm/wasm-module-builder.js'); ...@@ -174,7 +176,7 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
const sig_index = builder.addType(kSig_a_v); const sig_index = builder.addType(kSig_a_v);
builder.addFunction('main', sig_index) builder.addFunction('main', sig_index)
.addBody([kExprRefNull, kExprReturn]) .addBody([kExprRefNull, kWasmAnyFunc, kExprReturn])
.exportFunc(); .exportFunc();
const main = builder.instantiate().exports.main; const main = builder.instantiate().exports.main;
......
...@@ -560,21 +560,14 @@ function dummy_func() { ...@@ -560,21 +560,14 @@ function dummy_func() {
(function TestRefFuncGlobalInit() { (function TestRefFuncGlobalInit() {
print(arguments.callee.name); print(arguments.callee.name);
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
const g_ref = builder.addGlobal(kWasmAnyRef, true);
const g_func = builder.addGlobal(kWasmAnyFunc, true); const g_func = builder.addGlobal(kWasmAnyFunc, true);
const f_ref = builder.addFunction('get_anyref_global', kSig_r_v)
.addBody([kExprGlobalGet, g_ref.index])
.exportAs('get_anyref_global');
const f_func = builder.addFunction('get_anyfunc_global', kSig_a_v) const f_func = builder.addFunction('get_anyfunc_global', kSig_a_v)
.addBody([kExprGlobalGet, g_func.index]) .addBody([kExprGlobalGet, g_func.index])
.exportAs('get_anyfunc_global'); .exportAs('get_anyfunc_global');
builder.addDeclarativeElementSegment([f_ref.index, f_func.index]); builder.addDeclarativeElementSegment([f_func.index]);
g_ref.function_index = f_ref.index;
g_func.function_index = f_func.index; g_func.function_index = f_func.index;
const instance = builder.instantiate(); const instance = builder.instantiate();
assertEquals(
instance.exports.get_anyref_global, instance.exports.get_anyref_global());
assertEquals( assertEquals(
instance.exports.get_anyfunc_global, instance.exports.get_anyfunc_global,
instance.exports.get_anyfunc_global()); instance.exports.get_anyfunc_global());
......
...@@ -165,7 +165,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -165,7 +165,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
print(arguments.callee.name); print(arguments.callee.name);
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_r_v) builder.addFunction('main', kSig_r_v)
.addBody([kExprRefNull]) .addBody([kExprRefNull, kWasmAnyRef])
.exportFunc(); .exportFunc();
const instance = builder.instantiate(); const instance = builder.instantiate();
...@@ -177,7 +177,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -177,7 +177,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
print(arguments.callee.name); print(arguments.callee.name);
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_i_r) builder.addFunction('main', kSig_i_r)
.addBody([kExprLocalGet, 0, kExprRefIsNull]) .addBody([kExprLocalGet, 0, kExprRefIsNull, kWasmAnyRef])
.exportFunc(); .exportFunc();
const instance = builder.instantiate(); const instance = builder.instantiate();
...@@ -196,7 +196,10 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -196,7 +196,10 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_i_v) builder.addFunction('main', kSig_i_v)
.addBody([kExprRefNull, kExprRefIsNull]) .addBody([
kExprRefNull, kWasmAnyRef, // --
kExprRefIsNull, kWasmAnyRef // --
])
.exportFunc(); .exportFunc();
const instance = builder.instantiate(); const instance = builder.instantiate();
...@@ -222,7 +225,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -222,7 +225,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
const sig_index = builder.addType(kSig_r_v); const sig_index = builder.addType(kSig_r_v);
builder.addFunction('main', sig_index) builder.addFunction('main', sig_index)
.addBody([kExprRefNull]) .addBody([kExprRefNull, kWasmAnyRef])
.exportFunc(); .exportFunc();
const main = builder.instantiate().exports.main; const main = builder.instantiate().exports.main;
...@@ -234,7 +237,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -234,7 +237,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
const sig_index = builder.addType(kSig_r_v); const sig_index = builder.addType(kSig_r_v);
builder.addFunction('main', sig_index) builder.addFunction('main', sig_index)
.addBody([kExprRefNull, kExprReturn]) .addBody([kExprRefNull, kWasmAnyRef, kExprReturn])
.exportFunc(); .exportFunc();
const main = builder.instantiate().exports.main; const main = builder.instantiate().exports.main;
......
...@@ -14,7 +14,7 @@ load("test/mjsunit/wasm/exceptions-utils.js"); ...@@ -14,7 +14,7 @@ load("test/mjsunit/wasm/exceptions-utils.js");
let except = builder.addException(kSig_v_r); let except = builder.addException(kSig_v_r);
builder.addFunction("throw_null", kSig_v_v) builder.addFunction("throw_null", kSig_v_v)
.addBody([ .addBody([
kExprRefNull, kExprRefNull, kWasmAnyRef,
kExprThrow, except, kExprThrow, except,
]).exportFunc(); ]).exportFunc();
let instance = builder.instantiate(); let instance = builder.instantiate();
...@@ -33,7 +33,7 @@ load("test/mjsunit/wasm/exceptions-utils.js"); ...@@ -33,7 +33,7 @@ load("test/mjsunit/wasm/exceptions-utils.js");
kExprLocalGet, 0, kExprLocalGet, 0,
kExprI32Eqz, kExprI32Eqz,
kExprIf, kWasmAnyRef, kExprIf, kWasmAnyRef,
kExprRefNull, kExprRefNull, kWasmAnyRef,
kExprThrow, except, kExprThrow, except,
kExprElse, kExprElse,
kExprI32Const, 42, kExprI32Const, 42,
...@@ -43,7 +43,7 @@ load("test/mjsunit/wasm/exceptions-utils.js"); ...@@ -43,7 +43,7 @@ load("test/mjsunit/wasm/exceptions-utils.js");
kExprBrOnExn, 0, except, kExprBrOnExn, 0, except,
kExprRethrow, kExprRethrow,
kExprEnd, kExprEnd,
kExprRefIsNull, kExprRefIsNull, kWasmAnyRef,
kExprIf, kWasmI32, kExprIf, kWasmI32,
kExprI32Const, 23, kExprI32Const, 23,
kExprElse, kExprElse,
...@@ -191,7 +191,7 @@ load("test/mjsunit/wasm/exceptions-utils.js"); ...@@ -191,7 +191,7 @@ load("test/mjsunit/wasm/exceptions-utils.js");
let except = builder.addException(kSig_v_r); let except = builder.addException(kSig_v_r);
builder.addFunction('br_on_exn_nullref', kSig_v_v) builder.addFunction('br_on_exn_nullref', kSig_v_v)
.addBody([ .addBody([
kExprRefNull, kExprRefNull, kWasmExnRef,
kExprBrOnExn, 0, except, kExprBrOnExn, 0, except,
kExprDrop kExprDrop
]).exportFunc(); ]).exportFunc();
...@@ -240,7 +240,7 @@ load("test/mjsunit/wasm/exceptions-utils.js"); ...@@ -240,7 +240,7 @@ load("test/mjsunit/wasm/exceptions-utils.js");
let except = builder.addException(kSig_v_r); let except = builder.addException(kSig_v_r);
builder.addFunction('rethrow_nullref', kSig_v_v) builder.addFunction('rethrow_nullref', kSig_v_v)
.addBody([ .addBody([
kExprRefNull, kExprRefNull, kWasmExnRef,
kExprRethrow kExprRethrow
]).exportFunc(); ]).exportFunc();
let instance = builder.instantiate(); let instance = builder.instantiate();
......
This diff is collapsed.
...@@ -1126,18 +1126,23 @@ class WasmModuleBuilder { ...@@ -1126,18 +1126,23 @@ class WasmModuleBuilder {
data_view.setFloat64(0, global.init, true); data_view.setFloat64(0, global.init, true);
section.emit_bytes(byte_view); section.emit_bytes(byte_view);
break; break;
case kWasmAnyFunc:
case kWasmAnyRef: case kWasmAnyRef:
case kWasmNullRef: section.emit_u8(kExprRefNull);
section.emit_u8(kWasmAnyRef);
assertEquals(global.function_index, undefined);
break;
case kWasmAnyFunc:
if (global.function_index !== undefined) { if (global.function_index !== undefined) {
section.emit_u8(kExprRefFunc); section.emit_u8(kExprRefFunc);
section.emit_u32v(global.function_index); section.emit_u32v(global.function_index);
} else { } else {
section.emit_u8(kExprRefNull); section.emit_u8(kExprRefNull);
section.emit_u8(kWasmAnyFunc);
} }
break; break;
case kWasmExnRef: case kWasmExnRef:
section.emit_u8(kExprRefNull); section.emit_u8(kExprRefNull);
section.emit_u8(kWasmExnRef);
break; break;
} }
} else { } else {
...@@ -1227,6 +1232,7 @@ class WasmModuleBuilder { ...@@ -1227,6 +1232,7 @@ class WasmModuleBuilder {
for (let index of init.array) { for (let index of init.array) {
if (index === null) { if (index === null) {
section.emit_u8(kExprRefNull); section.emit_u8(kExprRefNull);
section.emit_u8(kWasmAnyFunc);
section.emit_u8(kExprEnd); section.emit_u8(kExprEnd);
} else { } else {
section.emit_u8(kExprRefFunc); section.emit_u8(kExprRefFunc);
......
...@@ -306,8 +306,7 @@ TEST_F(FunctionBodyDecoderTest, Int32Const1) { ...@@ -306,8 +306,7 @@ TEST_F(FunctionBodyDecoderTest, Int32Const1) {
TEST_F(FunctionBodyDecoderTest, RefNull) { TEST_F(FunctionBodyDecoderTest, RefNull) {
WASM_FEATURE_SCOPE(anyref); WASM_FEATURE_SCOPE(anyref);
ExpectValidates(sigs.r_v(), {kExprRefNull}); ExpectValidates(sigs.r_v(), {kExprRefNull, kLocalAnyRef});
ExpectValidates(sigs.n_v(), {kExprRefNull});
} }
TEST_F(FunctionBodyDecoderTest, RefFunc) { TEST_F(FunctionBodyDecoderTest, RefFunc) {
...@@ -2667,9 +2666,11 @@ TEST_F(FunctionBodyDecoderTest, SelectWithType) { ...@@ -2667,9 +2666,11 @@ TEST_F(FunctionBodyDecoderTest, SelectWithType) {
ExpectValidates(sigs.l_l(), ExpectValidates(sigs.l_l(),
{WASM_SELECT_L(WASM_I64V_1(0), WASM_I64V_1(0), WASM_ZERO)}); {WASM_SELECT_L(WASM_I64V_1(0), WASM_I64V_1(0), WASM_ZERO)});
ExpectValidates(sigs.r_r(), ExpectValidates(sigs.r_r(),
{WASM_SELECT_R(WASM_REF_NULL, WASM_REF_NULL, WASM_ZERO)}); {WASM_SELECT_R(WASM_REF_NULL(kLocalAnyRef),
WASM_REF_NULL(kLocalAnyRef), WASM_ZERO)});
ExpectValidates(sigs.a_a(), ExpectValidates(sigs.a_a(),
{WASM_SELECT_A(WASM_REF_NULL, WASM_REF_NULL, WASM_ZERO)}); {WASM_SELECT_A(WASM_REF_NULL(kLocalFuncRef),
WASM_REF_NULL(kLocalFuncRef), WASM_ZERO)});
} }
TEST_F(FunctionBodyDecoderTest, SelectWithType_fail) { TEST_F(FunctionBodyDecoderTest, SelectWithType_fail) {
...@@ -3209,17 +3210,16 @@ TEST_F(FunctionBodyDecoderTest, TableGrow) { ...@@ -3209,17 +3210,16 @@ TEST_F(FunctionBodyDecoderTest, TableGrow) {
byte tab_ref = builder.AddTable(kWasmAnyRef, 10, true, 20); byte tab_ref = builder.AddTable(kWasmAnyRef, 10, true, 20);
byte tab_null = builder.AddTable(kWasmNullRef, 10, true, 20); byte tab_null = builder.AddTable(kWasmNullRef, 10, true, 20);
ExpectFailure(sigs.i_a(), ExpectFailure(
{WASM_TABLE_GROW(tab_func, WASM_REF_NULL, WASM_ONE)}); sigs.i_a(),
ExpectFailure(sigs.i_n(), {WASM_TABLE_GROW(tab_func, WASM_REF_NULL(kLocalFuncRef), WASM_ONE)});
{WASM_TABLE_GROW(tab_null, WASM_REF_NULL, WASM_ONE)});
WASM_FEATURE_SCOPE(anyref); WASM_FEATURE_SCOPE(anyref);
ExpectValidates(sigs.i_a(), ExpectValidates(
{WASM_TABLE_GROW(tab_func, WASM_REF_NULL, WASM_ONE)}); sigs.i_a(),
ExpectValidates(sigs.i_r(), {WASM_TABLE_GROW(tab_func, WASM_REF_NULL(kLocalFuncRef), WASM_ONE)});
{WASM_TABLE_GROW(tab_ref, WASM_REF_NULL, WASM_ONE)}); ExpectValidates(
ExpectValidates(sigs.i_n(), sigs.i_r(),
{WASM_TABLE_GROW(tab_null, WASM_REF_NULL, WASM_ONE)}); {WASM_TABLE_GROW(tab_ref, WASM_REF_NULL(kLocalAnyRef), WASM_ONE)});
// FuncRef table cannot be initialized with an anyref value. // FuncRef table cannot be initialized with an anyref value.
ExpectFailure(sigs.i_r(), ExpectFailure(sigs.i_r(),
{WASM_TABLE_GROW(tab_func, WASM_GET_LOCAL(0), WASM_ONE)}); {WASM_TABLE_GROW(tab_func, WASM_GET_LOCAL(0), WASM_ONE)});
...@@ -3237,8 +3237,9 @@ TEST_F(FunctionBodyDecoderTest, TableGrow) { ...@@ -3237,8 +3237,9 @@ TEST_F(FunctionBodyDecoderTest, TableGrow) {
ExpectFailure(sigs.i_r(), ExpectFailure(sigs.i_r(),
{WASM_TABLE_GROW(tab_null, WASM_GET_LOCAL(0), WASM_ONE)}); {WASM_TABLE_GROW(tab_null, WASM_GET_LOCAL(0), WASM_ONE)});
// Check that the table index gets verified. // Check that the table index gets verified.
ExpectFailure(sigs.i_r(), ExpectFailure(
{WASM_TABLE_GROW(tab_ref + 2, WASM_REF_NULL, WASM_ONE)}); sigs.i_r(),
{WASM_TABLE_GROW(tab_ref + 2, WASM_REF_NULL(kLocalAnyRef), WASM_ONE)});
} }
TEST_F(FunctionBodyDecoderTest, TableSize) { TEST_F(FunctionBodyDecoderTest, TableSize) {
...@@ -3253,19 +3254,17 @@ TEST_F(FunctionBodyDecoderTest, TableSize) { ...@@ -3253,19 +3254,17 @@ TEST_F(FunctionBodyDecoderTest, TableSize) {
TEST_F(FunctionBodyDecoderTest, TableFill) { TEST_F(FunctionBodyDecoderTest, TableFill) {
byte tab_func = builder.AddTable(kWasmFuncRef, 10, true, 20); byte tab_func = builder.AddTable(kWasmFuncRef, 10, true, 20);
byte tab_ref = builder.AddTable(kWasmAnyRef, 10, true, 20); byte tab_ref = builder.AddTable(kWasmAnyRef, 10, true, 20);
byte tab_null = builder.AddTable(kWasmNullRef, 10, true, 20);
ExpectFailure(sigs.v_a(), ExpectFailure(sigs.v_a(),
{WASM_TABLE_FILL(tab_func, WASM_ONE, WASM_REF_NULL, WASM_ONE)}); {WASM_TABLE_FILL(tab_func, WASM_ONE,
ExpectFailure(sigs.v_n(), WASM_REF_NULL(kLocalFuncRef), WASM_ONE)});
{WASM_TABLE_FILL(tab_null, WASM_ONE, WASM_REF_NULL, WASM_ONE)});
WASM_FEATURE_SCOPE(anyref); WASM_FEATURE_SCOPE(anyref);
ExpectValidates(sigs.v_a(), {WASM_TABLE_FILL(tab_func, WASM_ONE, ExpectValidates(sigs.v_a(),
WASM_REF_NULL, WASM_ONE)}); {WASM_TABLE_FILL(tab_func, WASM_ONE,
ExpectValidates(sigs.v_r(), {WASM_TABLE_FILL(tab_ref, WASM_ONE, WASM_REF_NULL, WASM_REF_NULL(kLocalFuncRef), WASM_ONE)});
WASM_ONE)}); ExpectValidates(sigs.v_r(),
ExpectValidates(sigs.v_n(), {WASM_TABLE_FILL(tab_null, WASM_ONE, {WASM_TABLE_FILL(tab_ref, WASM_ONE,
WASM_REF_NULL, WASM_ONE)}); WASM_REF_NULL(kLocalAnyRef), WASM_ONE)});
// FuncRef table cannot be initialized with an anyref value. // FuncRef table cannot be initialized with an anyref value.
ExpectFailure(sigs.v_r(), {WASM_TABLE_FILL(tab_func, WASM_ONE, ExpectFailure(sigs.v_r(), {WASM_TABLE_FILL(tab_func, WASM_ONE,
WASM_GET_LOCAL(0), WASM_ONE)}); WASM_GET_LOCAL(0), WASM_ONE)});
...@@ -3278,17 +3277,20 @@ TEST_F(FunctionBodyDecoderTest, TableFill) { ...@@ -3278,17 +3277,20 @@ TEST_F(FunctionBodyDecoderTest, TableFill) {
ExpectValidates(sigs.v_n(), {WASM_TABLE_FILL(tab_ref, WASM_ONE, ExpectValidates(sigs.v_n(), {WASM_TABLE_FILL(tab_ref, WASM_ONE,
WASM_GET_LOCAL(0), WASM_ONE)}); WASM_GET_LOCAL(0), WASM_ONE)});
// Check that the table index gets verified. // Check that the table index gets verified.
ExpectFailure(sigs.v_r(), {WASM_TABLE_FILL(tab_ref + 2, WASM_ONE, ExpectFailure(sigs.v_r(),
WASM_REF_NULL, WASM_ONE)}); {WASM_TABLE_FILL(tab_ref + 2, WASM_ONE,
WASM_REF_NULL(kLocalAnyRef), WASM_ONE)});
} }
TEST_F(FunctionBodyDecoderTest, TableOpsWithoutTable) { TEST_F(FunctionBodyDecoderTest, TableOpsWithoutTable) {
{ {
WASM_FEATURE_SCOPE(anyref); WASM_FEATURE_SCOPE(anyref);
ExpectFailure(sigs.i_v(), {WASM_TABLE_GROW(0, WASM_REF_NULL, WASM_ONE)}); ExpectFailure(sigs.i_v(),
{WASM_TABLE_GROW(0, WASM_REF_NULL(kLocalAnyRef), WASM_ONE)});
ExpectFailure(sigs.i_v(), {WASM_TABLE_SIZE(0)}); ExpectFailure(sigs.i_v(), {WASM_TABLE_SIZE(0)});
ExpectFailure(sigs.i_r(), ExpectFailure(
{WASM_TABLE_FILL(0, WASM_ONE, WASM_REF_NULL, WASM_ONE)}); sigs.i_r(),
{WASM_TABLE_FILL(0, WASM_ONE, WASM_REF_NULL(kLocalAnyRef), WASM_ONE)});
} }
{ {
WASM_FEATURE_SCOPE(bulk_memory); WASM_FEATURE_SCOPE(bulk_memory);
...@@ -3519,7 +3521,7 @@ TEST_F(WasmOpcodeLengthTest, Statements) { ...@@ -3519,7 +3521,7 @@ TEST_F(WasmOpcodeLengthTest, Statements) {
TEST_F(WasmOpcodeLengthTest, MiscExpressions) { TEST_F(WasmOpcodeLengthTest, MiscExpressions) {
ExpectLength(5, kExprF32Const); ExpectLength(5, kExprF32Const);
ExpectLength(9, kExprF64Const); ExpectLength(9, kExprF64Const);
ExpectLength(1, kExprRefNull); ExpectLength(2, kExprRefNull);
ExpectLength(2, kExprLocalGet); ExpectLength(2, kExprLocalGet);
ExpectLength(2, kExprLocalSet); ExpectLength(2, kExprLocalSet);
ExpectLength(2, kExprGlobalGet); ExpectLength(2, kExprGlobalGet);
......
...@@ -29,11 +29,12 @@ namespace module_decoder_unittest { ...@@ -29,11 +29,12 @@ namespace module_decoder_unittest {
#define WASM_INIT_EXPR_F32(val) WASM_F32(val), kExprEnd #define WASM_INIT_EXPR_F32(val) WASM_F32(val), kExprEnd
#define WASM_INIT_EXPR_I64(val) WASM_I64(val), kExprEnd #define WASM_INIT_EXPR_I64(val) WASM_I64(val), kExprEnd
#define WASM_INIT_EXPR_F64(val) WASM_F64(val), kExprEnd #define WASM_INIT_EXPR_F64(val) WASM_F64(val), kExprEnd
#define WASM_INIT_EXPR_REF_NULL WASM_REF_NULL, kExprEnd #define WASM_INIT_EXPR_ANY_REF_NULL WASM_REF_NULL(kLocalAnyRef), kExprEnd
#define WASM_INIT_EXPR_FUNC_REF_NULL WASM_REF_NULL(kLocalFuncRef), kExprEnd
#define WASM_INIT_EXPR_REF_FUNC(val) WASM_REF_FUNC(val), kExprEnd #define WASM_INIT_EXPR_REF_FUNC(val) WASM_REF_FUNC(val), kExprEnd
#define WASM_INIT_EXPR_GLOBAL(index) WASM_GET_GLOBAL(index), kExprEnd #define WASM_INIT_EXPR_GLOBAL(index) WASM_GET_GLOBAL(index), kExprEnd
#define REF_NULL_ELEMENT kExprRefNull, kExprEnd #define REF_NULL_ELEMENT kExprRefNull, kLocalFuncRef, kExprEnd
#define REF_FUNC_ELEMENT(v) kExprRefFunc, U32V_1(v), kExprEnd #define REF_FUNC_ELEMENT(v) kExprRefFunc, U32V_1(v), kExprEnd
#define EMPTY_BODY 0 #define EMPTY_BODY 0
...@@ -269,8 +270,8 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobal) { ...@@ -269,8 +270,8 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobal) {
ENTRY_COUNT(2), // -- ENTRY_COUNT(2), // --
kLocalAnyRef, // local type kLocalAnyRef, // local type
0, // immutable 0, // immutable
WASM_INIT_EXPR_REF_NULL, // init WASM_INIT_EXPR_ANY_REF_NULL, // init
kLocalAnyRef, // local type kLocalFuncRef, // local type
0, // immutable 0, // immutable
WASM_INIT_EXPR_REF_FUNC(1)), // init WASM_INIT_EXPR_REF_FUNC(1)), // init
SECTION(Element, // section name SECTION(Element, // section name
...@@ -299,7 +300,7 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobal) { ...@@ -299,7 +300,7 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobal) {
EXPECT_EQ(WasmInitExpr::kRefNullConst, global->init.kind); EXPECT_EQ(WasmInitExpr::kRefNullConst, global->init.kind);
global = &result.value()->globals[1]; global = &result.value()->globals[1];
EXPECT_EQ(kWasmAnyRef, global->type); EXPECT_EQ(kWasmFuncRef, global->type);
EXPECT_FALSE(global->mutability); EXPECT_FALSE(global->mutability);
EXPECT_EQ(WasmInitExpr::kRefFuncConst, global->init.kind); EXPECT_EQ(WasmInitExpr::kRefFuncConst, global->init.kind);
EXPECT_EQ(uint32_t{1}, global->init.val.function_index); EXPECT_EQ(uint32_t{1}, global->init.val.function_index);
...@@ -314,24 +315,24 @@ TEST_F(WasmModuleVerifyTest, FuncRefGlobal) { ...@@ -314,24 +315,24 @@ TEST_F(WasmModuleVerifyTest, FuncRefGlobal) {
SIGNATURES_SECTION_VOID_VOID, SIGNATURES_SECTION_VOID_VOID,
// funcs --------------------------------------------------------------- // funcs ---------------------------------------------------------------
TWO_EMPTY_FUNCTIONS(SIG_INDEX(0)), TWO_EMPTY_FUNCTIONS(SIG_INDEX(0)),
SECTION(Global, // -- SECTION(Global, // --
ENTRY_COUNT(2), // -- ENTRY_COUNT(2), // --
kLocalFuncRef, // local type kLocalFuncRef, // local type
0, // immutable 0, // immutable
WASM_INIT_EXPR_REF_NULL, // init WASM_INIT_EXPR_FUNC_REF_NULL, // init
kLocalFuncRef, // local type kLocalFuncRef, // local type
0, // immutable 0, // immutable
WASM_INIT_EXPR_REF_FUNC(1)), // init WASM_INIT_EXPR_REF_FUNC(1)), // init
SECTION(Element, // section name SECTION(Element, // section name
ENTRY_COUNT(2), // entry count ENTRY_COUNT(2), // entry count
DECLARATIVE, // flags 0 DECLARATIVE, // flags 0
kExternalFunction, // type kExternalFunction, // type
ENTRY_COUNT(1), // func entry count ENTRY_COUNT(1), // func entry count
FUNC_INDEX(0), // func index FUNC_INDEX(0), // func index
DECLARATIVE_WITH_ELEMENTS, // flags 1 DECLARATIVE_WITH_ELEMENTS, // flags 1
kLocalFuncRef, // local type kLocalFuncRef, // local type
ENTRY_COUNT(1), // func ref count ENTRY_COUNT(1), // func ref count
REF_FUNC_ELEMENT(1)), // func ref REF_FUNC_ELEMENT(1)), // func ref
TWO_EMPTY_BODIES}; TWO_EMPTY_BODIES};
{ {
// Should decode to two globals. // Should decode to two globals.
...@@ -354,34 +355,6 @@ TEST_F(WasmModuleVerifyTest, FuncRefGlobal) { ...@@ -354,34 +355,6 @@ TEST_F(WasmModuleVerifyTest, FuncRefGlobal) {
} }
} }
TEST_F(WasmModuleVerifyTest, NullRefGlobal) {
WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {
// sig#0 ---------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
// funcs ---------------------------------------------------------------
TWO_EMPTY_FUNCTIONS(SIG_INDEX(0)),
SECTION(Global, // --
ENTRY_COUNT(1), // --
kLocalNullRef, // local type
0, // immutable
WASM_INIT_EXPR_REF_NULL), // init
TWO_EMPTY_BODIES};
{
// Should decode to one global.
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(1u, result.value()->globals.size());
EXPECT_EQ(2u, result.value()->functions.size());
EXPECT_EQ(0u, result.value()->data_segments.size());
const WasmGlobal* global = &result.value()->globals[0];
EXPECT_EQ(kWasmNullRef, global->type);
EXPECT_FALSE(global->mutability);
EXPECT_EQ(WasmInitExpr::kRefNullConst, global->init.kind);
}
}
TEST_F(WasmModuleVerifyTest, InvalidFuncRefGlobal) { TEST_F(WasmModuleVerifyTest, InvalidFuncRefGlobal) {
WASM_FEATURE_SCOPE(anyref); WASM_FEATURE_SCOPE(anyref);
static const byte data[] = { static const byte data[] = {
...@@ -398,27 +371,6 @@ TEST_F(WasmModuleVerifyTest, InvalidFuncRefGlobal) { ...@@ -398,27 +371,6 @@ TEST_F(WasmModuleVerifyTest, InvalidFuncRefGlobal) {
EXPECT_FAILURE(data); EXPECT_FAILURE(data);
} }
TEST_F(WasmModuleVerifyTest, InvalidNullRefGlobal) {
WASM_FEATURE_SCOPE(anyref);
// Initialize nullref from funcref
static const byte data[] = {
// sig#0 ---------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
// funcs ---------------------------------------------------------------
TWO_EMPTY_FUNCTIONS(SIG_INDEX(0)),
SECTION(Global, // --
ENTRY_COUNT(1), // --
kLocalNullRef, // local type
0, // immutable
WASM_INIT_EXPR_REF_FUNC(1)), // init
TWO_EMPTY_BODIES};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_NOT_OK(
result,
"type error in global initialization, expected nullref, got funcref");
}
TEST_F(WasmModuleVerifyTest, AnyRefGlobalWithGlobalInit) { TEST_F(WasmModuleVerifyTest, AnyRefGlobalWithGlobalInit) {
WASM_FEATURE_SCOPE(anyref); WASM_FEATURE_SCOPE(anyref);
static const byte data[] = { static const byte data[] = {
...@@ -2337,7 +2289,7 @@ TEST_F(WasmInitExprDecodeTest, InitExpr_f64) { ...@@ -2337,7 +2289,7 @@ TEST_F(WasmInitExprDecodeTest, InitExpr_f64) {
TEST_F(WasmInitExprDecodeTest, InitExpr_AnyRef) { TEST_F(WasmInitExprDecodeTest, InitExpr_AnyRef) {
WASM_FEATURE_SCOPE(anyref); WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {kExprRefNull, kExprEnd}; static const byte data[] = {kExprRefNull, kLocalAnyRef, kExprEnd};
WasmInitExpr expr = DecodeInitExpr(data, data + sizeof(data)); WasmInitExpr expr = DecodeInitExpr(data, data + sizeof(data));
EXPECT_EQ(WasmInitExpr::kRefNullConst, expr.kind); EXPECT_EQ(WasmInitExpr::kRefNullConst, expr.kind);
} }
...@@ -2623,7 +2575,7 @@ TEST_F(WasmModuleVerifyTest, DeclarativeElementSegmentMissingForGlobal) { ...@@ -2623,7 +2575,7 @@ TEST_F(WasmModuleVerifyTest, DeclarativeElementSegmentMissingForGlobal) {
// global definitions ---------------------------------------------------- // global definitions ----------------------------------------------------
SECTION(Global, // section name SECTION(Global, // section name
ENTRY_COUNT(1), // entry count ENTRY_COUNT(1), // entry count
kLocalAnyRef, // local type kLocalFuncRef, // local type
0, // immutable 0, // immutable
WASM_INIT_EXPR_REF_FUNC(0)), // init WASM_INIT_EXPR_REF_FUNC(0)), // init
// code ------------------------------------------------------------------ // code ------------------------------------------------------------------
...@@ -2734,7 +2686,8 @@ TEST_F(WasmModuleVerifyTest, DataCountSegmentCount_omitted) { ...@@ -2734,7 +2686,8 @@ TEST_F(WasmModuleVerifyTest, DataCountSegmentCount_omitted) {
#undef WASM_INIT_EXPR_F32 #undef WASM_INIT_EXPR_F32
#undef WASM_INIT_EXPR_I64 #undef WASM_INIT_EXPR_I64
#undef WASM_INIT_EXPR_F64 #undef WASM_INIT_EXPR_F64
#undef WASM_INIT_EXPR_REF_NULL #undef WASM_INIT_EXPR_ANY_REF_NULL
#undef WASM_INIT_EXPR_FUNC_REF_NULL
#undef WASM_INIT_EXPR_REF_FUNC #undef WASM_INIT_EXPR_REF_FUNC
#undef WASM_INIT_EXPR_GLOBAL #undef WASM_INIT_EXPR_GLOBAL
#undef REF_NULL_ELEMENT #undef REF_NULL_ELEMENT
......
...@@ -34,7 +34,7 @@ TEST_F(WasmCapiTest, HostRef) { ...@@ -34,7 +34,7 @@ TEST_F(WasmCapiTest, HostRef) {
FunctionSig r_i_sig(1, 1, ri_reps); FunctionSig r_i_sig(1, 1, ri_reps);
uint32_t func_index = builder()->AddImport(CStrVector("f"), &r_r_sig); uint32_t func_index = builder()->AddImport(CStrVector("f"), &r_r_sig);
const bool kMutable = true; const bool kMutable = true;
const WasmInitExpr global_init(WasmInitExpr::kRefNullConst, 0); const WasmInitExpr global_init(WasmInitExpr::kRefNullConst);
uint32_t global_index = builder()->AddExportedGlobal( uint32_t global_index = builder()->AddExportedGlobal(
kWasmAnyRef, kMutable, global_init, CStrVector("global")); kWasmAnyRef, kMutable, global_init, CStrVector("global"));
uint32_t table_index = builder()->AddTable(kWasmAnyRef, 10); uint32_t table_index = builder()->AddTable(kWasmAnyRef, 10);
......
...@@ -21,23 +21,10 @@ ...@@ -21,23 +21,10 @@
'proposals/js-types/linking': [FAIL], 'proposals/js-types/linking': [FAIL],
# TODO(v8:10556): Remove sub-typing in the reference-types implementation # TODO(v8:10556): Remove sub-typing in the reference-types implementation
'proposals/bulk-memory-operations/binary': [FAIL],
'proposals/bulk-memory-operations/bulk': [FAIL],
'proposals/bulk-memory-operations/elem': [FAIL],
'proposals/bulk-memory-operations/imports': [FAIL], 'proposals/bulk-memory-operations/imports': [FAIL],
'proposals/reference-types/binary': [FAIL],
'proposals/reference-types/bulk': [FAIL],
'proposals/reference-types/elem': [FAIL],
'proposals/reference-types/global': [FAIL],
'proposals/reference-types/linking': [FAIL], 'proposals/reference-types/linking': [FAIL],
'proposals/reference-types/ref_func': [FAIL], 'proposals/reference-types/ref_func': [FAIL],
'proposals/reference-types/ref_is_null': [FAIL],
'proposals/reference-types/ref_null': [FAIL],
'proposals/reference-types/table_get': [FAIL],
'proposals/reference-types/table_grow': [FAIL],
'proposals/reference-types/table_set': [FAIL],
'proposals/reference-types/table_size': [FAIL],
'proposals/reference-types/unreached-invalid': [FAIL], 'proposals/reference-types/unreached-invalid': [FAIL],
# TODO(wasm): This test declares a table larger than allowed by the spec. # TODO(wasm): This test declares a table larger than allowed by the spec.
......
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