Commit 022635bf authored by rossberg's avatar rossberg Committed by Commit bot

Implement Instance instances correctly; fix a few error cases

R=titzer@chromium.org
BUG=

Review-Url: https://codereview.chromium.org/2620263003
Cr-Commit-Position: refs/heads/master@{#42288}
parent 1d32a398
......@@ -4166,8 +4166,6 @@ bool Genesis::InstallSpecialObjects(Handle<Context> native_context) {
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<JSGlobalObject> global(JSGlobalObject::cast(
native_context->global_object()));
Handle<JSObject> Error = isolate->error_function();
Handle<String> name =
......@@ -4175,7 +4173,9 @@ bool Genesis::InstallSpecialObjects(Handle<Context> native_context) {
Handle<Smi> stack_trace_limit(Smi::FromInt(FLAG_stack_trace_limit), isolate);
JSObject::AddProperty(Error, name, stack_trace_limit, NONE);
WasmJs::Install(isolate, global);
if (FLAG_expose_wasm || FLAG_validate_asm) {
WasmJs::Install(isolate);
}
return true;
}
......
......@@ -71,7 +71,7 @@ RawBuffer GetRawBufferSource(
end = start + array->ByteLength();
if (start == nullptr || end == start) {
thrower->TypeError("ArrayBuffer argument is empty");
thrower->CompileError("ArrayBuffer argument is empty");
}
} else {
thrower->TypeError("Argument 0 must be an ArrayBuffer or Uint8Array");
......@@ -203,23 +203,31 @@ MaybeLocal<Value> InstantiateModuleImpl(
MaybeLocal<Value> nothing;
i::Handle<i::JSReceiver> ffi = i::Handle<i::JSObject>::null();
if (args.Length() > kFfiOffset && args[kFfiOffset]->IsObject()) {
if (args.Length() > kFfiOffset && !args[kFfiOffset]->IsUndefined()) {
if (!args[kFfiOffset]->IsObject()) {
thrower->TypeError("Argument %d must be an object", kFfiOffset);
return nothing;
}
Local<Object> obj = Local<Object>::Cast(args[kFfiOffset]);
ffi = i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
}
i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null();
if (args.Length() > kMemOffset && args[kMemOffset]->IsObject()) {
if (args.Length() > kMemOffset && !args[kMemOffset]->IsUndefined()) {
if (!args[kMemOffset]->IsObject()) {
thrower->TypeError("Argument %d must be a WebAssembly.Memory",
kMemOffset);
return nothing;
}
Local<Object> obj = Local<Object>::Cast(args[kMemOffset]);
i::Handle<i::Object> mem_obj = v8::Utils::OpenHandle(*obj);
if (i::WasmJs::IsWasmMemoryObject(i_isolate, mem_obj)) {
memory = i::Handle<i::JSArrayBuffer>(
i::Handle<i::WasmMemoryObject>::cast(mem_obj)->buffer(), i_isolate);
} else {
if (!i::WasmJs::IsWasmMemoryObject(i_isolate, mem_obj)) {
thrower->TypeError("Argument %d must be a WebAssembly.Memory",
kMemOffset);
return nothing;
}
memory = i::Handle<i::JSArrayBuffer>(
i::Handle<i::WasmMemoryObject>::cast(mem_obj)->buffer(), i_isolate);
}
i::MaybeHandle<i::JSObject> instance = i::wasm::WasmModule::Instantiate(
i_isolate, thrower, i_module_obj, ffi, memory);
......@@ -292,7 +300,7 @@ void WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value>& args) {
return_value.Set(Utils::ToLocal(exports));
}
void WebAssemblyInstanceCtor(const v8::FunctionCallbackInfo<v8::Value>& args) {
void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(args.GetIsolate());
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
......@@ -722,20 +730,39 @@ Handle<JSFunction> InstallGetter(Isolate* isolate, Handle<JSObject> object,
return function;
}
void WasmJs::InstallWasmModuleSymbolIfNeeded(Isolate* isolate,
Handle<JSGlobalObject> global,
Handle<Context> context) {
if (!context->get(Context::WASM_MODULE_SYM_INDEX)->IsSymbol() ||
!context->get(Context::WASM_INSTANCE_SYM_INDEX)->IsSymbol()) {
InstallWasmMapsIfNeeded(isolate, isolate->native_context());
InstallWasmConstructors(isolate, isolate->global_object(),
isolate->native_context());
}
}
void WasmJs::Install(Isolate* isolate) {
Handle<JSGlobalObject> global = isolate->global_object();
Handle<Context> context(global->native_context(), isolate);
// TODO(titzer): once FLAG_expose_wasm is gone, this should become a DCHECK.
if (context->get(Context::WASM_FUNCTION_MAP_INDEX)->IsMap()) return;
// Install Maps.
// TODO(titzer): Also make one for strict mode functions?
Handle<Map> prev_map = Handle<Map>(context->sloppy_function_map(), isolate);
InstanceType instance_type = prev_map->instance_type();
int internal_fields = JSObject::GetInternalFieldCount(*prev_map);
CHECK_EQ(0, internal_fields);
int pre_allocated =
prev_map->GetInObjectProperties() - prev_map->unused_property_fields();
int instance_size = 0;
int in_object_properties = 0;
int wasm_internal_fields = internal_fields + 1 // module instance object
+ 1 // function arity
+ 1; // function signature
JSFunction::CalculateInstanceSizeHelper(instance_type, wasm_internal_fields,
0, &instance_size,
&in_object_properties);
int unused_property_fields = in_object_properties - pre_allocated;
Handle<Map> map = Map::CopyInitialMap(
prev_map, instance_size, in_object_properties, unused_property_fields);
context->set_wasm_function_map(*map);
// Install symbols.
void WasmJs::InstallWasmConstructors(Isolate* isolate,
Handle<JSGlobalObject> global,
Handle<Context> context) {
Factory* factory = isolate->factory();
// Create private symbols.
Handle<Symbol> module_sym = factory->NewPrivateSymbol();
......@@ -750,7 +777,9 @@ void WasmJs::InstallWasmConstructors(Isolate* isolate,
Handle<Symbol> memory_sym = factory->NewPrivateSymbol();
context->set_wasm_memory_sym(*memory_sym);
// Bind the WebAssembly object.
// Install the JS API.
// Setup WebAssembly
Handle<String> name = v8_str(isolate, "WebAssembly");
Handle<JSFunction> cons = factory->NewFunction(name);
JSFunction::SetInstancePrototype(
......@@ -775,10 +804,10 @@ void WasmJs::InstallWasmConstructors(Isolate* isolate,
context->set_wasm_module_constructor(*module_constructor);
Handle<JSObject> module_proto =
factory->NewJSObject(module_constructor, TENURED);
i::Handle<i::Map> map = isolate->factory()->NewMap(
i::Handle<i::Map> module_map = isolate->factory()->NewMap(
i::JS_OBJECT_TYPE, i::JSObject::kHeaderSize +
WasmModuleObject::kFieldCount * i::kPointerSize);
JSFunction::SetInitialMap(module_constructor, map, module_proto);
JSFunction::SetInitialMap(module_constructor, module_map, module_proto);
JSObject::AddProperty(module_proto, isolate->factory()->constructor_string(),
module_constructor, DONT_ENUM);
InstallFunc(isolate, module_constructor, "imports", WebAssemblyModuleImports,
......@@ -788,8 +817,17 @@ void WasmJs::InstallWasmConstructors(Isolate* isolate,
// Setup Instance
Handle<JSFunction> instance_constructor =
InstallFunc(isolate, webassembly, "Instance", WebAssemblyInstanceCtor, 1);
InstallFunc(isolate, webassembly, "Instance", WebAssemblyInstance, 1);
context->set_wasm_instance_constructor(*instance_constructor);
Handle<JSObject> instance_proto =
factory->NewJSObject(instance_constructor, TENURED);
i::Handle<i::Map> instance_map = isolate->factory()->NewMap(
i::JS_OBJECT_TYPE, i::JSObject::kHeaderSize +
WasmInstanceObject::kFieldCount * i::kPointerSize);
JSFunction::SetInitialMap(instance_constructor, instance_map, instance_proto);
JSObject::AddProperty(instance_proto,
isolate->factory()->constructor_string(),
instance_constructor, DONT_ENUM);
// Setup Table
Handle<JSFunction> table_constructor =
......@@ -797,10 +835,10 @@ void WasmJs::InstallWasmConstructors(Isolate* isolate,
context->set_wasm_table_constructor(*table_constructor);
Handle<JSObject> table_proto =
factory->NewJSObject(table_constructor, TENURED);
map = isolate->factory()->NewMap(
i::Handle<i::Map> table_map = isolate->factory()->NewMap(
i::JS_OBJECT_TYPE, i::JSObject::kHeaderSize +
WasmTableObject::kFieldCount * i::kPointerSize);
JSFunction::SetInitialMap(table_constructor, map, table_proto);
JSFunction::SetInitialMap(table_constructor, table_map, table_proto);
JSObject::AddProperty(table_proto, isolate->factory()->constructor_string(),
table_constructor, DONT_ENUM);
InstallGetter(isolate, table_proto, "length", WebAssemblyTableGetLength);
......@@ -814,10 +852,10 @@ void WasmJs::InstallWasmConstructors(Isolate* isolate,
context->set_wasm_memory_constructor(*memory_constructor);
Handle<JSObject> memory_proto =
factory->NewJSObject(memory_constructor, TENURED);
map = isolate->factory()->NewMap(
i::Handle<i::Map> memory_map = isolate->factory()->NewMap(
i::JS_OBJECT_TYPE, i::JSObject::kHeaderSize +
WasmMemoryObject::kFieldCount * i::kPointerSize);
JSFunction::SetInitialMap(memory_constructor, map, memory_proto);
JSFunction::SetInitialMap(memory_constructor, memory_map, memory_proto);
JSObject::AddProperty(memory_proto, isolate->factory()->constructor_string(),
memory_constructor, DONT_ENUM);
InstallFunc(isolate, memory_proto, "grow", WebAssemblyMemoryGrow, 1);
......@@ -839,49 +877,6 @@ void WasmJs::InstallWasmConstructors(Isolate* isolate,
runtime_error, attributes);
}
void WasmJs::Install(Isolate* isolate, Handle<JSGlobalObject> global) {
if (!FLAG_expose_wasm && !FLAG_validate_asm) {
return;
}
// Setup wasm function map.
Handle<Context> context(global->native_context(), isolate);
InstallWasmMapsIfNeeded(isolate, context);
if (FLAG_expose_wasm) {
InstallWasmConstructors(isolate, global, context);
}
}
void WasmJs::InstallWasmMapsIfNeeded(Isolate* isolate,
Handle<Context> context) {
if (!context->get(Context::WASM_FUNCTION_MAP_INDEX)->IsMap()) {
// TODO(titzer): Move this to bootstrapper.cc??
// TODO(titzer): Also make one for strict mode functions?
Handle<Map> prev_map = Handle<Map>(context->sloppy_function_map(), isolate);
InstanceType instance_type = prev_map->instance_type();
int internal_fields = JSObject::GetInternalFieldCount(*prev_map);
CHECK_EQ(0, internal_fields);
int pre_allocated =
prev_map->GetInObjectProperties() - prev_map->unused_property_fields();
int instance_size = 0;
int in_object_properties = 0;
int wasm_internal_fields = internal_fields + 1 // module instance object
+ 1 // function arity
+ 1; // function signature
JSFunction::CalculateInstanceSizeHelper(instance_type, wasm_internal_fields,
0, &instance_size,
&in_object_properties);
int unused_property_fields = in_object_properties - pre_allocated;
Handle<Map> map = Map::CopyInitialMap(
prev_map, instance_size, in_object_properties, unused_property_fields);
context->set_wasm_function_map(*map);
}
}
static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> symbol) {
if (value->IsJSObject()) {
i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value);
......
......@@ -13,16 +13,7 @@ namespace internal {
// Exposes a WASM API to JavaScript through the V8 API.
class WasmJs {
public:
static void Install(Isolate* isolate, Handle<JSGlobalObject> global_object);
V8_EXPORT_PRIVATE static void InstallWasmModuleSymbolIfNeeded(
Isolate* isolate, Handle<JSGlobalObject> global, Handle<Context> context);
V8_EXPORT_PRIVATE static void InstallWasmMapsIfNeeded(
Isolate* isolate, Handle<Context> context);
static void InstallWasmConstructors(Isolate* isolate,
Handle<JSGlobalObject> global,
Handle<Context> context);
V8_EXPORT_PRIVATE static void Install(Isolate* isolate);
// WebAssembly.Table.
static bool IsWasmTableObject(Isolate* isolate, Handle<Object> value);
......
......@@ -398,6 +398,8 @@ V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
V8_EXPORT_PRIVATE Handle<JSArray> GetImports(Isolate* isolate,
Handle<WasmModuleObject> module);
V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
Handle<WasmModuleObject> module);
V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
Handle<WasmModuleObject> module);
......
......@@ -292,12 +292,15 @@ bool WasmInstanceObject::IsWasmInstanceObject(Object* object) {
Handle<WasmInstanceObject> WasmInstanceObject::New(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
Handle<Map> map = isolate->factory()->NewMap(
JS_OBJECT_TYPE, JSObject::kHeaderSize + kFieldCount * kPointerSize);
Handle<JSFunction> instance_cons(
isolate->native_context()->wasm_instance_constructor());
Handle<JSObject> instance_object =
isolate->factory()->NewJSObject(instance_cons, TENURED);
Handle<Symbol> instance_sym(isolate->native_context()->wasm_instance_sym());
Object::SetProperty(instance_object, instance_sym, instance_object, STRICT)
.Check();
Handle<WasmInstanceObject> instance(
reinterpret_cast<WasmInstanceObject*>(
*isolate->factory()->NewJSObjectFromMap(map, TENURED)),
isolate);
reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate);
instance->SetInternalField(kCompiledModule, *compiled_module);
instance->SetInternalField(kMemoryObject, isolate->heap()->undefined_value());
......
......@@ -85,6 +85,7 @@ class TestingModule : public ModuleEnv {
Vector<const byte>::empty()),
zone->allocator())
: nullptr) {
WasmJs::Install(isolate_);
instance->module = &module_;
instance->globals_start = global_data;
module_.globals_size = kMaxGlobalsSize;
......@@ -223,7 +224,6 @@ class TestingModule : public ModuleEnv {
// Wrap the code so it can be called as a JS function.
Handle<WasmInstanceObject> instance_obj(0, isolate_);
Handle<Code> code = instance->function_code[index];
WasmJs::InstallWasmMapsIfNeeded(isolate_, isolate_->native_context());
Handle<Code> ret_code =
compiler::CompileJSToWasmWrapper(isolate_, &module_, code, index);
Handle<JSFunction> ret = WasmExportedFunction::New(
......
......@@ -205,9 +205,7 @@ int32_t CallWasmFunctionForTesting(Isolate* isolate, Handle<JSObject> instance,
}
void SetupIsolateForWasmModule(Isolate* isolate) {
WasmJs::InstallWasmMapsIfNeeded(isolate, isolate->native_context());
WasmJs::InstallWasmModuleSymbolIfNeeded(isolate, isolate->global_object(),
isolate->native_context());
WasmJs::Install(isolate);
}
} // namespace testing
} // namespace wasm
......
......@@ -134,8 +134,8 @@ assertErrorMessage(() => new Module(), TypeError, /requires more than 0 argument
assertErrorMessage(() => new Module(undefined), TypeError, "first argument must be an ArrayBuffer or typed array object");
assertErrorMessage(() => new Module(1), TypeError, "first argument must be an ArrayBuffer or typed array object");
assertErrorMessage(() => new Module({}), TypeError, "first argument must be an ArrayBuffer or typed array object");
//TODO assertErrorMessage(() => new Module(new Uint8Array()), CompileError, /failed to match magic number/);
//TODO assertErrorMessage(() => new Module(new ArrayBuffer()), CompileError, /failed to match magic number/);
assertErrorMessage(() => new Module(new Uint8Array()), CompileError, /failed to match magic number/);
assertErrorMessage(() => new Module(new ArrayBuffer()), CompileError, /failed to match magic number/);
assertEq(new Module(emptyModuleBinary) instanceof Module, true);
assertEq(new Module(emptyModuleBinary.buffer) instanceof Module, true);
......@@ -259,9 +259,9 @@ assertEq(Instance.name, "Instance");
assertErrorMessage(() => Instance(), TypeError, /constructor without new is forbidden/);
assertErrorMessage(() => new Instance(1), TypeError, "first argument must be a WebAssembly.Module");
assertErrorMessage(() => new Instance({}), TypeError, "first argument must be a WebAssembly.Module");
//TODO assertErrorMessage(() => new Instance(emptyModule, null), TypeError, "second argument must be an object");
//TODO assertEq(new Instance(emptyModule) instanceof Instance, true);
//TODO assertEq(new Instance(emptyModule, {}) instanceof Instance, true);
assertErrorMessage(() => new Instance(emptyModule, null), TypeError, "second argument must be an object");
assertEq(new Instance(emptyModule) instanceof Instance, true);
assertEq(new Instance(emptyModule, {}) instanceof Instance, true);
// 'WebAssembly.Instance.prototype' data property
let instanceProtoDesc = Object.getOwnPropertyDescriptor(Instance, 'prototype');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment