[wasm][reference-types] Enable ref.null in Wasm code
Add decoding of ref.null as a valid argument for references in TurboFan, LiftOff and the interpreter. R=ahaas@chromium.org R=jkummerow@chromium.org Bug: chromium:10063 Change-Id: I1e2d9c76f616dacb3aa06f8b535543bdcdcf0783 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1991485 Commit-Queue: Emanuel Ziegler <ecmziegler@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#65788}
This commit is contained in:
parent
e659917aa3
commit
ea69636247
@ -2098,6 +2098,7 @@ Node* WasmGraphBuilder::Throw(uint32_t exception_index,
|
||||
break;
|
||||
case wasm::kWasmAnyRef:
|
||||
case wasm::kWasmFuncRef:
|
||||
case wasm::kWasmNullRef:
|
||||
case wasm::kWasmExnRef:
|
||||
STORE_FIXED_ARRAY_SLOT_ANY(values_array, index, value);
|
||||
++index;
|
||||
@ -2238,6 +2239,7 @@ Node* WasmGraphBuilder::GetExceptionValues(Node* except_obj,
|
||||
break;
|
||||
case wasm::kWasmAnyRef:
|
||||
case wasm::kWasmFuncRef:
|
||||
case wasm::kWasmNullRef:
|
||||
case wasm::kWasmExnRef:
|
||||
value = LOAD_FIXED_ARRAY_SLOT_ANY(values_array, index);
|
||||
++index;
|
||||
@ -3427,6 +3429,7 @@ void WasmGraphBuilder::GetTableBaseAndOffset(uint32_t table_index,
|
||||
Node* WasmGraphBuilder::TableGet(uint32_t table_index, Node* index,
|
||||
wasm::WasmCodePosition position) {
|
||||
if (env_->module->tables[table_index].type == wasm::kWasmAnyRef ||
|
||||
env_->module->tables[table_index].type == wasm::kWasmNullRef ||
|
||||
env_->module->tables[table_index].type == wasm::kWasmExnRef) {
|
||||
Node* base = nullptr;
|
||||
Node* offset = nullptr;
|
||||
@ -3456,6 +3459,7 @@ Node* WasmGraphBuilder::TableGet(uint32_t table_index, Node* index,
|
||||
Node* WasmGraphBuilder::TableSet(uint32_t table_index, Node* index, Node* val,
|
||||
wasm::WasmCodePosition position) {
|
||||
if (env_->module->tables[table_index].type == wasm::kWasmAnyRef ||
|
||||
env_->module->tables[table_index].type == wasm::kWasmNullRef ||
|
||||
env_->module->tables[table_index].type == wasm::kWasmExnRef) {
|
||||
Node* base = nullptr;
|
||||
Node* offset = nullptr;
|
||||
@ -5365,6 +5369,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
return BuildChangeFloat64ToTagged(node);
|
||||
case wasm::kWasmAnyRef:
|
||||
case wasm::kWasmFuncRef:
|
||||
case wasm::kWasmNullRef:
|
||||
case wasm::kWasmExnRef:
|
||||
return node;
|
||||
default:
|
||||
@ -5455,9 +5460,27 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
switch (type) {
|
||||
case wasm::kWasmAnyRef:
|
||||
case wasm::kWasmExnRef:
|
||||
// The parameter is of type anyref or exnref, we take it as is.
|
||||
return input;
|
||||
|
||||
case wasm::kWasmNullRef: {
|
||||
Node* check = graph()->NewNode(mcgraph()->machine()->WordEqual(), input,
|
||||
RefNull());
|
||||
|
||||
Diamond null_check(graph(), mcgraph()->common(), check,
|
||||
BranchHint::kTrue);
|
||||
null_check.Chain(Control());
|
||||
|
||||
Node* effect = Effect();
|
||||
BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, js_context,
|
||||
nullptr, 0, &effect, null_check.if_false);
|
||||
|
||||
SetEffect(null_check.EffectPhi(Effect(), effect));
|
||||
|
||||
SetControl(null_check.merge);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
case wasm::kWasmFuncRef: {
|
||||
Node* check =
|
||||
BuildChangeSmiToInt32(SetEffect(BuildCallToRuntimeWithContext(
|
||||
|
@ -236,11 +236,13 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
|
||||
#undef CASE_ARG_TYPE
|
||||
case wasm::kWasmAnyRef:
|
||||
case wasm::kWasmFuncRef:
|
||||
case wasm::kWasmNullRef:
|
||||
case wasm::kWasmExnRef: {
|
||||
DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetParam(i)),
|
||||
kSystemPointerSize);
|
||||
Handle<Object> ref(base::ReadUnalignedValue<Object>(arg_buf_ptr),
|
||||
isolate);
|
||||
DCHECK_IMPLIES(sig->GetParam(i) == wasm::kWasmNullRef, ref->IsNull());
|
||||
wasm_args[i] = wasm::WasmValue(ref);
|
||||
arg_buf_ptr += kSystemPointerSize;
|
||||
break;
|
||||
@ -287,9 +289,12 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
|
||||
#undef CASE_RET_TYPE
|
||||
case wasm::kWasmAnyRef:
|
||||
case wasm::kWasmFuncRef:
|
||||
case wasm::kWasmNullRef:
|
||||
case wasm::kWasmExnRef: {
|
||||
DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetReturn(i)),
|
||||
kSystemPointerSize);
|
||||
DCHECK_IMPLIES(sig->GetReturn(i) == wasm::kWasmNullRef,
|
||||
wasm_rets[i].to_anyref()->IsNull());
|
||||
base::WriteUnalignedValue<Object>(arg_buf_ptr,
|
||||
*wasm_rets[i].to_anyref());
|
||||
arg_buf_ptr += kSystemPointerSize;
|
||||
|
@ -1412,6 +1412,7 @@ void PushArgs(i::wasm::FunctionSig* sig, const Val args[],
|
||||
break;
|
||||
case i::wasm::kWasmAnyRef:
|
||||
case i::wasm::kWasmFuncRef:
|
||||
case i::wasm::kWasmNullRef:
|
||||
packer->Push(WasmRefToV8(store->i_isolate(), args[i].ref())->ptr());
|
||||
break;
|
||||
case i::wasm::kWasmExnRef:
|
||||
@ -1443,9 +1444,11 @@ void PopArgs(i::wasm::FunctionSig* sig, Val results[],
|
||||
results[i] = Val(packer->Pop<double>());
|
||||
break;
|
||||
case i::wasm::kWasmAnyRef:
|
||||
case i::wasm::kWasmFuncRef: {
|
||||
case i::wasm::kWasmFuncRef:
|
||||
case i::wasm::kWasmNullRef: {
|
||||
i::Address raw = packer->Pop<i::Address>();
|
||||
i::Handle<i::Object> obj(i::Object(raw), store->i_isolate());
|
||||
DCHECK_IMPLIES(type == i::wasm::kWasmNullRef, obj->IsNull());
|
||||
results[i] = Val(V8RefValueToWasm(store, obj));
|
||||
break;
|
||||
}
|
||||
|
@ -236,6 +236,9 @@ inline bool decode_local_type(uint8_t val, ValueType* result) {
|
||||
case kLocalAnyRef:
|
||||
*result = kWasmAnyRef;
|
||||
return true;
|
||||
case kLocalNullRef:
|
||||
*result = kWasmNullRef;
|
||||
return true;
|
||||
case kLocalExnRef:
|
||||
*result = kWasmExnRef;
|
||||
return true;
|
||||
@ -858,6 +861,15 @@ class WasmDecoder : public Decoder {
|
||||
"invalid local type 'funcref', enable with "
|
||||
"--experimental-wasm-anyref");
|
||||
return false;
|
||||
case kLocalNullRef:
|
||||
if (enabled.has_anyref()) {
|
||||
type = kWasmNullRef;
|
||||
break;
|
||||
}
|
||||
decoder->error(decoder->pc() - 1,
|
||||
"invalid local type 'nullref', enable with "
|
||||
"--experimental-wasm-anyref");
|
||||
return false;
|
||||
case kLocalExnRef:
|
||||
if (enabled.has_eh()) {
|
||||
type = kWasmExnRef;
|
||||
|
@ -701,6 +701,7 @@ class WasmGraphBuildingInterface {
|
||||
return builder_->S128Zero();
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef:
|
||||
return builder_->RefNull();
|
||||
default:
|
||||
|
@ -1616,6 +1616,9 @@ class ModuleDecoderImpl : public Decoder {
|
||||
case kLocalAnyRef:
|
||||
if (enabled_features_.has_anyref()) return kWasmAnyRef;
|
||||
break;
|
||||
case kLocalNullRef:
|
||||
if (enabled_features_.has_anyref()) return kWasmNullRef;
|
||||
break;
|
||||
case kLocalExnRef:
|
||||
if (enabled_features_.has_eh()) return kWasmExnRef;
|
||||
break;
|
||||
@ -1641,6 +1644,13 @@ class ModuleDecoderImpl : public Decoder {
|
||||
"Invalid type. Set --experimental-wasm-anyref to use 'AnyRef'");
|
||||
}
|
||||
return kWasmAnyRef;
|
||||
case kLocalNullRef:
|
||||
if (!enabled_features_.has_anyref()) {
|
||||
error(
|
||||
pc_ - 1,
|
||||
"Invalid type. Set --experimental-wasm-anyref to use 'NullRef'");
|
||||
}
|
||||
return kWasmNullRef;
|
||||
case kLocalExnRef:
|
||||
if (!enabled_features_.has_eh()) {
|
||||
error(pc_ - 1,
|
||||
|
@ -753,7 +753,9 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global,
|
||||
}
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef: {
|
||||
DCHECK_IMPLIES(global.type == kWasmNullRef, value->GetRef()->IsNull());
|
||||
tagged_globals_->set(global.offset, *value->GetRef());
|
||||
break;
|
||||
}
|
||||
@ -1155,8 +1157,6 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
|
||||
}
|
||||
|
||||
if (ValueTypes::IsReferenceType(global.type)) {
|
||||
// There shouldn't be any null-ref globals.
|
||||
DCHECK_NE(ValueType::kWasmNullRef, global.type);
|
||||
if (global.type == ValueType::kWasmFuncRef) {
|
||||
if (!value->IsNull(isolate_) &&
|
||||
!WasmExportedFunction::IsWasmExportedFunction(*value)) {
|
||||
@ -1165,6 +1165,15 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
|
||||
import_index, module_name, import_name);
|
||||
return false;
|
||||
}
|
||||
} else if (global.type == ValueType::kWasmNullRef) {
|
||||
if (value->IsNullOrUndefined(isolate_)) {
|
||||
WriteGlobalAnyRef(global, isolate_->factory()->null_value());
|
||||
return true;
|
||||
} else {
|
||||
ReportLinkError("imported nullref global must be null", import_index,
|
||||
module_name, import_name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
WriteGlobalAnyRef(global, value);
|
||||
return true;
|
||||
|
@ -213,7 +213,8 @@ class V8_EXPORT_PRIVATE ValueTypes {
|
||||
}
|
||||
|
||||
static inline bool IsReferenceType(ValueType type) {
|
||||
return type == kWasmAnyRef || type == kWasmFuncRef || type == kWasmExnRef;
|
||||
return type == kWasmAnyRef || type == kWasmFuncRef ||
|
||||
type == kWasmNullRef || type == kWasmExnRef;
|
||||
}
|
||||
|
||||
static inline ValueType CommonSubType(ValueType a, ValueType b) {
|
||||
@ -243,9 +244,11 @@ class V8_EXPORT_PRIVATE ValueTypes {
|
||||
return 16;
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef:
|
||||
return kSystemPointerSize;
|
||||
default:
|
||||
case kWasmStmt:
|
||||
case kWasmBottom:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
@ -262,9 +265,11 @@ class V8_EXPORT_PRIVATE ValueTypes {
|
||||
return 4;
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef:
|
||||
return kSystemPointerSizeLog2;
|
||||
default:
|
||||
case kWasmStmt:
|
||||
case kWasmBottom:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
@ -287,11 +292,13 @@ class V8_EXPORT_PRIVATE ValueTypes {
|
||||
return kLocalAnyRef;
|
||||
case kWasmFuncRef:
|
||||
return kLocalFuncRef;
|
||||
case kWasmNullRef:
|
||||
return kLocalNullRef;
|
||||
case kWasmExnRef:
|
||||
return kLocalExnRef;
|
||||
case kWasmStmt:
|
||||
return kLocalVoid;
|
||||
default:
|
||||
case kWasmBottom:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
@ -308,13 +315,14 @@ class V8_EXPORT_PRIVATE ValueTypes {
|
||||
return MachineType::Float64();
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef:
|
||||
return MachineType::TaggedPointer();
|
||||
case kWasmS128:
|
||||
return MachineType::Simd128();
|
||||
case kWasmStmt:
|
||||
return MachineType::None();
|
||||
default:
|
||||
case kWasmBottom:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
@ -338,7 +346,7 @@ class V8_EXPORT_PRIVATE ValueTypes {
|
||||
return MachineRepresentation::kSimd128;
|
||||
case kWasmStmt:
|
||||
return MachineRepresentation::kNone;
|
||||
default:
|
||||
case kWasmBottom:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
@ -382,10 +390,11 @@ class V8_EXPORT_PRIVATE ValueTypes {
|
||||
return 's';
|
||||
case kWasmStmt:
|
||||
return 'v';
|
||||
case kWasmNullRef:
|
||||
return 'n';
|
||||
case kWasmExnRef:
|
||||
case kWasmBottom:
|
||||
return '*';
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
@ -413,8 +422,6 @@ class V8_EXPORT_PRIVATE ValueTypes {
|
||||
return "<stmt>";
|
||||
case kWasmBottom:
|
||||
return "<bot>";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ enum ValueTypeCode : uint8_t {
|
||||
kLocalS128 = 0x7b,
|
||||
kLocalFuncRef = 0x70,
|
||||
kLocalAnyRef = 0x6f,
|
||||
kLocalNullRef = 0x6e,
|
||||
kLocalExnRef = 0x68,
|
||||
};
|
||||
// Binary encoding of other types.
|
||||
|
@ -1464,6 +1464,7 @@ class ThreadImpl {
|
||||
#undef CASE_TYPE
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef: {
|
||||
val = WasmValue(isolate_->factory()->null_value());
|
||||
break;
|
||||
@ -2861,8 +2862,10 @@ class ThreadImpl {
|
||||
}
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef: {
|
||||
Handle<Object> anyref = value.to_anyref();
|
||||
DCHECK_IMPLIES(sig->GetParam(i) == kWasmNullRef, anyref->IsNull());
|
||||
encoded_values->set(encoded_index++, *anyref);
|
||||
break;
|
||||
}
|
||||
@ -2963,8 +2966,10 @@ class ThreadImpl {
|
||||
}
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef: {
|
||||
Handle<Object> anyref(encoded_values->get(encoded_index++), isolate_);
|
||||
DCHECK_IMPLIES(sig->GetParam(i) == kWasmNullRef, anyref->IsNull());
|
||||
value = WasmValue(anyref);
|
||||
break;
|
||||
}
|
||||
@ -3122,6 +3127,7 @@ class ThreadImpl {
|
||||
V8_FALLTHROUGH;
|
||||
}
|
||||
case kExprSelect: {
|
||||
HandleScope scope(isolate_); // Avoid leaking handles.
|
||||
WasmValue cond = Pop();
|
||||
WasmValue fval = Pop();
|
||||
WasmValue tval = Pop();
|
||||
@ -3419,6 +3425,7 @@ class ThreadImpl {
|
||||
#undef CASE_TYPE
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef: {
|
||||
HandleScope handle_scope(isolate_); // Avoid leaking handles.
|
||||
Handle<FixedArray> global_buffer; // The buffer of the global.
|
||||
@ -3426,7 +3433,9 @@ class ThreadImpl {
|
||||
std::tie(global_buffer, global_index) =
|
||||
WasmInstanceObject::GetGlobalBufferAndIndex(instance_object_,
|
||||
global);
|
||||
global_buffer->set(global_index, *Pop().to_anyref());
|
||||
Handle<Object> ref = Pop().to_anyref();
|
||||
DCHECK_IMPLIES(global.type == kWasmNullRef, ref->IsNull());
|
||||
global_buffer->set(global_index, *ref);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -3882,7 +3891,10 @@ class ThreadImpl {
|
||||
break;
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef:
|
||||
DCHECK_IMPLIES(sig->GetParam(i) == kWasmNullRef,
|
||||
arg.to_anyref()->IsNull());
|
||||
packer.Push(arg.to_anyref()->ptr());
|
||||
break;
|
||||
default:
|
||||
@ -3921,8 +3933,10 @@ class ThreadImpl {
|
||||
break;
|
||||
case kWasmAnyRef:
|
||||
case kWasmFuncRef:
|
||||
case kWasmNullRef:
|
||||
case kWasmExnRef: {
|
||||
Handle<Object> ref(Object(packer.Pop<Address>()), isolate);
|
||||
DCHECK_IMPLIES(sig->GetReturn(i) == kWasmNullRef, ref->IsNull());
|
||||
Push(WasmValue(ref));
|
||||
break;
|
||||
}
|
||||
|
@ -1098,6 +1098,9 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
} else if (enabled_features.has_anyref() &&
|
||||
string->StringEquals(v8_str(isolate, "anyref"))) {
|
||||
type = i::wasm::kWasmAnyRef;
|
||||
} else if (enabled_features.has_anyref() &&
|
||||
string->StringEquals(v8_str(isolate, "nullref"))) {
|
||||
type = i::wasm::kWasmNullRef;
|
||||
} else {
|
||||
thrower.TypeError("Descriptor property 'element' must be 'anyfunc'");
|
||||
return;
|
||||
@ -1227,6 +1230,9 @@ bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
|
||||
} else if (enabled_features.has_anyref() &&
|
||||
string->StringEquals(v8_str(isolate, "anyfunc"))) {
|
||||
*type = i::wasm::kWasmFuncRef;
|
||||
} else if (enabled_features.has_anyref() &&
|
||||
string->StringEquals(v8_str(isolate, "nullref"))) {
|
||||
*type = i::wasm::kWasmNullRef;
|
||||
} else if (enabled_features.has_eh() &&
|
||||
string->StringEquals(v8_str(isolate, "exnref"))) {
|
||||
*type = i::wasm::kWasmExnRef;
|
||||
@ -1350,7 +1356,7 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
case i::wasm::kWasmAnyRef:
|
||||
case i::wasm::kWasmExnRef: {
|
||||
if (args.Length() < 2) {
|
||||
// When no inital value is provided, we have to use the WebAssembly
|
||||
// When no initial value is provided, we have to use the WebAssembly
|
||||
// default value 'null', and not the JS default value 'undefined'.
|
||||
global_obj->SetAnyRef(i_isolate->factory()->null_value());
|
||||
break;
|
||||
@ -1358,9 +1364,20 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
global_obj->SetAnyRef(Utils::OpenHandle(*value));
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmNullRef:
|
||||
if (args.Length() < 2) {
|
||||
// When no initial value is provided, we have to use the WebAssembly
|
||||
// default value 'null', and not the JS default value 'undefined'.
|
||||
global_obj->SetNullRef(i_isolate->factory()->null_value());
|
||||
break;
|
||||
}
|
||||
if (!global_obj->SetNullRef(Utils::OpenHandle(*value))) {
|
||||
thrower.TypeError("The value of nullref globals must be null");
|
||||
}
|
||||
break;
|
||||
case i::wasm::kWasmFuncRef: {
|
||||
if (args.Length() < 2) {
|
||||
// When no inital value is provided, we have to use the WebAssembly
|
||||
// When no initial value is provided, we have to use the WebAssembly
|
||||
// default value 'null', and not the JS default value 'undefined'.
|
||||
global_obj->SetFuncRef(i_isolate, i_isolate->factory()->null_value());
|
||||
break;
|
||||
@ -1789,7 +1806,10 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
break;
|
||||
case i::wasm::kWasmAnyRef:
|
||||
case i::wasm::kWasmFuncRef:
|
||||
case i::wasm::kWasmNullRef:
|
||||
case i::wasm::kWasmExnRef:
|
||||
DCHECK_IMPLIES(receiver->type() == i::wasm::kWasmNullRef,
|
||||
receiver->GetRef()->IsNull());
|
||||
return_value.Set(Utils::ToLocal(receiver->GetRef()));
|
||||
break;
|
||||
default:
|
||||
@ -1862,6 +1882,11 @@ void WebAssemblyGlobalSetValue(
|
||||
receiver->SetAnyRef(Utils::OpenHandle(*args[0]));
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmNullRef:
|
||||
if (!receiver->SetNullRef(Utils::OpenHandle(*args[0]))) {
|
||||
thrower.TypeError("The value of nullref must be null");
|
||||
}
|
||||
break;
|
||||
case i::wasm::kWasmFuncRef: {
|
||||
if (!receiver->SetFuncRef(i_isolate, Utils::OpenHandle(*args[0]))) {
|
||||
thrower.TypeError(
|
||||
|
@ -209,6 +209,10 @@ Handle<String> ToValueTypeString(Isolate* isolate, ValueType type) {
|
||||
string = factory->InternalizeUtf8String("anyfunc");
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmNullRef: {
|
||||
string = factory->InternalizeUtf8String("nullref");
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmExnRef: {
|
||||
string = factory->InternalizeUtf8String("exnref");
|
||||
break;
|
||||
|
@ -184,6 +184,15 @@ void WasmGlobalObject::SetAnyRef(Handle<Object> value) {
|
||||
tagged_buffer().set(offset(), *value);
|
||||
}
|
||||
|
||||
bool WasmGlobalObject::SetNullRef(Handle<Object> value) {
|
||||
DCHECK_EQ(type(), wasm::kWasmNullRef);
|
||||
if (!value->IsNull()) {
|
||||
return false;
|
||||
}
|
||||
tagged_buffer().set(offset(), *value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WasmGlobalObject::SetFuncRef(Isolate* isolate, Handle<Object> value) {
|
||||
DCHECK_EQ(type(), wasm::kWasmFuncRef);
|
||||
if (!value->IsNull(isolate) &&
|
||||
|
@ -523,6 +523,10 @@ bool WasmTableObject::IsValidElement(Isolate* isolate,
|
||||
table->type() == wasm::kWasmExnRef) {
|
||||
return true;
|
||||
}
|
||||
// Nullref only takes {null}.
|
||||
if (table->type() == wasm::kWasmNullRef) {
|
||||
return entry->IsNull(isolate);
|
||||
}
|
||||
// FuncRef tables can store {null}, {WasmExportedFunction}, {WasmJSFunction},
|
||||
// or {WasmCapiFunction} objects.
|
||||
if (entry->IsNull(isolate)) return true;
|
||||
@ -1794,6 +1798,7 @@ uint32_t WasmExceptionPackage::GetEncodedSize(
|
||||
break;
|
||||
case wasm::kWasmAnyRef:
|
||||
case wasm::kWasmFuncRef:
|
||||
case wasm::kWasmNullRef:
|
||||
case wasm::kWasmExnRef:
|
||||
encoded_size += 1;
|
||||
break;
|
||||
|
@ -369,6 +369,7 @@ class WasmGlobalObject : public JSObject {
|
||||
inline void SetF32(float value);
|
||||
inline void SetF64(double value);
|
||||
inline void SetAnyRef(Handle<Object> value);
|
||||
inline bool SetNullRef(Handle<Object> value);
|
||||
inline bool SetFuncRef(Isolate* isolate, Handle<Object> value);
|
||||
|
||||
private:
|
||||
|
@ -28,6 +28,7 @@ class TestSignatures {
|
||||
sig_i_r(1, 1, kIntAnyRefTypes4),
|
||||
sig_i_rr(1, 2, kIntAnyRefTypes4),
|
||||
sig_i_a(1, 1, kIntFuncRefTypes4),
|
||||
sig_i_n(1, 1, kIntNullRefTypes4),
|
||||
sig_l_v(1, 0, kLongTypes4),
|
||||
sig_l_l(1, 1, kLongTypes4),
|
||||
sig_l_ll(1, 2, kLongTypes4),
|
||||
@ -40,12 +41,14 @@ class TestSignatures {
|
||||
sig_a_v(1, 0, kFuncTypes4),
|
||||
sig_r_r(1, 1, kRefTypes4),
|
||||
sig_a_a(1, 1, kFuncTypes4),
|
||||
sig_n_v(1, 0, kIntNullRefTypes4 + 1),
|
||||
sig_v_v(0, 0, kIntTypes4),
|
||||
sig_v_i(0, 1, kIntTypes4),
|
||||
sig_v_ii(0, 2, kIntTypes4),
|
||||
sig_v_iii(0, 3, kIntTypes4),
|
||||
sig_v_r(0, 1, kRefTypes4),
|
||||
sig_v_a(0, 1, kFuncTypes4),
|
||||
sig_v_n(0, 1, kIntNullRefTypes4 + 1),
|
||||
sig_s_i(1, 1, kSimd128IntTypes4),
|
||||
sig_ii_v(2, 0, kIntTypes4),
|
||||
sig_iii_v(3, 0, kIntTypes4) {
|
||||
@ -61,12 +64,14 @@ class TestSignatures {
|
||||
for (int i = 1; i < 4; i++) kIntDoubleTypes4[i] = kWasmF64;
|
||||
for (int i = 1; i < 4; i++) kIntAnyRefTypes4[i] = kWasmAnyRef;
|
||||
for (int i = 1; i < 4; i++) kIntFuncRefTypes4[i] = kWasmFuncRef;
|
||||
for (int i = 1; i < 4; i++) kIntNullRefTypes4[i] = kWasmNullRef;
|
||||
for (int i = 0; i < 4; i++) kSimd128IntTypes4[i] = kWasmS128;
|
||||
kIntLongTypes4[0] = kWasmI32;
|
||||
kIntFloatTypes4[0] = kWasmI32;
|
||||
kIntDoubleTypes4[0] = kWasmI32;
|
||||
kIntAnyRefTypes4[0] = kWasmI32;
|
||||
kIntFuncRefTypes4[0] = kWasmI32;
|
||||
kIntNullRefTypes4[0] = kWasmI32;
|
||||
kSimd128IntTypes4[1] = kWasmI32;
|
||||
}
|
||||
|
||||
@ -87,6 +92,7 @@ class TestSignatures {
|
||||
FunctionSig* i_r() { return &sig_i_r; }
|
||||
FunctionSig* i_rr() { return &sig_i_rr; }
|
||||
FunctionSig* i_a() { return &sig_i_a; }
|
||||
FunctionSig* i_n() { return &sig_i_n; }
|
||||
|
||||
FunctionSig* f_f() { return &sig_f_f; }
|
||||
FunctionSig* f_ff() { return &sig_f_ff; }
|
||||
@ -97,6 +103,7 @@ class TestSignatures {
|
||||
FunctionSig* a_v() { return &sig_a_v; }
|
||||
FunctionSig* r_r() { return &sig_r_r; }
|
||||
FunctionSig* a_a() { return &sig_a_a; }
|
||||
FunctionSig* n_v() { return &sig_n_v; }
|
||||
|
||||
FunctionSig* v_v() { return &sig_v_v; }
|
||||
FunctionSig* v_i() { return &sig_v_i; }
|
||||
@ -104,6 +111,7 @@ class TestSignatures {
|
||||
FunctionSig* v_iii() { return &sig_v_iii; }
|
||||
FunctionSig* v_r() { return &sig_v_r; }
|
||||
FunctionSig* v_a() { return &sig_v_a; }
|
||||
FunctionSig* v_n() { return &sig_v_n; }
|
||||
FunctionSig* s_i() { return &sig_s_i; }
|
||||
|
||||
FunctionSig* ii_v() { return &sig_ii_v; }
|
||||
@ -130,6 +138,7 @@ class TestSignatures {
|
||||
ValueType kIntDoubleTypes4[4];
|
||||
ValueType kIntAnyRefTypes4[4];
|
||||
ValueType kIntFuncRefTypes4[4];
|
||||
ValueType kIntNullRefTypes4[4];
|
||||
ValueType kSimd128IntTypes4[4];
|
||||
|
||||
FunctionSig sig_i_v;
|
||||
@ -144,6 +153,7 @@ class TestSignatures {
|
||||
FunctionSig sig_i_r;
|
||||
FunctionSig sig_i_rr;
|
||||
FunctionSig sig_i_a;
|
||||
FunctionSig sig_i_n;
|
||||
|
||||
FunctionSig sig_l_v;
|
||||
FunctionSig sig_l_l;
|
||||
@ -159,6 +169,7 @@ class TestSignatures {
|
||||
FunctionSig sig_a_v;
|
||||
FunctionSig sig_r_r;
|
||||
FunctionSig sig_a_a;
|
||||
FunctionSig sig_n_v;
|
||||
|
||||
FunctionSig sig_v_v;
|
||||
FunctionSig sig_v_i;
|
||||
@ -166,6 +177,7 @@ class TestSignatures {
|
||||
FunctionSig sig_v_iii;
|
||||
FunctionSig sig_v_r;
|
||||
FunctionSig sig_v_a;
|
||||
FunctionSig sig_v_n;
|
||||
FunctionSig sig_s_i;
|
||||
|
||||
FunctionSig sig_ii_v;
|
||||
|
12
test/mjsunit/wasm/nullref-interpreter.js
Normal file
12
test/mjsunit/wasm/nullref-interpreter.js
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --experimental-wasm-anyref -experimental-wasm-eh
|
||||
// Flags: --wasm-interpret-all
|
||||
|
||||
// This is just a wrapper for an existing reference types test case that runs
|
||||
// with the --wasm-interpret-all flag added. If we ever decide to add a test
|
||||
// variant for this, then we can remove this file.
|
||||
|
||||
load("test/mjsunit/wasm/nullref.js");
|
347
test/mjsunit/wasm/nullref.js
Normal file
347
test/mjsunit/wasm/nullref.js
Normal file
@ -0,0 +1,347 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --experimental-wasm-anyref --experimental-wasm-eh
|
||||
|
||||
load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
|
||||
let kSig_n_n = makeSig([kWasmNullRef], [kWasmNullRef]);
|
||||
let kSig_r_n = makeSig([kWasmNullRef], [kWasmAnyRef]);
|
||||
let kSig_a_n = makeSig([kWasmNullRef], [kWasmAnyFunc]);
|
||||
let kSig_e_n = makeSig([kWasmNullRef], [kWasmExnRef]);
|
||||
let kSig_n_v = makeSig([], [kWasmNullRef]);
|
||||
let kSig_n_r = makeSig([kWasmAnyRef], [kWasmNullRef]);
|
||||
let kSig_n_a = makeSig([kWasmAnyFunc], [kWasmNullRef]);
|
||||
let kSig_n_e = makeSig([kWasmExnRef], [kWasmNullRef]);
|
||||
let kSig_v_n = makeSig([kWasmNullRef], []);
|
||||
let kSig_v_in = makeSig([kWasmI32, kWasmNullRef], []);
|
||||
let kSig_n_i = makeSig([kWasmI32], [kWasmNullRef]);
|
||||
let kSig_r_i = makeSig([kWasmI32], [kWasmAnyRef]);
|
||||
let kSig_e_i = makeSig([kWasmI32], [kWasmExnRef]);
|
||||
|
||||
(function testNullRefIdentityFunction() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
builder.addFunction('nullRef', kSig_n_n)
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
builder.addFunction('anyRef', kSig_r_n)
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
builder.addFunction('funcRef', kSig_a_n)
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
builder.addFunction('exnRef', kSig_e_n)
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
|
||||
const instance = builder.instantiate();
|
||||
|
||||
assertThrows(() => instance.exports.nullRef(a => a), TypeError);
|
||||
assertThrows(() => instance.exports.nullRef(print), TypeError);
|
||||
assertThrows(() => instance.exports.nullRef({'hello': 'world'}), TypeError);
|
||||
assertEquals(null, instance.exports.nullRef(null));
|
||||
assertEquals(null, instance.exports.anyRef(null));
|
||||
assertEquals(null, instance.exports.funcRef(null));
|
||||
assertEquals(null, instance.exports.exnRef(null));
|
||||
})();
|
||||
|
||||
(function testNullRefFromAnyRefFail() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_r);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
|
||||
assertThrows(() => builder.instantiate(), WebAssembly.CompileError);
|
||||
})();
|
||||
|
||||
(function testNullRefFromFuncRefFail() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_a);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
|
||||
assertThrows(() => builder.instantiate(), WebAssembly.CompileError);
|
||||
})();
|
||||
|
||||
(function testNullRefFromExnRefFail() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_e);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
|
||||
assertThrows(() => builder.instantiate(), WebAssembly.CompileError);
|
||||
})();
|
||||
|
||||
(function testNullRefDefaultValue() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_v);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addLocals({nullref_count: 1})
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
|
||||
const main = builder.instantiate().exports.main;
|
||||
assertEquals(null, main());
|
||||
})();
|
||||
|
||||
(function testNullRefFromAnyRefFail() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_v);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addLocals({anyref_count: 1})
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
|
||||
assertThrows(() => builder.instantiate(), WebAssembly.CompileError);
|
||||
})();
|
||||
|
||||
(function testNullRefFromFuncRefFail() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_v);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addLocals({anyfunc_count: 1})
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
|
||||
assertThrows(() => builder.instantiate(), WebAssembly.CompileError);
|
||||
})();
|
||||
|
||||
(function testNullRefFromExnRefFail() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_v);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addLocals({exnref_count: 1})
|
||||
.addBody([kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
|
||||
assertThrows(() => builder.instantiate(), WebAssembly.CompileError);
|
||||
})();
|
||||
|
||||
(function testAssignNullRefToNullRefLocal() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_n);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addBody([kExprRefNull, kExprLocalSet, 0, kExprLocalGet, 0])
|
||||
.exportFunc();
|
||||
|
||||
const main = builder.instantiate().exports.main;
|
||||
assertEquals(null, main(null));
|
||||
})();
|
||||
|
||||
(function testImplicitReturnNullRefAsNullRef() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_v);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addBody([kExprRefNull])
|
||||
.exportFunc();
|
||||
|
||||
const main = builder.instantiate().exports.main;
|
||||
assertEquals(null, main());
|
||||
})();
|
||||
|
||||
(function testExplicitReturnNullRefAsNullRef() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const sig_index = builder.addType(kSig_n_v);
|
||||
builder.addFunction('main', sig_index)
|
||||
.addBody([kExprRefNull, kExprReturn])
|
||||
.exportFunc();
|
||||
|
||||
const main = builder.instantiate().exports.main;
|
||||
assertEquals(null, main());
|
||||
})();
|
||||
|
||||
(function testGetNullRefGlobal() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const initialized = builder.addGlobal(kWasmNullRef, true)
|
||||
.exportAs('initialized');
|
||||
initialized.init = null;
|
||||
const uninitialized = builder.addGlobal(kWasmNullRef, true)
|
||||
.exportAs('uninitialized');
|
||||
const sig_n_v = builder.addType(kSig_n_v);
|
||||
const sig_v_n = builder.addType(kSig_v_n);
|
||||
const sig_v_v = builder.addType(kSig_v_v);
|
||||
builder.addFunction('get_initialized', sig_n_v)
|
||||
.addBody([kExprGlobalGet, initialized.index])
|
||||
.exportFunc();
|
||||
builder.addFunction('get_uninitialized', sig_n_v)
|
||||
.addBody([kExprGlobalGet, initialized.index])
|
||||
.exportFunc();
|
||||
builder.addFunction('set_initialized', sig_v_n)
|
||||
.addBody([kExprLocalGet, 0, kExprGlobalSet, initialized.index])
|
||||
.exportFunc();
|
||||
builder.addFunction('reset_initialized', sig_v_v)
|
||||
.addBody([kExprRefNull, kExprGlobalSet, initialized.index])
|
||||
.exportFunc();
|
||||
|
||||
const instance = builder.instantiate();
|
||||
assertTrue(instance.exports.initialized instanceof WebAssembly.Global);
|
||||
assertTrue(instance.exports.uninitialized instanceof WebAssembly.Global);
|
||||
assertEquals(instance.exports.initialized.value, null);
|
||||
assertEquals(instance.exports.uninitialized.value, null);
|
||||
assertEquals(null, instance.exports.get_initialized());
|
||||
assertEquals(null, instance.exports.get_uninitialized());
|
||||
|
||||
instance.exports.set_initialized(null);
|
||||
assertEquals(instance.exports.initialized.value, null);
|
||||
assertEquals(null, instance.exports.get_initialized());
|
||||
|
||||
instance.exports.reset_initialized();
|
||||
assertEquals(instance.exports.initialized.value, null);
|
||||
assertEquals(null, instance.exports.get_initialized());
|
||||
})();
|
||||
|
||||
(function testGetNullRefImportedGlobal() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const initialized_index = builder.addImportedGlobal("foo", "initialized", kWasmNullRef);
|
||||
const uninitialized_index = builder.addImportedGlobal("foo", "uninitialized", kWasmNullRef);
|
||||
const sig_n_v = builder.addType(kSig_n_v);
|
||||
const sig_v_n = builder.addType(kSig_v_n);
|
||||
const sig_v_v = builder.addType(kSig_v_v);
|
||||
builder.addFunction('get_initialized', sig_n_v)
|
||||
.addBody([kExprGlobalGet, initialized_index])
|
||||
.exportFunc();
|
||||
builder.addFunction('get_uninitialized', sig_n_v)
|
||||
.addBody([kExprGlobalGet, uninitialized_index])
|
||||
.exportFunc();
|
||||
|
||||
assertThrows(() => builder.instantiate({foo: {initialized: {}}}), WebAssembly.LinkError);
|
||||
assertThrows(() => builder.instantiate({foo: {initialized: a => a}}), WebAssembly.LinkError);
|
||||
|
||||
const instance = builder.instantiate({foo: {initialized: null}});
|
||||
assertEquals(null, instance.exports.get_initialized());
|
||||
assertEquals(null, instance.exports.get_uninitialized());
|
||||
})();
|
||||
|
||||
(function testNullRefTable() {
|
||||
print(arguments.callee.name);
|
||||
let table = new WebAssembly.Table({element: "nullref", initial: 2});
|
||||
|
||||
assertEquals(null, table.get(0));
|
||||
table.set(1, null);
|
||||
assertEquals(null, table.get(1));
|
||||
assertThrows(() => table.set(2, null), RangeError);
|
||||
|
||||
table.grow(2);
|
||||
|
||||
assertEquals(null, table.get(2));
|
||||
table.set(3, null);
|
||||
assertEquals(null, table.get(3));
|
||||
assertThrows(() => table.set(4, null), RangeError);
|
||||
|
||||
assertThrows(() => table.set(0, {}), TypeError);
|
||||
assertThrows(() => table.set(0, a => a), TypeError);
|
||||
})();
|
||||
|
||||
(function testAddNullRefTable() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const table = builder.addTable(kWasmNullRef, 3, 10);
|
||||
builder.addFunction('set_null', kSig_v_i)
|
||||
.addBody([kExprLocalGet, 0, kExprRefNull, kExprTableSet, table.index])
|
||||
.exportFunc();
|
||||
builder.addFunction('set', kSig_v_in)
|
||||
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprTableSet, table.index])
|
||||
.exportFunc();
|
||||
builder.addFunction('get_null', kSig_n_i)
|
||||
.addBody([kExprLocalGet, 0, kExprTableGet, table.index])
|
||||
.exportFunc();
|
||||
builder.addFunction('get_any', kSig_r_i)
|
||||
.addBody([kExprLocalGet, 0, kExprTableGet, table.index])
|
||||
.exportFunc();
|
||||
builder.addFunction('get_func', kSig_a_i)
|
||||
.addBody([kExprLocalGet, 0, kExprTableGet, table.index])
|
||||
.exportFunc();
|
||||
builder.addFunction('get_exn', kSig_e_i)
|
||||
.addBody([kExprLocalGet, 0, kExprTableGet, table.index])
|
||||
.exportFunc();
|
||||
|
||||
const instance = builder.instantiate();
|
||||
instance.exports.set_null(1);
|
||||
instance.exports.set(2, null);
|
||||
|
||||
assertEquals(null, instance.exports.get_null(0));
|
||||
assertEquals(null, instance.exports.get_null(1));
|
||||
assertEquals(null, instance.exports.get_null(2));
|
||||
assertEquals(null, instance.exports.get_any(0));
|
||||
assertEquals(null, instance.exports.get_any(1));
|
||||
assertEquals(null, instance.exports.get_any(2));
|
||||
assertEquals(null, instance.exports.get_func(0));
|
||||
assertEquals(null, instance.exports.get_func(1));
|
||||
assertEquals(null, instance.exports.get_func(2));
|
||||
assertEquals(null, instance.exports.get_exn(0));
|
||||
assertEquals(null, instance.exports.get_exn(1));
|
||||
assertEquals(null, instance.exports.get_exn(2));
|
||||
})();
|
||||
|
||||
(function testImportNullRefTable() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const table_index = builder.addImportedTable("imp", "table", 2, 10, kWasmNullRef);
|
||||
builder.addFunction('get_null', kSig_n_i)
|
||||
.addBody([kExprLocalGet, 0, kExprTableGet, table_index])
|
||||
.exportFunc();
|
||||
builder.addFunction('get_any', kSig_r_i)
|
||||
.addBody([kExprLocalGet, 0, kExprTableGet, table_index])
|
||||
.exportFunc();
|
||||
builder.addFunction('get_func', kSig_a_i)
|
||||
.addBody([kExprLocalGet, 0, kExprTableGet, table_index])
|
||||
.exportFunc();
|
||||
builder.addFunction('get_exn', kSig_e_i)
|
||||
.addBody([kExprLocalGet, 0, kExprTableGet, table_index])
|
||||
.exportFunc();
|
||||
|
||||
let table_func = new WebAssembly.Table({element: "anyfunc", initial: 2, maximum: 10});
|
||||
assertThrows(() => builder.instantiate({imp: {table: table_func}}),
|
||||
WebAssembly.LinkError, /imported table does not match the expected type/);
|
||||
|
||||
let table_any = new WebAssembly.Table({element: "anyref", initial: 2, maximum: 10});
|
||||
assertThrows(() => builder.instantiate({imp: {table: table_any}}),
|
||||
WebAssembly.LinkError, /imported table does not match the expected type/);
|
||||
|
||||
let table_null = new WebAssembly.Table({element: "nullref", initial: 2, maximum: 10});
|
||||
table_null.set(1, null);
|
||||
const instance = builder.instantiate({imp: {table: table_null}});
|
||||
|
||||
assertEquals(null, instance.exports.get_null(0));
|
||||
assertEquals(null, instance.exports.get_null(1));
|
||||
assertEquals(null, instance.exports.get_any(0));
|
||||
assertEquals(null, instance.exports.get_any(1));
|
||||
assertEquals(null, instance.exports.get_func(0));
|
||||
assertEquals(null, instance.exports.get_func(1));
|
||||
assertEquals(null, instance.exports.get_exn(0));
|
||||
assertEquals(null, instance.exports.get_exn(1));
|
||||
|
||||
assertThrows(() => instance.exports.get_null(2), WebAssembly.RuntimeError);
|
||||
table_null.grow(1);
|
||||
assertEquals(null, instance.exports.get_null(2));
|
||||
})();
|
||||
|
||||
(function testImportNullRefTableIntoAnyRefTable() {
|
||||
print(arguments.callee.name);
|
||||
const builder = new WasmModuleBuilder();
|
||||
const table_index = builder.addImportedTable("imp", "table", 2, 10, kWasmAnyRef);
|
||||
builder.addFunction('get', kSig_r_v)
|
||||
.addBody([kExprI32Const, 0, kExprTableGet, table_index])
|
||||
.exportFunc();
|
||||
|
||||
let table_null = new WebAssembly.Table({element: "nullref", initial: 2, maximum: 10});
|
||||
assertThrows(() => builder.instantiate({imp: {table: table_null}}),
|
||||
WebAssembly.LinkError, /imported table does not match the expected type/);
|
||||
})();
|
@ -99,6 +99,7 @@ let kWasmF64 = 0x7c;
|
||||
let kWasmS128 = 0x7b;
|
||||
let kWasmAnyRef = 0x6f;
|
||||
let kWasmAnyFunc = 0x70;
|
||||
let kWasmNullRef = 0x6e;
|
||||
let kWasmExnRef = 0x68;
|
||||
|
||||
let kExternalFunction = 0;
|
||||
@ -800,9 +801,9 @@ class WasmModuleBuilder {
|
||||
}
|
||||
|
||||
addTable(type, initial_size, max_size = undefined) {
|
||||
if (type != kWasmAnyRef && type != kWasmAnyFunc && type != kWasmExnRef) {
|
||||
if (type != kWasmAnyRef && type != kWasmAnyFunc && type != kWasmNullRef && type != kWasmExnRef) {
|
||||
throw new Error(
|
||||
'Tables must be of type kWasmAnyRef, kWasmAnyFunc, or kWasmExnRef');
|
||||
'Tables must be of type kWasmAnyRef, kWasmAnyFunc, kWasmNullRef or kWasmExnRef');
|
||||
}
|
||||
let table = new WasmTableBuilder(this, type, initial_size, max_size);
|
||||
table.index = this.tables.length + this.num_imported_tables;
|
||||
@ -1086,6 +1087,7 @@ class WasmModuleBuilder {
|
||||
break;
|
||||
case kWasmAnyFunc:
|
||||
case kWasmAnyRef:
|
||||
case kWasmNullRef:
|
||||
if (global.function_index !== undefined) {
|
||||
section.emit_u8(kExprRefFunc);
|
||||
section.emit_u32v(global.function_index);
|
||||
@ -1272,6 +1274,9 @@ class WasmModuleBuilder {
|
||||
if (l.anyfunc_count > 0) {
|
||||
local_decls.push({count: l.anyfunc_count, type: kWasmAnyFunc});
|
||||
}
|
||||
if (l.nullref_count > 0) {
|
||||
local_decls.push({count: l.nullref_count, type: kWasmNullRef});
|
||||
}
|
||||
if (l.except_count > 0) {
|
||||
local_decls.push({count: l.except_count, type: kWasmExnRef});
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ static const byte kCodeGetLocal1[] = {kExprLocalGet, 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,
|
||||
kWasmAnyRef};
|
||||
static const ValueType kValueTypes[] = {kWasmI32, kWasmI64, kWasmF32,
|
||||
kWasmF64, kWasmAnyRef, kWasmNullRef};
|
||||
static const MachineType machineTypes[] = {
|
||||
MachineType::Int8(), MachineType::Uint8(), MachineType::Int16(),
|
||||
MachineType::Uint16(), MachineType::Int32(), MachineType::Uint32(),
|
||||
@ -243,7 +243,7 @@ class TestModuleBuilder {
|
||||
|
||||
byte AddTable(ValueType type, uint32_t initial_size, bool has_maximum_size,
|
||||
uint32_t maximum_size) {
|
||||
CHECK(type == kWasmAnyRef || type == kWasmFuncRef);
|
||||
CHECK(type == kWasmAnyRef || type == kWasmFuncRef || type == kWasmNullRef);
|
||||
mod.tables.emplace_back();
|
||||
WasmTable& table = mod.tables.back();
|
||||
table.type = type;
|
||||
@ -296,6 +296,7 @@ TEST_F(FunctionBodyDecoderTest, Int32Const1) {
|
||||
TEST_F(FunctionBodyDecoderTest, RefNull) {
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
ExpectValidates(sigs.r_v(), {kExprRefNull});
|
||||
ExpectValidates(sigs.n_v(), {kExprRefNull});
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, RefFunc) {
|
||||
@ -1738,7 +1739,8 @@ TEST_F(FunctionBodyDecoderTest, MultiReturnType) {
|
||||
|
||||
ExpectValidates(&sig_cd_v, {WASM_CALL_FUNCTION0(0)});
|
||||
|
||||
if (a == c && b == d) {
|
||||
if (ValueTypes::IsSubType(kValueTypes[c], kValueTypes[a]) &&
|
||||
ValueTypes::IsSubType(kValueTypes[d], kValueTypes[b])) {
|
||||
ExpectValidates(&sig_ab_v, {WASM_CALL_FUNCTION0(0)});
|
||||
} else {
|
||||
ExpectFailure(&sig_ab_v, {WASM_CALL_FUNCTION0(0)});
|
||||
@ -1984,7 +1986,8 @@ TEST_F(FunctionBodyDecoderTest, AllGetGlobalCombinations) {
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.AddGlobal(global_type);
|
||||
Validate(local_type == global_type, &sig, {WASM_GET_GLOBAL(0)});
|
||||
Validate(ValueTypes::IsSubType(global_type, local_type), &sig,
|
||||
{WASM_GET_GLOBAL(0)});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1998,7 +2001,7 @@ TEST_F(FunctionBodyDecoderTest, AllSetGlobalCombinations) {
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.AddGlobal(global_type);
|
||||
Validate(local_type == global_type, &sig,
|
||||
Validate(ValueTypes::IsSubType(local_type, global_type), &sig,
|
||||
{WASM_SET_GLOBAL(0, WASM_GET_LOCAL(0))});
|
||||
}
|
||||
}
|
||||
@ -2012,11 +2015,14 @@ TEST_F(FunctionBodyDecoderTest, TableSet) {
|
||||
byte tab_func1 = builder.AddTable(kWasmFuncRef, 20, true, 30);
|
||||
byte tab_func2 = builder.AddTable(kWasmFuncRef, 10, false, 20);
|
||||
byte tab_ref2 = builder.AddTable(kWasmAnyRef, 10, false, 20);
|
||||
ValueType sig_types[]{kWasmAnyRef, kWasmFuncRef, kWasmI32};
|
||||
FunctionSig sig(0, 3, sig_types);
|
||||
byte tab_null1 = builder.AddTable(kWasmNullRef, 10, true, 20);
|
||||
byte tab_null2 = builder.AddTable(kWasmNullRef, 10, false, 20);
|
||||
ValueType sig_types[]{kWasmAnyRef, kWasmFuncRef, kWasmNullRef, kWasmI32};
|
||||
FunctionSig sig(0, 4, sig_types);
|
||||
byte local_ref = 0;
|
||||
byte local_func = 1;
|
||||
byte local_int = 2;
|
||||
byte local_null = 2;
|
||||
byte local_int = 3;
|
||||
ExpectValidates(&sig, {WASM_TABLE_SET(tab_ref1, WASM_I32V(6),
|
||||
WASM_GET_LOCAL(local_ref))});
|
||||
ExpectValidates(&sig, {WASM_TABLE_SET(tab_func1, WASM_I32V(5),
|
||||
@ -2039,12 +2045,42 @@ TEST_F(FunctionBodyDecoderTest, TableSet) {
|
||||
WASM_GET_LOCAL(local_int))});
|
||||
ExpectFailure(&sig, {WASM_TABLE_SET(tab_func1, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_int))});
|
||||
|
||||
// We can store nullref values as funcref or anyref but not the other way
|
||||
// round.
|
||||
ExpectValidates(&sig, {WASM_TABLE_SET(tab_null1, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_null))});
|
||||
ExpectValidates(&sig, {WASM_TABLE_SET(tab_ref1, WASM_I32V(8),
|
||||
WASM_GET_LOCAL(local_null))});
|
||||
ExpectValidates(&sig, {WASM_TABLE_SET(tab_func1, WASM_I32V(8),
|
||||
WASM_GET_LOCAL(local_null))});
|
||||
ExpectFailure(&sig, {WASM_TABLE_SET(tab_null1, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_ref))});
|
||||
ExpectFailure(&sig, {WASM_TABLE_SET(tab_null1, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_func))});
|
||||
ExpectFailure(&sig, {WASM_TABLE_SET(tab_null1, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_int))});
|
||||
ExpectValidates(&sig, {WASM_TABLE_SET(tab_null2, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_null))});
|
||||
ExpectValidates(&sig, {WASM_TABLE_SET(tab_ref2, WASM_I32V(8),
|
||||
WASM_GET_LOCAL(local_null))});
|
||||
ExpectValidates(&sig, {WASM_TABLE_SET(tab_func2, WASM_I32V(8),
|
||||
WASM_GET_LOCAL(local_null))});
|
||||
ExpectFailure(&sig, {WASM_TABLE_SET(tab_null2, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_ref))});
|
||||
ExpectFailure(&sig, {WASM_TABLE_SET(tab_null2, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_func))});
|
||||
ExpectFailure(&sig, {WASM_TABLE_SET(tab_null2, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_int))});
|
||||
|
||||
// Out-of-bounds table index should fail.
|
||||
byte oob_tab = 37;
|
||||
ExpectFailure(
|
||||
&sig, {WASM_TABLE_SET(oob_tab, WASM_I32V(9), WASM_GET_LOCAL(local_ref))});
|
||||
ExpectFailure(&sig, {WASM_TABLE_SET(oob_tab, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_func))});
|
||||
ExpectFailure(&sig, {WASM_TABLE_SET(oob_tab, WASM_I32V(3),
|
||||
WASM_GET_LOCAL(local_null))});
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, TableGet) {
|
||||
@ -2362,7 +2398,8 @@ TEST_F(FunctionBodyDecoderTest, Break_TypeCheckAll1) {
|
||||
sig.GetReturn(), WASM_IF(WASM_ZERO, WASM_BRV(0, WASM_GET_LOCAL(0))),
|
||||
WASM_GET_LOCAL(1))};
|
||||
|
||||
Validate(i == j, &sig, code);
|
||||
Validate(ValueTypes::IsSubType(kValueTypes[j], kValueTypes[i]), &sig,
|
||||
code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2376,7 +2413,8 @@ TEST_F(FunctionBodyDecoderTest, Break_TypeCheckAll2) {
|
||||
WASM_BRV_IF_ZERO(0, WASM_GET_LOCAL(0)),
|
||||
WASM_GET_LOCAL(1))};
|
||||
|
||||
Validate(i == j, &sig, code);
|
||||
Validate(ValueTypes::IsSubType(kValueTypes[j], kValueTypes[i]), &sig,
|
||||
code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2390,7 +2428,8 @@ TEST_F(FunctionBodyDecoderTest, Break_TypeCheckAll3) {
|
||||
WASM_GET_LOCAL(1),
|
||||
WASM_BRV_IF_ZERO(0, WASM_GET_LOCAL(0)))};
|
||||
|
||||
Validate(i == j, &sig, code);
|
||||
Validate(ValueTypes::IsSubType(kValueTypes[j], kValueTypes[i]), &sig,
|
||||
code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2434,7 +2473,8 @@ TEST_F(FunctionBodyDecoderTest, BreakIf_val_type) {
|
||||
types[1], WASM_BRV_IF(0, WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
|
||||
WASM_DROP, WASM_GET_LOCAL(0))};
|
||||
|
||||
Validate(i == j, &sig, code);
|
||||
Validate(ValueTypes::IsSubType(kValueTypes[j], kValueTypes[i]), &sig,
|
||||
code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2665,7 +2705,7 @@ TEST_F(FunctionBodyDecoderTest, Select_fail2) {
|
||||
ValueType type = kValueTypes[i];
|
||||
if (type == kWasmI32) continue;
|
||||
// Select without specified type is only allowed for number types.
|
||||
if (type == kWasmAnyRef) continue;
|
||||
if (type == kWasmAnyRef || type == kWasmNullRef) continue;
|
||||
|
||||
ValueType types[] = {type, kWasmI32, type};
|
||||
FunctionSig sig(1, 2, types);
|
||||
@ -3204,22 +3244,37 @@ TEST_F(FunctionBodyDecoderTest, TableGrow) {
|
||||
TestModuleBuilder builder;
|
||||
byte tab_func = builder.AddTable(kWasmFuncRef, 10, true, 20);
|
||||
byte tab_ref = builder.AddTable(kWasmAnyRef, 10, true, 20);
|
||||
byte tab_null = builder.AddTable(kWasmNullRef, 10, true, 20);
|
||||
|
||||
module = builder.module();
|
||||
|
||||
ExpectFailure(sigs.i_a(),
|
||||
{WASM_TABLE_GROW(tab_func, WASM_REF_NULL, WASM_ONE)});
|
||||
ExpectFailure(sigs.i_n(),
|
||||
{WASM_TABLE_GROW(tab_null, WASM_REF_NULL, WASM_ONE)});
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
ExpectValidates(sigs.i_a(),
|
||||
{WASM_TABLE_GROW(tab_func, WASM_REF_NULL, WASM_ONE)});
|
||||
ExpectValidates(sigs.i_r(),
|
||||
{WASM_TABLE_GROW(tab_ref, WASM_REF_NULL, WASM_ONE)});
|
||||
ExpectValidates(sigs.i_n(),
|
||||
{WASM_TABLE_GROW(tab_null, WASM_REF_NULL, WASM_ONE)});
|
||||
// FuncRef table cannot be initialized with an anyref value.
|
||||
ExpectFailure(sigs.i_r(),
|
||||
{WASM_TABLE_GROW(tab_func, WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
// Anyref table can be initialized with an funcref value.
|
||||
// FuncRef table can be initialized with a nullref value.
|
||||
ExpectValidates(sigs.i_n(),
|
||||
{WASM_TABLE_GROW(tab_func, WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
// Anyref table can be initialized with an funcref or nullref value.
|
||||
ExpectValidates(sigs.i_a(),
|
||||
{WASM_TABLE_GROW(tab_ref, WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
ExpectValidates(sigs.i_n(),
|
||||
{WASM_TABLE_GROW(tab_ref, WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
// NullRef table cannot be initialized with an funcref or anyref value.
|
||||
ExpectFailure(sigs.i_a(),
|
||||
{WASM_TABLE_GROW(tab_null, WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
ExpectFailure(sigs.i_r(),
|
||||
{WASM_TABLE_GROW(tab_null, WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
// Check that the table index gets verified.
|
||||
ExpectFailure(sigs.i_r(),
|
||||
{WASM_TABLE_GROW(tab_ref + 2, WASM_REF_NULL, WASM_ONE)});
|
||||
@ -3241,22 +3296,32 @@ TEST_F(FunctionBodyDecoderTest, TableFill) {
|
||||
TestModuleBuilder builder;
|
||||
byte tab_func = builder.AddTable(kWasmFuncRef, 10, true, 20);
|
||||
byte tab_ref = builder.AddTable(kWasmAnyRef, 10, true, 20);
|
||||
byte tab_null = builder.AddTable(kWasmNullRef, 10, true, 20);
|
||||
|
||||
module = builder.module();
|
||||
|
||||
ExpectFailure(sigs.v_a(),
|
||||
{WASM_TABLE_FILL(tab_func, WASM_ONE, WASM_REF_NULL, WASM_ONE)});
|
||||
ExpectFailure(sigs.v_n(),
|
||||
{WASM_TABLE_FILL(tab_null, WASM_ONE, WASM_REF_NULL, WASM_ONE)});
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
ExpectValidates(sigs.v_a(), {WASM_TABLE_FILL(tab_func, WASM_ONE,
|
||||
WASM_REF_NULL, WASM_ONE)});
|
||||
ExpectValidates(sigs.v_r(), {WASM_TABLE_FILL(tab_ref, WASM_ONE, WASM_REF_NULL,
|
||||
WASM_ONE)});
|
||||
ExpectValidates(sigs.v_n(), {WASM_TABLE_FILL(tab_null, WASM_ONE,
|
||||
WASM_REF_NULL, WASM_ONE)});
|
||||
// FuncRef table cannot be initialized with an anyref value.
|
||||
ExpectFailure(sigs.v_r(), {WASM_TABLE_FILL(tab_func, WASM_ONE,
|
||||
WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
// Anyref table can be initialized with an funcref value.
|
||||
// FuncRef table can be initialized with an nullref value.
|
||||
ExpectValidates(sigs.v_n(), {WASM_TABLE_FILL(tab_func, WASM_ONE,
|
||||
WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
// Anyref table can be initialized with an funcref or nullref value.
|
||||
ExpectValidates(sigs.v_a(), {WASM_TABLE_FILL(tab_ref, WASM_ONE,
|
||||
WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
ExpectValidates(sigs.v_n(), {WASM_TABLE_FILL(tab_ref, WASM_ONE,
|
||||
WASM_GET_LOCAL(0), WASM_ONE)});
|
||||
// Check that the table index gets verified.
|
||||
ExpectFailure(sigs.v_r(), {WASM_TABLE_FILL(tab_ref + 2, WASM_ONE,
|
||||
WASM_REF_NULL, WASM_ONE)});
|
||||
|
@ -168,7 +168,8 @@ struct ValueTypePair {
|
||||
{kLocalF32, kWasmF32}, // --
|
||||
{kLocalF64, kWasmF64}, // --
|
||||
{kLocalFuncRef, kWasmFuncRef}, // --
|
||||
{kLocalAnyRef, kWasmAnyRef} // --
|
||||
{kLocalAnyRef, kWasmAnyRef}, // --
|
||||
{kLocalNullRef, kWasmNullRef} // --
|
||||
};
|
||||
|
||||
class WasmModuleVerifyTest : public TestWithIsolateAndZone {
|
||||
@ -324,6 +325,34 @@ 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) {
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
static const byte data[] = {
|
||||
@ -340,6 +369,27 @@ TEST_F(WasmModuleVerifyTest, InvalidFuncRefGlobal) {
|
||||
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) {
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
static const byte data[] = {
|
||||
@ -373,6 +423,40 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobalWithGlobalInit) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, NullRefGlobalWithGlobalInit) {
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
static const byte data[] = {
|
||||
SECTION(Import, // --
|
||||
ENTRY_COUNT(1), // number of imports
|
||||
ADD_COUNT('m'), // module name
|
||||
ADD_COUNT('n'), // global name
|
||||
kExternalGlobal, // import kind
|
||||
kLocalNullRef, // type
|
||||
0), // mutability
|
||||
SECTION(Global, // --
|
||||
ENTRY_COUNT(1),
|
||||
kLocalNullRef, // local type
|
||||
0, // immutable
|
||||
WASM_INIT_EXPR_GLOBAL(0)),
|
||||
};
|
||||
|
||||
{
|
||||
// Should decode to exactly one global.
|
||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||
std::cout << result.error().message() << std::endl;
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(2u, result.value()->globals.size());
|
||||
EXPECT_EQ(0u, result.value()->functions.size());
|
||||
EXPECT_EQ(0u, result.value()->data_segments.size());
|
||||
|
||||
const WasmGlobal* global = &result.value()->globals.back();
|
||||
|
||||
EXPECT_EQ(kWasmNullRef, global->type);
|
||||
EXPECT_FALSE(global->mutability);
|
||||
EXPECT_EQ(WasmInitExpr::kGlobalIndex, global->init.kind);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, Global_invalid_type) {
|
||||
static const byte data[] = {
|
||||
SECTION(Global, // --
|
||||
@ -1551,7 +1635,7 @@ TEST_F(WasmSignatureDecodeTest, Fail_off_end) {
|
||||
TEST_F(WasmSignatureDecodeTest, Fail_anyref_without_flag) {
|
||||
// Disable AnyRef support and check that decoding fails.
|
||||
WASM_FEATURE_SCOPE_VAL(anyref, false);
|
||||
byte ref_types[] = {kLocalFuncRef, kLocalAnyRef};
|
||||
byte ref_types[] = {kLocalFuncRef, kLocalAnyRef, kLocalNullRef};
|
||||
for (byte invalid_type : ref_types) {
|
||||
for (size_t i = 0;; i++) {
|
||||
byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalI32)};
|
||||
|
@ -24,12 +24,6 @@
|
||||
'proposals/multi-value/call': [FAIL],
|
||||
'proposals/multi-value/if': [FAIL],
|
||||
'proposals/multi-value/func': [FAIL],
|
||||
|
||||
'proposals/reference-types/br_table' : [FAIL],
|
||||
'proposals/reference-types/ref_is_null' : [FAIL],
|
||||
'proposals/reference-types/linking' : [FAIL],
|
||||
'proposals/reference-types/ref_null' : [FAIL],
|
||||
'proposals/reference-types/select' : [FAIL],
|
||||
}], # ALWAYS
|
||||
|
||||
['arch == mipsel or arch == mips64el or arch == mips or arch == mips64', {
|
||||
|
Loading…
Reference in New Issue
Block a user