[wasm] Implement WebAssembly.Global object
This change implements the WebAssembly.Global object and constructor, but none of the accessors or functions. There is a new flag to enable this: --experimental-wasm-mut-global. Change-Id: Ifeb270d57392d7ca0900c80c0038932c96ee8b61 Reviewed-on: https://chromium-review.googlesource.com/989296 Commit-Queue: Ben Smith <binji@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#52335}
This commit is contained in:
parent
76e79f0f20
commit
2e197ba64e
@ -223,6 +223,7 @@ class StringWrapper;
|
||||
class SymbolWrapper;
|
||||
class Undetectable;
|
||||
class UniqueName;
|
||||
class WasmGlobalObject;
|
||||
class WasmMemoryObject;
|
||||
class WasmModuleObject;
|
||||
class WasmTableObject;
|
||||
|
@ -238,6 +238,7 @@ Type::bitset BitsetType::Lub(i::Map* map) {
|
||||
case JS_WEAK_SET_TYPE:
|
||||
case JS_PROMISE_TYPE:
|
||||
case WASM_MODULE_TYPE:
|
||||
case WASM_GLOBAL_TYPE:
|
||||
case WASM_INSTANCE_TYPE:
|
||||
case WASM_MEMORY_TYPE:
|
||||
case WASM_TABLE_TYPE:
|
||||
|
@ -306,6 +306,7 @@ enum ContextLookupFlags {
|
||||
V(STRING_ITERATOR_MAP_INDEX, Map, string_iterator_map) \
|
||||
V(SYMBOL_FUNCTION_INDEX, JSFunction, symbol_function) \
|
||||
V(NATIVE_FUNCTION_MAP_INDEX, Map, native_function_map) \
|
||||
V(WASM_GLOBAL_CONSTRUCTOR_INDEX, JSFunction, wasm_global_constructor) \
|
||||
V(WASM_INSTANCE_CONSTRUCTOR_INDEX, JSFunction, wasm_instance_constructor) \
|
||||
V(WASM_MEMORY_CONSTRUCTOR_INDEX, JSFunction, wasm_memory_constructor) \
|
||||
V(WASM_MODULE_CONSTRUCTOR_INDEX, JSFunction, wasm_module_constructor) \
|
||||
|
@ -590,6 +590,8 @@ DEFINE_BOOL(experimental_wasm_se, false,
|
||||
"enable prototype sign extension opcodes for wasm")
|
||||
DEFINE_BOOL(experimental_wasm_anyref, false,
|
||||
"enable prototype anyref support for wasm")
|
||||
DEFINE_BOOL(experimental_wasm_mut_global, false,
|
||||
"enable prototype import/export mutable global support for wasm")
|
||||
|
||||
DEFINE_BOOL(wasm_opt, false, "enable wasm optimization")
|
||||
DEFINE_BOOL(wasm_no_bounds_checks, false,
|
||||
|
@ -3555,6 +3555,7 @@ AllocationResult Heap::CopyJSObject(JSObject* source, AllocationSite* site) {
|
||||
map->instance_type() == JS_ERROR_TYPE ||
|
||||
map->instance_type() == JS_ARRAY_TYPE ||
|
||||
map->instance_type() == JS_API_OBJECT_TYPE ||
|
||||
map->instance_type() == WASM_GLOBAL_TYPE ||
|
||||
map->instance_type() == WASM_INSTANCE_TYPE ||
|
||||
map->instance_type() == WASM_MEMORY_TYPE ||
|
||||
map->instance_type() == WASM_MODULE_TYPE ||
|
||||
|
@ -593,6 +593,7 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_MESSAGE_OBJECT_TYPE:
|
||||
case JS_BOUND_FUNCTION_TYPE:
|
||||
case WASM_GLOBAL_TYPE:
|
||||
case WASM_MEMORY_TYPE:
|
||||
case WASM_MODULE_TYPE:
|
||||
case WASM_TABLE_TYPE:
|
||||
|
@ -191,6 +191,7 @@ void HeapObject::HeapObjectVerify() {
|
||||
case JS_API_OBJECT_TYPE:
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
|
||||
case WASM_GLOBAL_TYPE:
|
||||
case WASM_INSTANCE_TYPE:
|
||||
case WASM_MEMORY_TYPE:
|
||||
case WASM_MODULE_TYPE:
|
||||
|
@ -119,6 +119,7 @@ TYPE_CHECKER(SmallOrderedHashSet, SMALL_ORDERED_HASH_SET_TYPE)
|
||||
TYPE_CHECKER(SourcePositionTableWithFrameCache, TUPLE2_TYPE)
|
||||
TYPE_CHECKER(TemplateObjectDescription, TUPLE2_TYPE)
|
||||
TYPE_CHECKER(TransitionArray, TRANSITION_ARRAY_TYPE)
|
||||
TYPE_CHECKER(WasmGlobalObject, WASM_GLOBAL_TYPE)
|
||||
TYPE_CHECKER(WasmInstanceObject, WASM_INSTANCE_TYPE)
|
||||
TYPE_CHECKER(WasmMemoryObject, WASM_MEMORY_TYPE)
|
||||
TYPE_CHECKER(WasmModuleObject, WASM_MODULE_TYPE)
|
||||
|
@ -149,6 +149,7 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
|
||||
case JS_ASYNC_GENERATOR_OBJECT_TYPE:
|
||||
case JS_ARGUMENTS_TYPE:
|
||||
case JS_ERROR_TYPE:
|
||||
case WASM_GLOBAL_TYPE:
|
||||
case WASM_INSTANCE_TYPE: // TODO(titzer): debug printing for wasm objects
|
||||
case WASM_MEMORY_TYPE:
|
||||
case WASM_MODULE_TYPE:
|
||||
|
@ -1387,6 +1387,8 @@ int JSObject::GetHeaderSize(InstanceType type,
|
||||
return JSStringIterator::kSize;
|
||||
case JS_MODULE_NAMESPACE_TYPE:
|
||||
return JSModuleNamespace::kHeaderSize;
|
||||
case WASM_GLOBAL_TYPE:
|
||||
return WasmGlobalObject::kSize;
|
||||
case WASM_INSTANCE_TYPE:
|
||||
return WasmInstanceObject::kSize;
|
||||
case WASM_MEMORY_TYPE:
|
||||
@ -3091,6 +3093,7 @@ VisitorId Map::GetVisitorId(Map* map) {
|
||||
case JS_STRING_ITERATOR_TYPE:
|
||||
case JS_PROMISE_TYPE:
|
||||
case JS_REGEXP_TYPE:
|
||||
case WASM_GLOBAL_TYPE:
|
||||
case WASM_MEMORY_TYPE:
|
||||
case WASM_MODULE_TYPE:
|
||||
case WASM_TABLE_TYPE:
|
||||
@ -12826,6 +12829,7 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
|
||||
case JS_VALUE_TYPE:
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
case JS_WEAK_SET_TYPE:
|
||||
case WASM_GLOBAL_TYPE:
|
||||
case WASM_INSTANCE_TYPE:
|
||||
case WASM_MEMORY_TYPE:
|
||||
case WASM_MODULE_TYPE:
|
||||
@ -15784,7 +15788,8 @@ bool JSObject::WasConstructedFromApiFunction() {
|
||||
bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
|
||||
instance_type == JS_SPECIAL_API_OBJECT_TYPE;
|
||||
bool is_wasm_object =
|
||||
instance_type == WASM_MEMORY_TYPE || instance_type == WASM_MODULE_TYPE ||
|
||||
instance_type == WASM_GLOBAL_TYPE || instance_type == WASM_MEMORY_TYPE ||
|
||||
instance_type == WASM_MODULE_TYPE ||
|
||||
instance_type == WASM_INSTANCE_TYPE || instance_type == WASM_TABLE_TYPE;
|
||||
#ifdef ENABLE_SLOW_DCHECKS
|
||||
if (FLAG_enable_slow_asserts) {
|
||||
|
@ -72,6 +72,7 @@
|
||||
// - JSDate
|
||||
// - JSMessageObject
|
||||
// - JSModuleNamespace
|
||||
// - WasmGlobalObject
|
||||
// - WasmInstanceObject
|
||||
// - WasmMemoryObject
|
||||
// - WasmModuleObject
|
||||
@ -473,6 +474,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(JS_TYPED_ARRAY_TYPE) \
|
||||
V(JS_DATA_VIEW_TYPE) \
|
||||
\
|
||||
V(WASM_GLOBAL_TYPE) \
|
||||
V(WASM_INSTANCE_TYPE) \
|
||||
V(WASM_MEMORY_TYPE) \
|
||||
V(WASM_MODULE_TYPE) \
|
||||
@ -847,6 +849,7 @@ enum InstanceType : uint16_t {
|
||||
JS_TYPED_ARRAY_TYPE,
|
||||
JS_DATA_VIEW_TYPE,
|
||||
|
||||
WASM_GLOBAL_TYPE,
|
||||
WASM_INSTANCE_TYPE,
|
||||
WASM_MEMORY_TYPE,
|
||||
WASM_MODULE_TYPE,
|
||||
@ -1130,6 +1133,7 @@ template <class C> inline bool Is(Object* obj);
|
||||
V(TransitionArray) \
|
||||
V(Undetectable) \
|
||||
V(UniqueName) \
|
||||
V(WasmGlobalObject) \
|
||||
V(WasmInstanceObject) \
|
||||
V(WasmMemoryObject) \
|
||||
V(WasmModuleObject) \
|
||||
|
@ -676,6 +676,67 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
args.GetReturnValue().Set(Utils::ToLocal(memory_obj));
|
||||
}
|
||||
|
||||
void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
HandleScope scope(isolate);
|
||||
ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Global()");
|
||||
if (!args.IsConstructCall()) {
|
||||
thrower.TypeError("WebAssembly.Global must be invoked with 'new'");
|
||||
return;
|
||||
}
|
||||
if (!args[0]->IsObject()) {
|
||||
thrower.TypeError("Argument 0 must be a global descriptor");
|
||||
return;
|
||||
}
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
|
||||
|
||||
// TODO(binji): handle descriptor's 'value'.
|
||||
|
||||
// The descriptor's 'mutable'.
|
||||
bool is_mutable = false;
|
||||
{
|
||||
Local<String> mutable_key = v8_str(isolate, "mutable");
|
||||
v8::MaybeLocal<v8::Value> maybe = descriptor->Get(context, mutable_key);
|
||||
v8::Local<v8::Value> value;
|
||||
if (maybe.ToLocal(&value)) {
|
||||
if (!value->BooleanValue(context).To(&is_mutable)) return;
|
||||
}
|
||||
}
|
||||
|
||||
// The descriptor's 'type'.
|
||||
i::wasm::ValueType type;
|
||||
{
|
||||
v8::MaybeLocal<v8::Value> maybe =
|
||||
descriptor->Get(context, v8_str(isolate, "type"));
|
||||
v8::Local<v8::Value> value;
|
||||
if (!maybe.ToLocal(&value)) return;
|
||||
v8::Local<v8::String> string;
|
||||
if (!value->ToString(context).ToLocal(&string)) return;
|
||||
|
||||
bool equal;
|
||||
if (string->Equals(context, v8_str(isolate, "i32")).To(&equal) && equal) {
|
||||
type = i::wasm::kWasmI32;
|
||||
} else if (string->Equals(context, v8_str(isolate, "f32")).To(&equal) &&
|
||||
equal) {
|
||||
type = i::wasm::kWasmF32;
|
||||
} else if (string->Equals(context, v8_str(isolate, "f64")).To(&equal) &&
|
||||
equal) {
|
||||
type = i::wasm::kWasmF64;
|
||||
} else {
|
||||
thrower.TypeError(
|
||||
"Descriptor property 'type' must be 'i32', 'f32', or 'f64'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t offset = 0;
|
||||
i::Handle<i::JSObject> global_obj = i::WasmGlobalObject::New(
|
||||
i_isolate, i::MaybeHandle<i::JSArrayBuffer>(), type, offset, is_mutable);
|
||||
args.GetReturnValue().Set(Utils::ToLocal(global_obj));
|
||||
}
|
||||
|
||||
constexpr const char* kName_WasmMemoryObject = "WebAssembly.Memory";
|
||||
constexpr const char* kName_WasmInstanceObject = "WebAssembly.Instance";
|
||||
constexpr const char* kName_WasmTableObject = "WebAssembly.Table";
|
||||
@ -1040,6 +1101,22 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
|
||||
JSObject::AddProperty(memory_proto, factory->to_string_tag_symbol(),
|
||||
v8_str(isolate, "WebAssembly.Memory"), ro_attributes);
|
||||
|
||||
// Setup Global
|
||||
if (i::FLAG_experimental_wasm_mut_global) {
|
||||
Handle<JSFunction> global_constructor =
|
||||
InstallFunc(isolate, webassembly, "Global", WebAssemblyGlobal, 1);
|
||||
context->set_wasm_global_constructor(*global_constructor);
|
||||
JSFunction::EnsureHasInitialMap(global_constructor);
|
||||
Handle<JSObject> global_proto(
|
||||
JSObject::cast(global_constructor->instance_prototype()));
|
||||
i::Handle<i::Map> global_map = isolate->factory()->NewMap(
|
||||
i::WASM_GLOBAL_TYPE, WasmGlobalObject::kSize);
|
||||
JSFunction::SetInitialMap(global_constructor, global_map, global_proto);
|
||||
// TODO(binji): add other properties
|
||||
JSObject::AddProperty(global_proto, factory->to_string_tag_symbol(),
|
||||
v8_str(isolate, "WebAssembly.Global"), ro_attributes);
|
||||
}
|
||||
|
||||
// Setup errors
|
||||
attributes = static_cast<PropertyAttributes>(DONT_ENUM);
|
||||
Handle<JSFunction> compile_error(
|
||||
|
@ -22,6 +22,7 @@ namespace internal {
|
||||
|
||||
class WasmCompiledModule;
|
||||
class WasmDebugInfo;
|
||||
class WasmGlobalObject;
|
||||
class WasmInstanceObject;
|
||||
class WasmMemoryObject;
|
||||
class WasmModuleObject;
|
||||
|
@ -16,6 +16,7 @@ namespace internal {
|
||||
|
||||
CAST_ACCESSOR(WasmCompiledModule)
|
||||
CAST_ACCESSOR(WasmDebugInfo)
|
||||
CAST_ACCESSOR(WasmGlobalObject)
|
||||
CAST_ACCESSOR(WasmInstanceObject)
|
||||
CAST_ACCESSOR(WasmMemoryObject)
|
||||
CAST_ACCESSOR(WasmModuleObject)
|
||||
@ -57,6 +58,12 @@ SMI_ACCESSORS(WasmMemoryObject, maximum_pages, kMaximumPagesOffset)
|
||||
OPTIONAL_ACCESSORS(WasmMemoryObject, instances, FixedArrayOfWeakCells,
|
||||
kInstancesOffset)
|
||||
|
||||
// WasmGlobalObject
|
||||
ACCESSORS(WasmGlobalObject, array_buffer, JSArrayBuffer, kArrayBufferOffset)
|
||||
SMI_ACCESSORS(WasmGlobalObject, type, kTypeOffset)
|
||||
SMI_ACCESSORS(WasmGlobalObject, offset, kOffsetOffset)
|
||||
SMI_ACCESSORS(WasmGlobalObject, is_mutable, kIsMutableOffset)
|
||||
|
||||
// WasmInstanceObject
|
||||
ACCESSORS(WasmInstanceObject, wasm_context, Managed<WasmContext>,
|
||||
kWasmContextOffset)
|
||||
|
@ -518,6 +518,36 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate,
|
||||
return old_size / wasm::kWasmPageSize;
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<WasmGlobalObject> WasmGlobalObject::New(
|
||||
Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_buffer,
|
||||
wasm::ValueType type, int32_t offset, bool is_mutable) {
|
||||
Handle<JSFunction> global_ctor(
|
||||
isolate->native_context()->wasm_global_constructor());
|
||||
auto global_obj = Handle<WasmGlobalObject>::cast(
|
||||
isolate->factory()->NewJSObject(global_ctor));
|
||||
|
||||
uint32_t type_size = 1 << ElementSizeLog2Of(type);
|
||||
|
||||
Handle<JSArrayBuffer> buffer;
|
||||
if (!maybe_buffer.ToHandle(&buffer)) {
|
||||
// If no buffer was provided, create one long enough for the given type.
|
||||
buffer = wasm::SetupArrayBuffer(isolate, nullptr, type_size, false);
|
||||
}
|
||||
|
||||
// Check that the offset is in bounds.
|
||||
uint32_t buffer_size = 0;
|
||||
CHECK(buffer->byte_length()->ToUint32(&buffer_size));
|
||||
CHECK(offset + type_size <= buffer_size);
|
||||
|
||||
global_obj->set_array_buffer(*buffer);
|
||||
global_obj->set_type(static_cast<int>(type));
|
||||
global_obj->set_offset(offset);
|
||||
global_obj->set_is_mutable(is_mutable);
|
||||
|
||||
return global_obj;
|
||||
}
|
||||
|
||||
bool WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
|
||||
size_t minimum_size) {
|
||||
constexpr int kInvalidSigIndex = -1;
|
||||
|
@ -190,6 +190,33 @@ class WasmMemoryObject : public JSObject {
|
||||
static int32_t Grow(Isolate*, Handle<WasmMemoryObject>, uint32_t pages);
|
||||
};
|
||||
|
||||
// Representation of a WebAssembly.Global JavaScript-level object.
|
||||
class WasmGlobalObject : public JSObject {
|
||||
public:
|
||||
DECL_CAST(WasmGlobalObject)
|
||||
|
||||
DECL_ACCESSORS(array_buffer, JSArrayBuffer)
|
||||
DECL_INT_ACCESSORS(type)
|
||||
DECL_INT_ACCESSORS(offset)
|
||||
DECL_INT_ACCESSORS(is_mutable)
|
||||
|
||||
// Layout description.
|
||||
#define WASM_GLOBAL_OBJECT_FIELDS(V) \
|
||||
V(kArrayBufferOffset, kPointerSize) \
|
||||
V(kTypeOffset, kPointerSize) \
|
||||
V(kOffsetOffset, kPointerSize) \
|
||||
V(kIsMutableOffset, kPointerSize) \
|
||||
V(kSize, 0)
|
||||
|
||||
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
|
||||
WASM_GLOBAL_OBJECT_FIELDS)
|
||||
#undef WASM_GLOBAL_OBJECT_FIELDS
|
||||
|
||||
V8_EXPORT_PRIVATE static Handle<WasmGlobalObject> New(
|
||||
Isolate* isolate, MaybeHandle<JSArrayBuffer> buffer, wasm::ValueType type,
|
||||
int32_t offset, bool is_mutable);
|
||||
};
|
||||
|
||||
// A WebAssembly.Instance JavaScript-level object.
|
||||
class WasmInstanceObject : public JSObject {
|
||||
public:
|
||||
|
30
test/mjsunit/wasm/mutable-globals.js
Normal file
30
test/mjsunit/wasm/mutable-globals.js
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2018 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-mut-global
|
||||
|
||||
function assertGlobalIsValid(global) {
|
||||
assertSame(WebAssembly.Global.prototype, global.__proto__);
|
||||
assertSame(WebAssembly.Global, global.constructor);
|
||||
assertTrue(global instanceof Object);
|
||||
assertTrue(global instanceof WebAssembly.Global);
|
||||
}
|
||||
|
||||
(function TestConstructor() {
|
||||
|
||||
assertTrue(WebAssembly.Global instanceof Function);
|
||||
assertSame(WebAssembly.Global, WebAssembly.Global.prototype.constructor);
|
||||
|
||||
assertThrows(() => new WebAssembly.Global(), TypeError);
|
||||
assertThrows(() => new WebAssembly.Global(1), TypeError);
|
||||
assertThrows(() => new WebAssembly.Global(""), TypeError);
|
||||
|
||||
assertThrows(() => new WebAssembly.Global({}), TypeError);
|
||||
assertThrows(() => new WebAssembly.Global({type: 'foo'}), TypeError);
|
||||
assertThrows(() => new WebAssembly.Global({type: 'i64'}), TypeError);
|
||||
|
||||
for (let type of ['i32', 'f32', 'f64']) {
|
||||
assertGlobalIsValid(new WebAssembly.Global({type}));
|
||||
}
|
||||
})();
|
@ -145,12 +145,13 @@ INSTANCE_TYPES = {
|
||||
1080: "JS_WEAK_SET_TYPE",
|
||||
1081: "JS_TYPED_ARRAY_TYPE",
|
||||
1082: "JS_DATA_VIEW_TYPE",
|
||||
1083: "WASM_INSTANCE_TYPE",
|
||||
1084: "WASM_MEMORY_TYPE",
|
||||
1085: "WASM_MODULE_TYPE",
|
||||
1086: "WASM_TABLE_TYPE",
|
||||
1087: "JS_BOUND_FUNCTION_TYPE",
|
||||
1088: "JS_FUNCTION_TYPE",
|
||||
1083: "WASM_GLOBAL_TYPE",
|
||||
1084: "WASM_INSTANCE_TYPE",
|
||||
1085: "WASM_MEMORY_TYPE",
|
||||
1086: "WASM_MODULE_TYPE",
|
||||
1087: "WASM_TABLE_TYPE",
|
||||
1088: "JS_BOUND_FUNCTION_TYPE",
|
||||
1089: "JS_FUNCTION_TYPE",
|
||||
}
|
||||
|
||||
# List of known V8 maps.
|
||||
|
Loading…
Reference in New Issue
Block a user