[wasm][anyref] Introduce anyfunc globals
Anyfunc globals are very similar to anyref globals. This CL is mostly about extending the conditions which guard the anyref globals code. R=mstarzinger@chromium.org Bug: v8:7581 Change-Id: Ia92ac4560102cc3ed0060342f92758db28f415ca Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1526004 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#60281}
This commit is contained in:
parent
644556e6ed
commit
d7cd9051ad
@ -3251,7 +3251,7 @@ Node* WasmGraphBuilder::BuildCallToRuntime(Runtime::FunctionId f,
|
||||
|
||||
Node* WasmGraphBuilder::GetGlobal(uint32_t index) {
|
||||
const wasm::WasmGlobal& global = env_->module->globals[index];
|
||||
if (global.type == wasm::ValueType::kWasmAnyRef) {
|
||||
if (wasm::ValueTypes::IsReferenceType(global.type)) {
|
||||
if (global.mutability && global.imported) {
|
||||
Node* base = nullptr;
|
||||
Node* offset = nullptr;
|
||||
@ -3282,7 +3282,7 @@ Node* WasmGraphBuilder::GetGlobal(uint32_t index) {
|
||||
|
||||
Node* WasmGraphBuilder::SetGlobal(uint32_t index, Node* val) {
|
||||
const wasm::WasmGlobal& global = env_->module->globals[index];
|
||||
if (global.type == wasm::ValueType::kWasmAnyRef) {
|
||||
if (wasm::ValueTypes::IsReferenceType(global.type)) {
|
||||
if (global.mutability && global.imported) {
|
||||
Node* base = nullptr;
|
||||
Node* offset = nullptr;
|
||||
|
@ -2683,17 +2683,10 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
return stack_.data() + old_size;
|
||||
}
|
||||
|
||||
V8_INLINE bool IsSubType(ValueType expected, ValueType actual) {
|
||||
return (expected == actual) ||
|
||||
(expected == kWasmAnyRef && actual == kWasmNullRef) ||
|
||||
(expected == kWasmAnyRef && actual == kWasmAnyFunc) ||
|
||||
(expected == kWasmAnyFunc && actual == kWasmNullRef);
|
||||
}
|
||||
|
||||
V8_INLINE Value Pop(int index, ValueType expected) {
|
||||
auto val = Pop();
|
||||
if (!VALIDATE(IsSubType(expected, val.type) || val.type == kWasmVar ||
|
||||
expected == kWasmVar)) {
|
||||
if (!VALIDATE(ValueTypes::IsSubType(expected, val.type) ||
|
||||
val.type == kWasmVar || expected == kWasmVar)) {
|
||||
this->errorf(val.pc, "%s[%d] expected type %s, found %s of type %s",
|
||||
SafeOpcodeNameAt(this->pc_), index,
|
||||
ValueTypes::TypeName(expected), SafeOpcodeNameAt(val.pc),
|
||||
@ -2739,7 +2732,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
for (uint32_t i = 0; i < merge->arity; ++i) {
|
||||
Value& val = stack_values[i];
|
||||
Value& old = (*merge)[i];
|
||||
if (IsSubType(old.type, val.type)) continue;
|
||||
if (ValueTypes::IsSubType(old.type, val.type)) continue;
|
||||
// If {val.type} is polymorphic, which results from unreachable, make
|
||||
// it more specific by using the merge value's expected type.
|
||||
// If it is not polymorphic, this is a type error.
|
||||
@ -2810,7 +2803,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
for (uint32_t i = 0; i < num_returns; ++i) {
|
||||
auto& val = stack_values[i];
|
||||
ValueType expected_type = this->sig_->GetReturn(i);
|
||||
if (IsSubType(expected_type, val.type)) continue;
|
||||
if (ValueTypes::IsSubType(expected_type, val.type)) continue;
|
||||
// If {val.type} is polymorphic, which results from unreachable,
|
||||
// make it more specific by using the return's expected type.
|
||||
// If it is not polymorphic, this is a type error.
|
||||
|
@ -117,8 +117,8 @@ ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
|
||||
return kWasmF32;
|
||||
case WasmInitExpr::kF64Const:
|
||||
return kWasmF64;
|
||||
case WasmInitExpr::kAnyRefConst:
|
||||
return kWasmAnyRef;
|
||||
case WasmInitExpr::kRefNullConst:
|
||||
return kWasmNullRef;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -1169,7 +1169,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
ValueTypes::TypeName(module->globals[other_index].type));
|
||||
}
|
||||
} else {
|
||||
if (global->type != TypeOf(module, global->init)) {
|
||||
if (!ValueTypes::IsSubType(global->type, TypeOf(module, global->init))) {
|
||||
errorf(pos, "type error in global initialization, expected %s, got %s",
|
||||
ValueTypes::TypeName(global->type),
|
||||
ValueTypes::TypeName(TypeOf(module, global->init)));
|
||||
@ -1185,7 +1185,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
for (WasmGlobal& global : module->globals) {
|
||||
if (global.mutability && global.imported) {
|
||||
global.index = num_imported_mutable_globals++;
|
||||
} else if (global.type == ValueType::kWasmAnyRef) {
|
||||
} else if (ValueTypes::IsReferenceType(global.type)) {
|
||||
global.offset = tagged_offset;
|
||||
// All entries in the tagged_globals_buffer have size 1.
|
||||
tagged_offset++;
|
||||
@ -1435,7 +1435,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
}
|
||||
case kExprRefNull: {
|
||||
if (enabled_features_.anyref) {
|
||||
expr.kind = WasmInitExpr::kAnyRefConst;
|
||||
expr.kind = WasmInitExpr::kRefNullConst;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -552,7 +552,6 @@ MaybeHandle<Object> InstanceBuilder::LookupImport(uint32_t index,
|
||||
// We pre-validated in the js-api layer that the ffi object is present, and
|
||||
// a JSObject, if the module has imports.
|
||||
DCHECK(!ffi_.is_null());
|
||||
|
||||
// Look up the module first.
|
||||
MaybeHandle<Object> result = Object::GetPropertyOrElement(
|
||||
isolate_, ffi_.ToHandleChecked(), module_name);
|
||||
@ -972,7 +971,7 @@ bool InstanceBuilder::ProcessImportedWasmGlobalObject(
|
||||
DCHECK_LT(global.index, module_->num_imported_mutable_globals);
|
||||
Handle<Object> buffer;
|
||||
Address address_or_offset;
|
||||
if (global.type == kWasmAnyRef) {
|
||||
if (ValueTypes::IsReferenceType(global.type)) {
|
||||
static_assert(sizeof(global_object->offset()) <= sizeof(Address),
|
||||
"The offset into the globals buffer does not fit into "
|
||||
"the imported_mutable_globals array");
|
||||
@ -1050,7 +1049,18 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (global.type == ValueType::kWasmAnyRef) {
|
||||
if (ValueTypes::IsReferenceType(global.type)) {
|
||||
// There shouldn't be any null-ref globals.
|
||||
DCHECK_NE(ValueType::kWasmNullRef, global.type);
|
||||
if (global.type == ValueType::kWasmAnyFunc) {
|
||||
if (!value->IsNull(isolate_) &&
|
||||
!WasmExportedFunction::IsWasmExportedFunction(*value)) {
|
||||
ReportLinkError(
|
||||
"imported anyfunc global must be null or an exported function",
|
||||
import_index, module_name, import_name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
WriteGlobalAnyRef(global, value);
|
||||
return true;
|
||||
}
|
||||
@ -1183,7 +1193,7 @@ void InstanceBuilder::InitGlobals() {
|
||||
WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global),
|
||||
global.init.val.f64_const);
|
||||
break;
|
||||
case WasmInitExpr::kAnyRefConst:
|
||||
case WasmInitExpr::kRefNullConst:
|
||||
DCHECK(enabled_.anyref);
|
||||
if (global.imported) break; // We already initialized imported globals.
|
||||
|
||||
@ -1375,7 +1385,7 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
|
||||
if (global.mutability && global.imported) {
|
||||
Handle<FixedArray> buffers_array(
|
||||
instance->imported_mutable_globals_buffers(), isolate_);
|
||||
if (global.type == kWasmAnyRef) {
|
||||
if (ValueTypes::IsReferenceType(global.type)) {
|
||||
tagged_buffer = buffers_array->GetValueChecked<FixedArray>(
|
||||
isolate_, global.index);
|
||||
// For anyref globals we store the relative offset in the
|
||||
@ -1398,7 +1408,7 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
|
||||
offset = static_cast<uint32_t>(global_addr - backing_store);
|
||||
}
|
||||
} else {
|
||||
if (global.type == kWasmAnyRef) {
|
||||
if (ValueTypes::IsReferenceType(global.type)) {
|
||||
tagged_buffer = handle(instance->tagged_globals_buffer(), isolate_);
|
||||
} else {
|
||||
untagged_buffer =
|
||||
|
@ -178,6 +178,21 @@ class StoreType {
|
||||
// A collection of ValueType-related static methods.
|
||||
class V8_EXPORT_PRIVATE ValueTypes {
|
||||
public:
|
||||
static inline bool IsSubType(ValueType expected, ValueType actual) {
|
||||
return (expected == actual) ||
|
||||
(expected == kWasmAnyRef && actual == kWasmNullRef) ||
|
||||
(expected == kWasmAnyRef && actual == kWasmAnyFunc) ||
|
||||
(expected == kWasmAnyFunc && actual == kWasmNullRef);
|
||||
}
|
||||
|
||||
static inline bool IsReferenceType(ValueType type) {
|
||||
// This function assumes at the moment that it is never called with
|
||||
// {kWasmNullRef}. If this assumption is wrong, it should be added to the
|
||||
// result calculation below.
|
||||
DCHECK_NE(type, kWasmNullRef);
|
||||
return type == kWasmAnyRef || type == kWasmAnyFunc;
|
||||
}
|
||||
|
||||
static byte MemSize(MachineType type) {
|
||||
return 1 << i::ElementSizeLog2Of(type.representation());
|
||||
}
|
||||
|
@ -1202,6 +1202,8 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
type = i::wasm::kWasmF64;
|
||||
} else if (string->StringEquals(v8_str(isolate, "anyref"))) {
|
||||
type = i::wasm::kWasmAnyRef;
|
||||
} else if (string->StringEquals(v8_str(isolate, "anyfunc"))) {
|
||||
type = i::wasm::kWasmAnyFunc;
|
||||
} else {
|
||||
thrower.TypeError(
|
||||
"Descriptor property 'value' must be 'i32', 'i64', 'f32', or "
|
||||
@ -1277,13 +1279,27 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() < 2) {
|
||||
// When no inital value is provided, we have to use the WebAssembly
|
||||
// default value 'null', and not the JS default value 'undefined'.
|
||||
global_obj->SetAnyRef(
|
||||
handle(i::ReadOnlyRoots(i_isolate).null_value(), i_isolate));
|
||||
global_obj->SetAnyRef(i_isolate->factory()->null_value());
|
||||
break;
|
||||
}
|
||||
global_obj->SetAnyRef(Utils::OpenHandle(*value));
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmAnyFunc: {
|
||||
if (args.Length() < 2) {
|
||||
// When no inital value is provided, we have to use the WebAssembly
|
||||
// default value 'null', and not the JS default value 'undefined'.
|
||||
global_obj->SetAnyFunc(i_isolate, i_isolate->factory()->null_value());
|
||||
break;
|
||||
}
|
||||
|
||||
if (!global_obj->SetAnyFunc(i_isolate, Utils::OpenHandle(*value))) {
|
||||
thrower.TypeError(
|
||||
"The value of anyfunc globals must be null or an "
|
||||
"exported function");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -1640,7 +1656,8 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
return_value.Set(receiver->GetF64());
|
||||
break;
|
||||
case i::wasm::kWasmAnyRef:
|
||||
return_value.Set(Utils::ToLocal(receiver->GetAnyRef()));
|
||||
case i::wasm::kWasmAnyFunc:
|
||||
return_value.Set(Utils::ToLocal(receiver->GetRef()));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -1711,6 +1728,14 @@ void WebAssemblyGlobalSetValue(
|
||||
receiver->SetAnyRef(Utils::OpenHandle(*args[0]));
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmAnyFunc: {
|
||||
if (!receiver->SetAnyFunc(i_isolate, Utils::OpenHandle(*args[0]))) {
|
||||
thrower.TypeError(
|
||||
"value of an anyfunc reference must be either null or an "
|
||||
"exported function");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -151,8 +151,9 @@ double WasmGlobalObject::GetF64() {
|
||||
return ReadLittleEndianValue<double>(address());
|
||||
}
|
||||
|
||||
Handle<Object> WasmGlobalObject::GetAnyRef() {
|
||||
DCHECK_EQ(type(), wasm::kWasmAnyRef);
|
||||
Handle<Object> WasmGlobalObject::GetRef() {
|
||||
// We use this getter also for anyfunc.
|
||||
DCHECK(wasm::ValueTypes::IsReferenceType(type()));
|
||||
return handle(tagged_buffer()->get(offset()), GetIsolate());
|
||||
}
|
||||
|
||||
@ -177,6 +178,16 @@ void WasmGlobalObject::SetAnyRef(Handle<Object> value) {
|
||||
tagged_buffer()->set(offset(), *value);
|
||||
}
|
||||
|
||||
bool WasmGlobalObject::SetAnyFunc(Isolate* isolate, Handle<Object> value) {
|
||||
DCHECK_EQ(type(), wasm::kWasmAnyFunc);
|
||||
if (!value->IsNull(isolate) &&
|
||||
!WasmExportedFunction::IsWasmExportedFunction(*value)) {
|
||||
return false;
|
||||
}
|
||||
tagged_buffer()->set(offset(), *value);
|
||||
return true;
|
||||
}
|
||||
|
||||
// WasmInstanceObject
|
||||
PRIMITIVE_ACCESSORS(WasmInstanceObject, memory_start, byte*, kMemoryStartOffset)
|
||||
PRIMITIVE_ACCESSORS(WasmInstanceObject, memory_size, size_t, kMemorySizeOffset)
|
||||
|
@ -1327,7 +1327,7 @@ MaybeHandle<WasmGlobalObject> WasmGlobalObject::New(
|
||||
auto global_obj = Handle<WasmGlobalObject>::cast(
|
||||
isolate->factory()->NewJSObject(global_ctor));
|
||||
|
||||
if (type == wasm::kWasmAnyRef) {
|
||||
if (wasm::ValueTypes::IsReferenceType(type)) {
|
||||
DCHECK(maybe_untagged_buffer.is_null());
|
||||
Handle<FixedArray> tagged_buffer;
|
||||
if (!maybe_tagged_buffer.ToHandle(&tagged_buffer)) {
|
||||
|
@ -410,13 +410,14 @@ class WasmGlobalObject : public JSObject {
|
||||
inline int64_t GetI64();
|
||||
inline float GetF32();
|
||||
inline double GetF64();
|
||||
inline Handle<Object> GetAnyRef();
|
||||
inline Handle<Object> GetRef();
|
||||
|
||||
inline void SetI32(int32_t value);
|
||||
inline void SetI64(int64_t value);
|
||||
inline void SetF32(float value);
|
||||
inline void SetF64(double value);
|
||||
inline void SetAnyRef(Handle<Object> value);
|
||||
inline bool SetAnyFunc(Isolate* isolate, Handle<Object> value);
|
||||
|
||||
private:
|
||||
// This function returns the address of the global's data in the
|
||||
|
@ -609,7 +609,7 @@ struct WasmInitExpr {
|
||||
kI64Const,
|
||||
kF32Const,
|
||||
kF64Const,
|
||||
kAnyRefConst,
|
||||
kRefNullConst,
|
||||
} kind;
|
||||
|
||||
union {
|
||||
|
@ -9,33 +9,49 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
(function TestDefaultValue() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
const g_nullref = builder.addGlobal(kWasmAnyRef, true);
|
||||
builder.addFunction("main", kSig_r_v)
|
||||
.addBody([kExprGetGlobal, g_nullref.index])
|
||||
.exportAs("main");
|
||||
const g_nullref = builder.addGlobal(kWasmAnyRef, true).index;
|
||||
const g_nullfunc = builder.addGlobal(kWasmAnyFunc, true).index;
|
||||
builder.addFunction("get_anyref_global", kSig_r_v)
|
||||
.addBody([kExprGetGlobal, g_nullref])
|
||||
.exportAs("get_anyref_global");
|
||||
builder.addFunction("get_anyfunc_global", kSig_a_v)
|
||||
.addBody([kExprGetGlobal, g_nullfunc])
|
||||
.exportAs("get_anyfunc_global");
|
||||
|
||||
const instance = builder.instantiate();
|
||||
assertNull(instance.exports.main());
|
||||
assertEquals(null, instance.exports.get_anyref_global());
|
||||
assertEquals(null, instance.exports.get_anyfunc_global());
|
||||
})();
|
||||
|
||||
(function TestDefaultValueSecondGlobal() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
const g_setref = builder.addGlobal(kWasmAnyRef, true);
|
||||
const g_setfunc = builder.addGlobal(kWasmAnyFunc, true);
|
||||
const g_nullref = builder.addGlobal(kWasmAnyRef, true);
|
||||
builder.addFunction("main", kSig_r_r)
|
||||
const g_nullfunc = builder.addGlobal(kWasmAnyFunc, true);
|
||||
builder.addFunction("get_anyref_global", kSig_r_r)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g_setref.index,
|
||||
kExprGetGlobal, g_nullref.index
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g_setref.index,
|
||||
kExprGetGlobal, g_nullref.index
|
||||
])
|
||||
.exportAs("main");
|
||||
.exportAs("get_anyref_global");
|
||||
builder.addFunction("get_anyfunc_global", kSig_a_a)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g_setfunc.index,
|
||||
kExprGetGlobal, g_nullfunc.index
|
||||
])
|
||||
.exportAs("get_anyfunc_global");
|
||||
|
||||
const instance = builder.instantiate();
|
||||
assertNull(instance.exports.main({}));
|
||||
assertEquals(null, instance.exports.get_anyref_global({}));
|
||||
assertEquals(null, instance.exports.get_anyfunc_global(
|
||||
instance.exports.get_anyref_global));
|
||||
})();
|
||||
|
||||
(function TestGlobalChangeValue() {
|
||||
(function TestAnyRefGlobalChangeValue() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
// Dummy global for offset.
|
||||
@ -43,15 +59,35 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
const g = builder.addGlobal(kWasmAnyRef, true);
|
||||
builder.addFunction("main", kSig_r_r)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g.index,
|
||||
kExprGetGlobal, g.index
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g.index,
|
||||
kExprGetGlobal, g.index
|
||||
])
|
||||
.exportAs("main");
|
||||
|
||||
const instance = builder.instantiate();
|
||||
|
||||
const test_value = {hello: 'world'};
|
||||
const test_value = { hello: 'world' };
|
||||
assertSame(test_value, instance.exports.main(test_value));
|
||||
})();
|
||||
|
||||
(function TestAnyFuncGlobalChangeValue() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
// Dummy global for offset.
|
||||
builder.addGlobal(kWasmAnyFunc, true);
|
||||
const g = builder.addGlobal(kWasmAnyFunc, true);
|
||||
builder.addFunction("main", kSig_a_a)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g.index,
|
||||
kExprGetGlobal, g.index
|
||||
])
|
||||
.exportAs("main");
|
||||
|
||||
const instance = builder.instantiate();
|
||||
|
||||
const test_value = instance.exports.main;
|
||||
assertSame(test_value, instance.exports.main(test_value));
|
||||
})();
|
||||
|
||||
@ -64,16 +100,16 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
const g = builder.addGlobal(kWasmAnyRef, true);
|
||||
builder.addFunction("main", kSig_r_r)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g.index,
|
||||
kExprCallFunction, gc_index, // call gc
|
||||
kExprGetGlobal, g.index
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g.index,
|
||||
kExprCallFunction, gc_index, // call gc
|
||||
kExprGetGlobal, g.index
|
||||
])
|
||||
.exportAs("main");
|
||||
|
||||
const instance = builder.instantiate({q: {gc: gc}});
|
||||
const instance = builder.instantiate({ q: { gc: gc } });
|
||||
|
||||
const test_value = {hello: 'world'};
|
||||
const test_value = { hello: 'world' };
|
||||
assertSame(test_value, instance.exports.main(test_value));
|
||||
assertSame(5, instance.exports.main(5));
|
||||
assertSame("Hello", instance.exports.main("Hello"));
|
||||
@ -85,20 +121,20 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
const g = builder.addGlobal(kWasmAnyRef, true);
|
||||
builder.addFunction("get_global", kSig_r_v)
|
||||
.addBody([
|
||||
kExprGetGlobal, g.index
|
||||
kExprGetGlobal, g.index
|
||||
])
|
||||
.exportAs("get_global");
|
||||
|
||||
builder.addFunction("set_global", kSig_v_r)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g.index
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g.index
|
||||
])
|
||||
.exportAs("set_global");
|
||||
|
||||
const instance = builder.instantiate();
|
||||
|
||||
let test_value = {hello: 'world'};
|
||||
let test_value = { hello: 'world' };
|
||||
instance.exports.set_global(test_value);
|
||||
test_value = null;
|
||||
gc();
|
||||
@ -108,38 +144,73 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertEquals('world', result.hello);
|
||||
})();
|
||||
|
||||
(function TestImported() {
|
||||
(function TestImportedAnyRef() {
|
||||
print(arguments.callee.name);
|
||||
function Test(obj) {
|
||||
let builder = new WasmModuleBuilder();
|
||||
const g = builder.addImportedGlobal('m', 'val', kWasmAnyRef);
|
||||
builder.addFunction('main', kSig_r_v)
|
||||
.addBody([kExprGetGlobal, g])
|
||||
.exportAs('main');
|
||||
.addBody([kExprGetGlobal, g])
|
||||
.exportAs('main');
|
||||
|
||||
const instance = builder.instantiate({m: {val: obj}});
|
||||
const instance = builder.instantiate({ m: { val: obj } });
|
||||
assertSame(obj, instance.exports.main());
|
||||
}
|
||||
Test(null);
|
||||
Test(undefined);
|
||||
Test(1653);
|
||||
Test("mystring");
|
||||
Test({q: 14});
|
||||
Test({ q: 14 });
|
||||
Test(print);
|
||||
})();
|
||||
|
||||
function dummy_func() {
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addFunction("dummy", kSig_i_v)
|
||||
.addBody([kExprI32Const, 12])
|
||||
.exportAs("dummy");
|
||||
return builder.instantiate().exports.dummy;
|
||||
}
|
||||
|
||||
(function TestImportedAnyFunc() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
let builder = new WasmModuleBuilder();
|
||||
const g = builder.addImportedGlobal('m', 'val', kWasmAnyFunc);
|
||||
builder.addFunction('main', kSig_a_v)
|
||||
.addBody([kExprGetGlobal, g])
|
||||
.exportAs('main');
|
||||
|
||||
const module = builder.toModule();
|
||||
const instance = new WebAssembly.Instance(module, { m: { val: null } });
|
||||
assertSame(null, instance.exports.main());
|
||||
|
||||
const instance2 = new WebAssembly.Instance(
|
||||
module, { m: { val: instance.exports.main } });
|
||||
assertSame(instance.exports.main, instance2.exports.main());
|
||||
|
||||
assertThrows(() => new WebAssembly.Instance(module, { m: { val: {} } }),
|
||||
WebAssembly.LinkError);
|
||||
})();
|
||||
|
||||
(function TestAnyRefGlobalObjectDefaultValue() {
|
||||
print(arguments.callee.name);
|
||||
let default_init = new WebAssembly.Global({value: 'anyref', mutable: true});
|
||||
let default_init = new WebAssembly.Global({ value: 'anyref', mutable: true });
|
||||
assertSame(null, default_init.value);
|
||||
assertSame(null, default_init.valueOf());
|
||||
})();
|
||||
|
||||
(function TestAnyFuncGlobalObjectDefaultValue() {
|
||||
print(arguments.callee.name);
|
||||
let default_init = new WebAssembly.Global({ value: 'anyfunc', mutable: true });
|
||||
assertSame(null, default_init.value);
|
||||
assertSame(null, default_init.valueOf());
|
||||
})();
|
||||
|
||||
(function TestAnyRefGlobalObject() {
|
||||
print(arguments.callee.name);
|
||||
function TestGlobal(obj) {
|
||||
const global = new WebAssembly.Global({value: 'anyref'}, obj);
|
||||
const global = new WebAssembly.Global({ value: 'anyref' }, obj);
|
||||
assertSame(obj, global.value);
|
||||
assertSame(obj, global.valueOf());
|
||||
}
|
||||
@ -148,13 +219,28 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
TestGlobal(undefined);
|
||||
TestGlobal(1663);
|
||||
TestGlobal("testmyglobal");
|
||||
TestGlobal({a: 11});
|
||||
TestGlobal({ a: 11 });
|
||||
TestGlobal(print);
|
||||
})();
|
||||
|
||||
(function TestAnyFuncGlobalObject() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
const dummy = dummy_func();
|
||||
const global = new WebAssembly.Global({ value: 'anyfunc' }, dummy);
|
||||
assertSame(dummy, global.value);
|
||||
assertSame(dummy, global.valueOf());
|
||||
|
||||
const global_null = new WebAssembly.Global({ value: 'anyfunc' }, null);
|
||||
assertSame(null, global_null.value);
|
||||
assertSame(null, global_null.valueOf());
|
||||
|
||||
assertThrows(() => new WebAssembly.Global({ value: 'anyfunc' }, {}), TypeError);
|
||||
})();
|
||||
|
||||
(function TestAnyRefGlobalObjectSetValue() {
|
||||
print(arguments.callee.name);
|
||||
let global = new WebAssembly.Global({value: 'anyref', mutable: true});
|
||||
let global = new WebAssembly.Global({ value: 'anyref', mutable: true });
|
||||
|
||||
function TestGlobal(obj) {
|
||||
global.value = obj;
|
||||
@ -166,32 +252,60 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertThrows(() => TestGlobal(undefined), TypeError);
|
||||
TestGlobal(1663);
|
||||
TestGlobal("testmyglobal");
|
||||
TestGlobal({a: 11});
|
||||
TestGlobal({ a: 11 });
|
||||
TestGlobal(print);
|
||||
})();
|
||||
|
||||
(function TestExportMutableAnyRefGlobal() {
|
||||
|
||||
(function TestAnyFuncGlobalObjectSetValue() {
|
||||
print(arguments.callee.name);
|
||||
let global = new WebAssembly.Global({ value: 'anyfunc', mutable: true });
|
||||
|
||||
const dummy = dummy_func();
|
||||
global.value = dummy;
|
||||
assertSame(dummy, global.value);
|
||||
assertSame(dummy, global.valueOf());
|
||||
|
||||
global.value = null;
|
||||
assertSame(null, global.value);
|
||||
assertSame(null, global.valueOf());
|
||||
|
||||
assertThrows(() => global.value = {}, TypeError);
|
||||
})();
|
||||
|
||||
(function TestExportMutableRefGlobal() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
const g1 = builder.addGlobal(kWasmAnyRef, true).exportAs("global1");
|
||||
const g2 = builder.addGlobal(kWasmAnyFunc, true).exportAs("global2");
|
||||
builder.addGlobal(kWasmI32, true); // Dummy.
|
||||
builder.addGlobal(kWasmAnyRef, true); // Dummy.
|
||||
const g2 = builder.addGlobal(kWasmAnyRef, true).exportAs("global2");
|
||||
builder.addFunction("main", kSig_v_rr)
|
||||
const g3 = builder.addGlobal(kWasmAnyRef, true).exportAs("global3");
|
||||
const g4 = builder.addGlobal(kWasmAnyFunc, true).exportAs("global4");
|
||||
builder.addFunction("main",
|
||||
makeSig([kWasmAnyRef, kWasmAnyFunc, kWasmAnyRef, kWasmAnyFunc], []))
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g1.index,
|
||||
kExprGetLocal, 1,
|
||||
kExprSetGlobal, g2.index
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g1.index,
|
||||
kExprGetLocal, 1,
|
||||
kExprSetGlobal, g2.index,
|
||||
kExprGetLocal, 2,
|
||||
kExprSetGlobal, g3.index,
|
||||
kExprGetLocal, 3,
|
||||
kExprSetGlobal, g4.index
|
||||
])
|
||||
.exportAs("main");
|
||||
|
||||
const instance = builder.instantiate();
|
||||
const obj1 = {x: 221};
|
||||
const obj2 = print;
|
||||
instance.exports.main(obj1, obj2);
|
||||
const obj1 = { x: 221 };
|
||||
const func2 = instance.exports.main;
|
||||
const obj3 = print;
|
||||
const func4 = dummy_func();
|
||||
instance.exports.main(obj1, func2, obj3, func4);
|
||||
assertSame(obj1, instance.exports.global1.value);
|
||||
assertSame(obj2, instance.exports.global2.value);
|
||||
assertSame(func2, instance.exports.global2.value);
|
||||
assertSame(obj3, instance.exports.global3.value);
|
||||
assertSame(func4, instance.exports.global4.value);
|
||||
})();
|
||||
|
||||
(function TestImportMutableAnyRefGlobal() {
|
||||
@ -200,21 +314,38 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
let builder = new WasmModuleBuilder();
|
||||
const g = builder.addImportedGlobal('m', 'val', kWasmAnyRef, true);
|
||||
builder.addFunction('main', kSig_r_v)
|
||||
.addBody([kExprGetGlobal, g])
|
||||
.exportAs('main');
|
||||
.addBody([kExprGetGlobal, g])
|
||||
.exportAs('main');
|
||||
|
||||
const global = new WebAssembly.Global({value: 'anyref', mutable: 'true'}, obj);
|
||||
const instance = builder.instantiate({m: {val: global}});
|
||||
const global = new WebAssembly.Global({ value: 'anyref', mutable: 'true' }, obj);
|
||||
const instance = builder.instantiate({ m: { val: global } });
|
||||
assertSame(obj, instance.exports.main());
|
||||
}
|
||||
Test(null);
|
||||
Test(undefined);
|
||||
Test(1653);
|
||||
Test("mystring");
|
||||
Test({q: 14});
|
||||
Test({ q: 14 });
|
||||
Test(print);
|
||||
})();
|
||||
|
||||
(function TestImportMutableAnyFuncGlobal() {
|
||||
print(arguments.callee.name);
|
||||
function Test(obj) {
|
||||
let builder = new WasmModuleBuilder();
|
||||
const g = builder.addImportedGlobal('m', 'val', kWasmAnyFunc, true);
|
||||
builder.addFunction('main', kSig_a_v)
|
||||
.addBody([kExprGetGlobal, g])
|
||||
.exportAs('main');
|
||||
|
||||
const global = new WebAssembly.Global({ value: 'anyfunc', mutable: 'true' }, obj);
|
||||
const instance = builder.instantiate({ m: { val: global } });
|
||||
assertSame(obj, instance.exports.main());
|
||||
}
|
||||
Test(dummy_func());
|
||||
Test(null);
|
||||
})();
|
||||
|
||||
(function TestImportMutableAnyRefGlobalFromOtherInstance() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
@ -227,23 +358,23 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
builder1.addFunction("set_globals", kSig_v_rr)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g2.index,
|
||||
kExprGetLocal, 1,
|
||||
kExprSetGlobal, g3.index,
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g2.index,
|
||||
kExprGetLocal, 1,
|
||||
kExprSetGlobal, g3.index,
|
||||
])
|
||||
.exportAs("set_globals");
|
||||
|
||||
builder1.addFunction('get_global2', kSig_r_v)
|
||||
.addBody([kExprGetGlobal, g2.index])
|
||||
.exportAs('get_global2');
|
||||
.addBody([kExprGetGlobal, g2.index])
|
||||
.exportAs('get_global2');
|
||||
|
||||
builder1.addFunction('get_global3', kSig_r_v)
|
||||
.addBody([kExprGetGlobal, g3.index])
|
||||
.exportAs('get_global3');
|
||||
.addBody([kExprGetGlobal, g3.index])
|
||||
.exportAs('get_global3');
|
||||
|
||||
const instance1 = builder1.instantiate();
|
||||
const obj2 = {x: 221};
|
||||
const obj2 = { x: 221 };
|
||||
const obj3 = print;
|
||||
instance1.exports.set_globals(obj2, obj3);
|
||||
|
||||
@ -261,20 +392,20 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
builder2.addFunction("set_globals", kSig_v_rr)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, i2,
|
||||
kExprGetLocal, 1,
|
||||
kExprSetGlobal, i3,
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, i2,
|
||||
kExprGetLocal, 1,
|
||||
kExprSetGlobal, i3,
|
||||
])
|
||||
.exportAs("set_globals");
|
||||
|
||||
builder2.addFunction('get_global2', kSig_r_v)
|
||||
.addBody([kExprGetGlobal, i2])
|
||||
.exportAs('get_global2');
|
||||
.addBody([kExprGetGlobal, i2])
|
||||
.exportAs('get_global2');
|
||||
|
||||
builder2.addFunction('get_global3', kSig_r_v)
|
||||
.addBody([kExprGetGlobal, i3])
|
||||
.exportAs('get_global3');
|
||||
.addBody([kExprGetGlobal, i3])
|
||||
.exportAs('get_global3');
|
||||
|
||||
const instance2 = builder2.instantiate(instance1);
|
||||
// Check if the globals were imported correctly.
|
||||
@ -300,8 +431,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertEquals("foo", instance2.exports.reexport2.value);
|
||||
assertEquals(66343, instance2.exports.reexport3.value);
|
||||
|
||||
const bar2 = {f: "oo"};
|
||||
const bar3 = {b: "ar"};
|
||||
const bar2 = { f: "oo" };
|
||||
const bar3 = { b: "ar" };
|
||||
instance2.exports.reexport2.value = bar2;
|
||||
instance2.exports.reexport3.value = bar3;
|
||||
|
||||
@ -310,3 +441,90 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertSame(bar2, instance2.exports.get_global2());
|
||||
assertSame(bar3, instance2.exports.get_global3());
|
||||
})();
|
||||
|
||||
(function TestImportMutableAnyFuncGlobalFromOtherInstance() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
// Create an instance which exports globals.
|
||||
let builder1 = new WasmModuleBuilder();
|
||||
const g3 = builder1.addGlobal(kWasmAnyFunc, true).exportAs("e3");
|
||||
builder1.addGlobal(kWasmI32, true).exportAs("e1"); // Dummy.
|
||||
builder1.addGlobal(kWasmAnyFunc, true).exportAs("e4"); // Dummy.
|
||||
const g2 = builder1.addGlobal(kWasmAnyFunc, true).exportAs("e2");
|
||||
|
||||
builder1.addFunction("set_globals", kSig_v_aa)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, g2.index,
|
||||
kExprGetLocal, 1,
|
||||
kExprSetGlobal, g3.index,
|
||||
])
|
||||
.exportAs("set_globals");
|
||||
|
||||
builder1.addFunction('get_global2', kSig_a_v)
|
||||
.addBody([kExprGetGlobal, g2.index])
|
||||
.exportAs('get_global2');
|
||||
|
||||
builder1.addFunction('get_global3', kSig_a_v)
|
||||
.addBody([kExprGetGlobal, g3.index])
|
||||
.exportAs('get_global3');
|
||||
|
||||
const instance1 = builder1.instantiate();
|
||||
const obj2 = dummy_func();
|
||||
const obj3 = instance1.exports.set_globals;
|
||||
const obj4 = instance1.exports.get_global3;
|
||||
instance1.exports.set_globals(obj2, obj3);
|
||||
|
||||
// Create an instance which imports the globals of the other instance.
|
||||
let builder2 = new WasmModuleBuilder();
|
||||
const i1 = builder2.addImportedGlobal('exports', 'e1', kWasmI32, true);
|
||||
const i2 = builder2.addImportedGlobal('exports', 'e2', kWasmAnyFunc, true);
|
||||
const i3 = builder2.addImportedGlobal('exports', 'e3', kWasmAnyFunc, true);
|
||||
const i4 = builder2.addImportedGlobal('exports', 'e4', kWasmAnyFunc, true);
|
||||
|
||||
builder2.addExportOfKind("reexport1", kExternalGlobal, i1);
|
||||
builder2.addExportOfKind("reexport2", kExternalGlobal, i2);
|
||||
builder2.addExportOfKind("reexport3", kExternalGlobal, i3);
|
||||
builder2.addExportOfKind("reexport4", kExternalGlobal, i4);
|
||||
|
||||
builder2.addFunction("set_globals", kSig_v_aa)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprSetGlobal, i2,
|
||||
kExprGetLocal, 1,
|
||||
kExprSetGlobal, i3,
|
||||
])
|
||||
.exportAs("set_globals");
|
||||
|
||||
builder2.addFunction('get_global2', kSig_a_v)
|
||||
.addBody([kExprGetGlobal, i2])
|
||||
.exportAs('get_global2');
|
||||
|
||||
builder2.addFunction('get_global3', kSig_a_v)
|
||||
.addBody([kExprGetGlobal, i3])
|
||||
.exportAs('get_global3');
|
||||
|
||||
const instance2 = builder2.instantiate(instance1);
|
||||
// Check if the globals were imported correctly.
|
||||
assertSame(obj2, instance2.exports.get_global2());
|
||||
assertSame(obj3, instance2.exports.get_global3());
|
||||
|
||||
assertSame(obj2, instance2.exports.reexport2.value);
|
||||
assertSame(obj3, instance2.exports.reexport3.value);
|
||||
|
||||
// Check if instance2 can make changes visible for instance1.
|
||||
instance2.exports.set_globals(null, obj4);
|
||||
assertEquals(null, instance1.exports.get_global2());
|
||||
assertEquals(obj4, instance1.exports.get_global3());
|
||||
|
||||
assertEquals(null, instance2.exports.reexport2.value);
|
||||
assertEquals(obj4, instance2.exports.reexport3.value);
|
||||
|
||||
// Check if instance1 can make changes visible for instance2.
|
||||
instance1.exports.set_globals(obj2, obj3);
|
||||
assertEquals(obj2, instance2.exports.get_global2());
|
||||
assertEquals(obj3, instance2.exports.get_global3());
|
||||
|
||||
assertEquals(obj2, instance2.exports.reexport2.value);
|
||||
assertEquals(obj3, instance2.exports.reexport3.value);
|
||||
})();
|
||||
|
@ -154,6 +154,7 @@ let kSig_i_r = makeSig([kWasmAnyRef], [kWasmI32]);
|
||||
let kSig_v_r = makeSig([kWasmAnyRef], []);
|
||||
let kSig_v_a = makeSig([kWasmAnyFunc], []);
|
||||
let kSig_v_rr = makeSig([kWasmAnyRef, kWasmAnyRef], []);
|
||||
let kSig_v_aa = makeSig([kWasmAnyFunc, kWasmAnyFunc], []);
|
||||
let kSig_r_v = makeSig([], [kWasmAnyRef]);
|
||||
let kSig_a_v = makeSig([], [kWasmAnyFunc]);
|
||||
let kSig_a_i = makeSig([kWasmI32], [kWasmAnyFunc]);
|
||||
@ -1051,6 +1052,7 @@ class WasmModuleBuilder {
|
||||
section.emit_bytes(f64_bytes_view);
|
||||
break;
|
||||
case kWasmAnyRef:
|
||||
case kWasmAnyFunc:
|
||||
section.emit_u8(kExprRefNull);
|
||||
break;
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobal) {
|
||||
|
||||
EXPECT_EQ(kWasmAnyRef, global->type);
|
||||
EXPECT_FALSE(global->mutability);
|
||||
EXPECT_EQ(WasmInitExpr::kAnyRefConst, global->init.kind);
|
||||
EXPECT_EQ(WasmInitExpr::kRefNullConst, global->init.kind);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2119,7 +2119,7 @@ TEST_F(WasmInitExprDecodeTest, InitExpr_AnyRef) {
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
static const byte data[] = {kExprRefNull, kExprEnd};
|
||||
WasmInitExpr expr = DecodeInitExpr(data, data + sizeof(data));
|
||||
EXPECT_EQ(WasmInitExpr::kAnyRefConst, expr.kind);
|
||||
EXPECT_EQ(WasmInitExpr::kRefNullConst, expr.kind);
|
||||
}
|
||||
|
||||
TEST_F(WasmInitExprDecodeTest, InitExpr_illegal) {
|
||||
|
Loading…
Reference in New Issue
Block a user