[wasm][anyref] Allow anyref values in WebAssembly.Global objects
This CL adds support for anyref in WebAssembly.Global objects. Note that the specification is not complete yet in this area. I did the following changes: - I renamed the `array_buffer` field of WasmGlobalObject to `untagged_buffer` - I added an additional field of type FixedArray, `tagged_buffer`. - In the constructor of WasmGlobalObject I allocate either the former or the latter, but not both. - In the WebAssembly.Global constructor I added special handling for the case where no initial value is provided. In that case I set the inital value to `null` and not to `undefined`. R=titzer@chromium.org Bug: v8:7581 Change-Id: I7e4855d7e6c04a9bcdc7ebd450caca5819d060e2 Reviewed-on: https://chromium-review.googlesource.com/c/1398226 Commit-Queue: Andreas Haas <ahaas@chromium.org> Reviewed-by: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#58625}
This commit is contained in:
parent
195686d37c
commit
741f2312d1
@ -1792,7 +1792,7 @@ bool InstanceBuilder::ProcessImportedWasmGlobalObject(
|
||||
return false;
|
||||
}
|
||||
if (global.mutability) {
|
||||
Handle<JSArrayBuffer> buffer(global_object->array_buffer(), isolate_);
|
||||
Handle<JSArrayBuffer> buffer(global_object->untagged_buffer(), isolate_);
|
||||
int index = (*next_imported_mutable_global_index)++;
|
||||
instance->imported_mutable_globals_buffers()->set(index, *buffer);
|
||||
// It is safe in this case to store the raw pointer to the buffer
|
||||
@ -2193,33 +2193,35 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
|
||||
case kExternalGlobal: {
|
||||
const WasmGlobal& global = module_->globals[exp.index];
|
||||
if (enabled_.mut_global) {
|
||||
Handle<JSArrayBuffer> buffer;
|
||||
Handle<JSArrayBuffer> untagged_buffer;
|
||||
uint32_t offset;
|
||||
|
||||
if (global.mutability && global.imported) {
|
||||
Handle<FixedArray> buffers_array(
|
||||
instance->imported_mutable_globals_buffers(), isolate_);
|
||||
buffer = buffers_array->GetValueChecked<JSArrayBuffer>(
|
||||
untagged_buffer = buffers_array->GetValueChecked<JSArrayBuffer>(
|
||||
isolate_, global.index);
|
||||
Address global_addr =
|
||||
instance->imported_mutable_globals()[global.index];
|
||||
|
||||
size_t buffer_size = buffer->byte_length();
|
||||
size_t buffer_size = untagged_buffer->byte_length();
|
||||
Address backing_store =
|
||||
reinterpret_cast<Address>(buffer->backing_store());
|
||||
reinterpret_cast<Address>(untagged_buffer->backing_store());
|
||||
CHECK(global_addr >= backing_store &&
|
||||
global_addr < backing_store + buffer_size);
|
||||
offset = static_cast<uint32_t>(global_addr - backing_store);
|
||||
} else {
|
||||
buffer = handle(instance->untagged_globals_buffer(), isolate_);
|
||||
untagged_buffer =
|
||||
handle(instance->untagged_globals_buffer(), isolate_);
|
||||
offset = global.offset;
|
||||
}
|
||||
|
||||
// Since the global's array buffer is always provided, allocation
|
||||
// should never fail.
|
||||
// Since the global's array untagged_buffer is always provided,
|
||||
// allocation should never fail.
|
||||
Handle<WasmGlobalObject> global_obj =
|
||||
WasmGlobalObject::New(isolate_, buffer, global.type, offset,
|
||||
global.mutability)
|
||||
WasmGlobalObject::New(isolate_, untagged_buffer,
|
||||
MaybeHandle<FixedArray>(), global.type,
|
||||
offset, global.mutability)
|
||||
.ToHandleChecked();
|
||||
desc.set_value(global_obj);
|
||||
} else {
|
||||
|
@ -1152,6 +1152,8 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
type = i::wasm::kWasmI64;
|
||||
} else if (string->StringEquals(v8_str(isolate, "f64"))) {
|
||||
type = i::wasm::kWasmF64;
|
||||
} else if (string->StringEquals(v8_str(isolate, "anyref"))) {
|
||||
type = i::wasm::kWasmAnyRef;
|
||||
} else {
|
||||
thrower.TypeError(
|
||||
"Descriptor property 'value' must be 'i32', 'i64', 'f32', or "
|
||||
@ -1163,7 +1165,8 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
const uint32_t offset = 0;
|
||||
i::MaybeHandle<i::WasmGlobalObject> maybe_global_obj =
|
||||
i::WasmGlobalObject::New(i_isolate, i::MaybeHandle<i::JSArrayBuffer>(),
|
||||
type, offset, is_mutable);
|
||||
i::MaybeHandle<i::FixedArray>(), type, offset,
|
||||
is_mutable);
|
||||
|
||||
i::Handle<i::WasmGlobalObject> global_obj;
|
||||
if (!maybe_global_obj.ToHandle(&global_obj)) {
|
||||
@ -1222,6 +1225,17 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
global_obj->SetF64(f64_value);
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmAnyRef: {
|
||||
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));
|
||||
break;
|
||||
}
|
||||
global_obj->SetAnyRef(Utils::OpenHandle(*value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -1469,6 +1483,9 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
case i::wasm::kWasmF64:
|
||||
return_value.Set(receiver->GetF64());
|
||||
break;
|
||||
case i::wasm::kWasmAnyRef:
|
||||
return_value.Set(Utils::ToLocal(receiver->GetAnyRef()));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -1530,6 +1547,10 @@ void WebAssemblyGlobalSetValue(
|
||||
receiver->SetF64(f64_value);
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmAnyRef: {
|
||||
receiver->SetAnyRef(Utils::OpenHandle(*args[0]));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -120,7 +120,9 @@ OPTIONAL_ACCESSORS2(WasmMemoryObject, instances, WeakArrayList,
|
||||
kInstancesOffset)
|
||||
|
||||
// WasmGlobalObject
|
||||
ACCESSORS2(WasmGlobalObject, array_buffer, JSArrayBuffer, kArrayBufferOffset)
|
||||
ACCESSORS2(WasmGlobalObject, untagged_buffer, JSArrayBuffer,
|
||||
kUntaggedBufferOffset)
|
||||
ACCESSORS2(WasmGlobalObject, tagged_buffer, FixedArray, kTaggedBufferOffset)
|
||||
SMI_ACCESSORS(WasmGlobalObject, offset, kOffsetOffset)
|
||||
SMI_ACCESSORS(WasmGlobalObject, flags, kFlagsOffset)
|
||||
BIT_FIELD_ACCESSORS(WasmGlobalObject, flags, type, WasmGlobalObject::TypeBits)
|
||||
@ -132,8 +134,9 @@ int WasmGlobalObject::type_size() const {
|
||||
}
|
||||
|
||||
Address WasmGlobalObject::address() const {
|
||||
DCHECK_LE(offset() + type_size(), array_buffer()->byte_length());
|
||||
return Address(array_buffer()->backing_store()) + offset();
|
||||
DCHECK_NE(type(), wasm::kWasmAnyRef);
|
||||
DCHECK_LE(offset() + type_size(), untagged_buffer()->byte_length());
|
||||
return Address(untagged_buffer()->backing_store()) + offset();
|
||||
}
|
||||
|
||||
int32_t WasmGlobalObject::GetI32() {
|
||||
@ -152,6 +155,11 @@ double WasmGlobalObject::GetF64() {
|
||||
return ReadLittleEndianValue<double>(address());
|
||||
}
|
||||
|
||||
Handle<Object> WasmGlobalObject::GetAnyRef() {
|
||||
DCHECK_EQ(type(), wasm::kWasmAnyRef);
|
||||
return handle(tagged_buffer()->get(offset()), GetIsolate());
|
||||
}
|
||||
|
||||
void WasmGlobalObject::SetI32(int32_t value) {
|
||||
WriteLittleEndianValue<int32_t>(address(), value);
|
||||
}
|
||||
@ -168,6 +176,11 @@ void WasmGlobalObject::SetF64(double value) {
|
||||
WriteLittleEndianValue<double>(address(), value);
|
||||
}
|
||||
|
||||
void WasmGlobalObject::SetAnyRef(Handle<Object> value) {
|
||||
DCHECK_EQ(type(), wasm::kWasmAnyRef);
|
||||
tagged_buffer()->set(offset(), *value);
|
||||
}
|
||||
|
||||
// WasmInstanceObject
|
||||
PRIMITIVE_ACCESSORS(WasmInstanceObject, memory_start, byte*, kMemoryStartOffset)
|
||||
PRIMITIVE_ACCESSORS(WasmInstanceObject, memory_size, size_t, kMemorySizeOffset)
|
||||
|
@ -1097,32 +1097,42 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate,
|
||||
|
||||
// static
|
||||
MaybeHandle<WasmGlobalObject> WasmGlobalObject::New(
|
||||
Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_buffer,
|
||||
wasm::ValueType type, int32_t offset, bool is_mutable) {
|
||||
Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_untagged_buffer,
|
||||
MaybeHandle<FixedArray> maybe_tagged_buffer, wasm::ValueType type,
|
||||
int32_t offset, bool is_mutable) {
|
||||
Handle<JSFunction> global_ctor(
|
||||
isolate->native_context()->wasm_global_constructor(), isolate);
|
||||
auto global_obj = Handle<WasmGlobalObject>::cast(
|
||||
isolate->factory()->NewJSObject(global_ctor));
|
||||
|
||||
uint32_t type_size = wasm::ValueTypes::ElementSizeInBytes(type);
|
||||
|
||||
Handle<JSArrayBuffer> buffer;
|
||||
if (!maybe_buffer.ToHandle(&buffer)) {
|
||||
// If no buffer was provided, create one long enough for the given type.
|
||||
buffer =
|
||||
isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED);
|
||||
|
||||
const bool initialize = true;
|
||||
if (!JSArrayBuffer::SetupAllocatingData(buffer, isolate, type_size,
|
||||
initialize)) {
|
||||
return {};
|
||||
if (type == wasm::kWasmAnyRef) {
|
||||
Handle<FixedArray> tagged_buffer;
|
||||
if (!maybe_tagged_buffer.ToHandle(&tagged_buffer)) {
|
||||
// If no buffer was provided, create one.
|
||||
tagged_buffer = isolate->factory()->NewFixedArray(1, TENURED);
|
||||
CHECK_EQ(offset, 0);
|
||||
}
|
||||
global_obj->set_tagged_buffer(*tagged_buffer);
|
||||
} else {
|
||||
Handle<JSArrayBuffer> untagged_buffer;
|
||||
uint32_t type_size = wasm::ValueTypes::ElementSizeInBytes(type);
|
||||
if (!maybe_untagged_buffer.ToHandle(&untagged_buffer)) {
|
||||
// If no buffer was provided, create one long enough for the given type.
|
||||
untagged_buffer =
|
||||
isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED);
|
||||
|
||||
const bool initialize = true;
|
||||
if (!JSArrayBuffer::SetupAllocatingData(untagged_buffer, isolate,
|
||||
type_size, initialize)) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the offset is in bounds.
|
||||
CHECK_LE(offset + type_size, untagged_buffer->byte_length());
|
||||
|
||||
global_obj->set_untagged_buffer(*untagged_buffer);
|
||||
}
|
||||
|
||||
// Check that the offset is in bounds.
|
||||
CHECK_LE(offset + type_size, buffer->byte_length());
|
||||
|
||||
global_obj->set_array_buffer(*buffer);
|
||||
global_obj->set_flags(0);
|
||||
global_obj->set_type(type);
|
||||
global_obj->set_offset(offset);
|
||||
|
@ -335,7 +335,8 @@ class WasmGlobalObject : public JSObject {
|
||||
public:
|
||||
DECL_CAST2(WasmGlobalObject)
|
||||
|
||||
DECL_ACCESSORS2(array_buffer, JSArrayBuffer)
|
||||
DECL_ACCESSORS2(untagged_buffer, JSArrayBuffer)
|
||||
DECL_ACCESSORS2(tagged_buffer, FixedArray)
|
||||
DECL_INT32_ACCESSORS(offset)
|
||||
DECL_INT_ACCESSORS(flags)
|
||||
DECL_PRIMITIVE_ACCESSORS(type, wasm::ValueType)
|
||||
@ -350,10 +351,11 @@ class WasmGlobalObject : public JSObject {
|
||||
#undef WASM_GLOBAL_OBJECT_FLAGS_BIT_FIELDS
|
||||
|
||||
// Layout description.
|
||||
#define WASM_GLOBAL_OBJECT_FIELDS(V) \
|
||||
V(kArrayBufferOffset, kTaggedSize) \
|
||||
V(kOffsetOffset, kTaggedSize) \
|
||||
V(kFlagsOffset, kTaggedSize) \
|
||||
#define WASM_GLOBAL_OBJECT_FIELDS(V) \
|
||||
V(kUntaggedBufferOffset, kTaggedSize) \
|
||||
V(kTaggedBufferOffset, kTaggedSize) \
|
||||
V(kOffsetOffset, kTaggedSize) \
|
||||
V(kFlagsOffset, kTaggedSize) \
|
||||
V(kSize, 0)
|
||||
|
||||
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
|
||||
@ -361,7 +363,8 @@ class WasmGlobalObject : public JSObject {
|
||||
#undef WASM_GLOBAL_OBJECT_FIELDS
|
||||
|
||||
V8_EXPORT_PRIVATE static MaybeHandle<WasmGlobalObject> New(
|
||||
Isolate* isolate, MaybeHandle<JSArrayBuffer> buffer, wasm::ValueType type,
|
||||
Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_untagged_buffer,
|
||||
MaybeHandle<FixedArray> maybe_tagged_buffer, wasm::ValueType type,
|
||||
int32_t offset, bool is_mutable);
|
||||
|
||||
inline int type_size() const;
|
||||
@ -370,11 +373,13 @@ class WasmGlobalObject : public JSObject {
|
||||
inline int64_t GetI64();
|
||||
inline float GetF32();
|
||||
inline double GetF64();
|
||||
inline Handle<Object> GetAnyRef();
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
// This function returns the address of the global's data in the
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --experimental-wasm-anyref --expose-gc
|
||||
// Flags: --experimental-wasm-anyref --expose-gc --experimental-wasm-mut-global
|
||||
|
||||
load("test/mjsunit/wasm/wasm-constants.js");
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
@ -128,3 +128,45 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
Test({q: 14});
|
||||
Test(print);
|
||||
})();
|
||||
|
||||
(function TestAnyRefGlobalObjectDefaultValue() {
|
||||
print(arguments.callee.name);
|
||||
let default_init = new WebAssembly.Global({value: 'anyref', 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);
|
||||
assertSame(obj, global.value);
|
||||
assertSame(obj, global.valueOf());
|
||||
}
|
||||
|
||||
TestGlobal(null);
|
||||
TestGlobal(undefined);
|
||||
TestGlobal(1663);
|
||||
TestGlobal("testmyglobal");
|
||||
TestGlobal({a: 11});
|
||||
TestGlobal(print);
|
||||
})();
|
||||
|
||||
(function TestAnyRefGlobalObjectSetValue() {
|
||||
print(arguments.callee.name);
|
||||
let global = new WebAssembly.Global({value: 'anyref', mutable: true});
|
||||
|
||||
function TestGlobal(obj) {
|
||||
global.value = obj;
|
||||
assertSame(obj, global.value);
|
||||
assertSame(obj, global.valueOf());
|
||||
}
|
||||
|
||||
TestGlobal(null);
|
||||
TestGlobal(undefined);
|
||||
TestGlobal(1663);
|
||||
TestGlobal("testmyglobal");
|
||||
TestGlobal({a: 11});
|
||||
TestGlobal(print);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user