[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:
Ben Smith 2018-04-03 11:17:57 -07:00 committed by Commit Bot
parent 76e79f0f20
commit 2e197ba64e
18 changed files with 199 additions and 7 deletions

View File

@ -223,6 +223,7 @@ class StringWrapper;
class SymbolWrapper;
class Undetectable;
class UniqueName;
class WasmGlobalObject;
class WasmMemoryObject;
class WasmModuleObject;
class WasmTableObject;

View File

@ -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:

View File

@ -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) \

View File

@ -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,

View File

@ -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 ||

View File

@ -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:

View File

@ -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:

View File

@ -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)

View File

@ -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:

View File

@ -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) {

View File

@ -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) \

View File

@ -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(

View File

@ -22,6 +22,7 @@ namespace internal {
class WasmCompiledModule;
class WasmDebugInfo;
class WasmGlobalObject;
class WasmInstanceObject;
class WasmMemoryObject;
class WasmModuleObject;

View File

@ -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)

View File

@ -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;

View File

@ -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:

View 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}));
}
})();

View File

@ -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.