Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Unified Diff: src/wasm/wasm-js.cc

Issue 2342623002: [wasm] Set up Table and Memory constructors
Patch Set: Eps Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/wasm/wasm-js.cc
diff --git a/src/wasm/wasm-js.cc b/src/wasm/wasm-js.cc
index ff974cb8cd13d5666318048bee15acf84a087667..7e0e53dd755806737fa2ee137ecbb4f48adf6284 100644
--- a/src/wasm/wasm-js.cc
+++ b/src/wasm/wasm-js.cc
@@ -29,6 +29,15 @@ using v8::internal::wasm::ErrorThrower;
namespace v8 {
namespace {
+i::Handle<i::String> v8_str(i::Isolate* isolate, const char* str) {
+ return isolate->factory()->NewStringFromAsciiChecked(str);
+}
+
+Local<String> v8_str(Isolate* isolate, const char* str) {
+ return Utils::ToLocal(v8_str(reinterpret_cast<i::Isolate*>(isolate), str));
+}
+
+
struct RawBuffer {
const byte* start;
const byte* end;
@@ -78,7 +87,7 @@ void VerifyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
ErrorThrower thrower(isolate, "Wasm.verifyModule()");
if (args.Length() < 1) {
- thrower.Error("Argument 0 must be a buffer source");
+ thrower.TypeError("Argument 0 must be a buffer source");
return;
}
RawBuffer buffer = GetRawBufferSource(args[0], &thrower);
@@ -102,7 +111,7 @@ void VerifyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
ErrorThrower thrower(isolate, "Wasm.verifyFunction()");
if (args.Length() < 1) {
- thrower.Error("Argument 0 must be a buffer source");
+ thrower.TypeError("Argument 0 must be a buffer source");
return;
}
RawBuffer buffer = GetRawBufferSource(args[0], &thrower);
@@ -167,7 +176,7 @@ void InstantiateModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
ErrorThrower thrower(isolate, "Wasm.instantiateModule()");
if (args.Length() < 1) {
- thrower.Error("Argument 0 must be a buffer source");
+ thrower.TypeError("Argument 0 must be a buffer source");
return;
}
RawBuffer buffer = GetRawBufferSource(args[0], &thrower);
@@ -191,6 +200,20 @@ static i::MaybeHandle<i::JSObject> CreateModuleObject(
i::wasm::ModuleOrigin::kWasmOrigin);
}
+bool BrandCheck(
+ Isolate* isolate, i::Handle<i::Object> value, i::Handle<i::Symbol> sym,
+ const char* msg) {
+ if (value->IsJSObject()) {
+ i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value);
+ Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym);
+ if (has_brand.IsNothing()) return false;
+ if (has_brand.ToChecked()) return true;
+ }
+ v8::Local<v8::Value> e = v8::Exception::TypeError(v8_str(isolate, msg));
+ isolate->ThrowException(e);
+ return false;
+}
+
void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate);
@@ -198,7 +221,7 @@ void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
"WebAssembly.compile()");
if (args.Length() < 1) {
- thrower.Error("Argument 0 must be a buffer source");
+ thrower.TypeError("Argument 0 must be a buffer source");
return;
}
i::MaybeHandle<i::JSObject> module_obj =
@@ -223,7 +246,7 @@ void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
"WebAssembly.Module()");
if (args.Length() < 1) {
- thrower.Error("Argument 0 must be a buffer source");
+ thrower.TypeError("Argument 0 must be a buffer source");
return;
}
i::MaybeHandle<i::JSObject> module_obj =
@@ -242,28 +265,26 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
ErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
if (args.Length() < 1) {
- thrower.Error(
- "Argument 0 must be provided, and must be a WebAssembly.Module object");
+ thrower.TypeError("Argument 0 must be a WebAssembly.Module");
return;
}
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
- i::Handle<i::Symbol> module_sym(i_context->wasm_module_sym());
- i::MaybeHandle<i::Object> source =
- i::Object::GetProperty(Utils::OpenHandle(*args[0]), module_sym);
- if (source.is_null() || source.ToHandleChecked()->IsUndefined(i_isolate)) {
- thrower.Error("Argument 0 must be a WebAssembly.Module");
+ if (!BrandCheck(isolate, Utils::OpenHandle(*args[0]),
+ i::Handle<i::Symbol>(i_context->wasm_module_sym()),
+ "Argument 0 must be a WebAssembly.Module")) {
return;
}
+
Local<Object> obj = Local<Object>::Cast(args[0]);
i::Handle<i::JSObject> module_obj =
i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
if (module_obj->GetInternalFieldCount() < 1 ||
!module_obj->GetInternalField(0)->IsFixedArray()) {
- thrower.Error("Argument 0 is an invalid WebAssembly.Module");
+ thrower.TypeError("Argument 0 is an invalid WebAssembly.Module");
return;
}
@@ -288,8 +309,237 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(Utils::ToLocal(instance.ToHandleChecked()));
}
+
+void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ v8::Isolate* isolate = args.GetIsolate();
+ HandleScope scope(isolate);
+ ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
+ "WebAssembly.Module()");
+
+ if (args.Length() < 1 || !args[0]->IsObject()) {
+ thrower.TypeError("Argument 0 must be a table descriptor");
+ return;
+ }
+ Local<Context> context = isolate->GetCurrentContext();
+ Local<v8::Object> descriptor = args[0]->ToObject(context).ToLocalChecked();
+
+ // The descriptor's 'element'.
+ {
+ v8::MaybeLocal<v8::Value> maybe =
+ descriptor->Get(context, v8_str(isolate, "element"));
+ 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, "anyfunc")).To(&equal)) return;
+ if (!equal) {
+ thrower.TypeError("Descriptor property 'element' must be 'anyfunc'");
+ return;
+ }
+ }
+
+ // The descriptor's 'initial'.
+ int initial;
+ {
+ v8::MaybeLocal<v8::Value> maybe =
+ descriptor->Get(context, v8_str(isolate, "initial"));
+ v8::Local<v8::Value> value;
+ if (!maybe.ToLocal(&value)) return;
+ int64_t number;
+ if (!value->IntegerValue(context).To(&number)) return;
+ if (number < 0) {
+ thrower.RangeError("Descriptor property 'initial' must not be negative");
+ return;
+ }
+ initial = static_cast<int>(number);
+ if (initial != number) {
+ thrower.RangeError("Descriptor property 'initial' too large");
+ return;
+ }
+ }
+
+ // The descriptor's 'maximum'.
+ Maybe<int> maximum = Nothing<int>();
+ {
+ v8::MaybeLocal<v8::Value> maybe =
+ descriptor->Get(context, v8_str(isolate, "maximum"));
+ v8::Local<v8::Value> value;
+ if (maybe.ToLocal(&value) && !value->IsUndefined()) {
+ int64_t number;
+ if (!value->IntegerValue(context).To(&number)) return;
+ if (number < 0) {
+ thrower.RangeError(
+ "Descriptor property 'maximum' must not be negative");
+ return;
+ }
+ int num = static_cast<int>(number);
+ if (num != number) {
+ thrower.RangeError("Descriptor property 'maximum' too large");
+ return;
+ }
+ if (num < initial) {
+ thrower.RangeError(
+ "Descriptor property 'maximum' must not be smaller than 'initial'");
+ return;
+ }
+ maximum = Just(num);
+ }
+ }
+
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ i::Handle<i::JSFunction> table_cons(
+ i_isolate->native_context()->wasm_table_constructor());
+ i::Handle<i::JSObject> table_obj =
+ i_isolate->factory()->NewJSObject(table_cons);
+ i::Handle<i::FixedArray> fixed_array =
+ i_isolate->factory()->NewFixedArray(initial);
+ i::Object* null = i_isolate->heap()->null_value();
+ for (int i = 0; i < initial; ++i) fixed_array->set(i, null);
+ table_obj->SetInternalField(0, *fixed_array);
+ table_obj->SetInternalField(1,
+ maximum.IsNothing()
+ ? static_cast<i::Object*>(i_isolate->heap()->undefined_value())
+ : static_cast<i::Object*>(i::Smi::FromInt(maximum.ToChecked())));
+ i::Handle<i::Symbol> table_sym(i_isolate->native_context()->wasm_table_sym());
+ i::Object::SetProperty(table_obj, table_sym, table_obj, i::STRICT).Check();
+
+ v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
+ return_value.Set(Utils::ToLocal(table_obj));
+}
+
+void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ v8::Isolate* isolate = args.GetIsolate();
+ HandleScope scope(isolate);
+ ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
+ "WebAssembly.Module()");
+
+ if (args.Length() < 1 || !args[0]->IsObject()) {
+ thrower.TypeError("Argument 0 must be a table descriptor");
+ return;
+ }
+ Local<Context> context = isolate->GetCurrentContext();
+ Local<v8::Object> descriptor = args[0]->ToObject(context).ToLocalChecked();
+
+ // The descriptor's 'initial'.
+ int initial;
+ {
+ v8::MaybeLocal<v8::Value> maybe =
+ descriptor->Get(context, v8_str(isolate, "initial"));
+ v8::Local<v8::Value> value;
+ if (!maybe.ToLocal(&value)) return;
+ int64_t number;
+ if (!value->IntegerValue(context).To(&number)) return;
+ if (number < 0) {
+ thrower.RangeError("Descriptor property 'inital' must not be negative");
+ return;
+ }
+ initial = static_cast<int>(number);
+ if (initial != number || initial > 65536) {
+ thrower.RangeError("Descriptor property 'initial' "
+ "must not be larger than 65536 (4GiB)");
+ return;
+ }
+ }
+
+ // The descriptor's 'maximum'.
+ Maybe<int> maximum = Nothing<int>();
+ {
+ v8::MaybeLocal<v8::Value> maybe =
+ descriptor->Get(context, v8_str(isolate, "maximum"));
+ v8::Local<v8::Value> value;
+ if (maybe.ToLocal(&value) && !value->IsUndefined()) {
+ int64_t number;
+ if (!value->IntegerValue(context).To(&number)) return;
+ if (number < 0) {
+ thrower.RangeError(
+ "Descriptor property 'maximum' must not be negative");
+ return;
+ }
+ int num = static_cast<int>(number);
+ if (num != number || initial > 65536) {
+ thrower.RangeError(
+ "Descriptor property 'maximum' must not be larger than 65536 (4GiB)");
+ return;
+ }
+ if (num < initial) {
+ thrower.RangeError(
+ "Descriptor property 'maximum' must not be smaller than 'initial'");
+ return;
+ }
+ maximum = Just(num);
+ }
+ }
+
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ i::Handle<i::JSFunction> memory_cons(
+ i_isolate->native_context()->wasm_memory_constructor());
+ i::Handle<i::JSObject> memory_obj =
+ i_isolate->factory()->NewJSObject(memory_cons);
+ i::Handle<i::JSArrayBuffer> buffer =
+ i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kNotShared);
+ size_t size =
+ static_cast<size_t>(i::wasm::WasmModule::kPageSize) *
+ static_cast<size_t>(initial);
+ i::JSArrayBuffer::SetupAllocatingData(buffer, i_isolate, size);
+ memory_obj->SetInternalField(0, *buffer);
+ memory_obj->SetInternalField(1,
+ maximum.IsNothing()
+ ? static_cast<i::Object*>(i_isolate->heap()->undefined_value())
+ : static_cast<i::Object*>(i::Smi::FromInt(maximum.ToChecked())));
+ i::Handle<i::Symbol> memory_sym(
+ i_isolate->native_context()->wasm_memory_sym());
+ i::Object::SetProperty(memory_obj, memory_sym, memory_obj, i::STRICT).Check();
+
+ v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
+ return_value.Set(Utils::ToLocal(memory_obj));
+}
+
+void WebAssemblyTableGetLength(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ // TODO(rossberg)
+}
+
+void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ // TODO(rossberg)
+}
+
+void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ // TODO(rossberg)
+}
+
+void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ // TODO(rossberg)
+}
+
+void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ // TODO(rossberg)
+}
+
+void WebAssemblyMemoryGetBuffer(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ v8::Isolate* isolate = args.GetIsolate();
+ Local<Context> context = isolate->GetCurrentContext();
+ i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
+
+ if (!BrandCheck(isolate, Utils::OpenHandle(*args.This()),
+ i::Handle<i::Symbol>(i_context->wasm_memory_sym()),
+ "Receiver is not a WebAssembly.Memory")) {
+ return;
+ }
+
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ i::Handle<i::JSObject> receiver =
+ i::Handle<i::JSObject>::cast(Utils::OpenHandle(*args.This()));
+ i::Handle<i::Object> buffer(receiver->GetInternalField(0), i_isolate);
+ DCHECK(buffer->IsJSArrayBuffer());
+
+ v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
+ return_value.Set(Utils::ToLocal(buffer));
+}
} // namespace
+
// TODO(titzer): we use the API to create the function template because the
// internal guts are too ugly to replicate here.
static i::Handle<i::FunctionTemplateInfo> NewTemplate(i::Isolate* i_isolate,
@@ -300,11 +550,7 @@ static i::Handle<i::FunctionTemplateInfo> NewTemplate(i::Isolate* i_isolate,
}
namespace internal {
-static Handle<String> v8_str(Isolate* isolate, const char* str) {
- return isolate->factory()->NewStringFromAsciiChecked(str);
-}
-
-static Handle<JSFunction> InstallFunc(Isolate* isolate, Handle<JSObject> object,
+Handle<JSFunction> InstallFunc(Isolate* isolate, Handle<JSObject> object,
const char* str, FunctionCallback func) {
Handle<String> name = v8_str(isolate, str);
Handle<FunctionTemplateInfo> temp = NewTemplate(isolate, func);
@@ -316,21 +562,41 @@ static Handle<JSFunction> InstallFunc(Isolate* isolate, Handle<JSObject> object,
return function;
}
+Handle<JSFunction> InstallGetter(
+ Isolate* isolate, Handle<JSObject> object,
+ const char* str, FunctionCallback func) {
+ Handle<String> name = v8_str(isolate, str);
+ Handle<FunctionTemplateInfo> temp = NewTemplate(isolate, func);
+ Handle<JSFunction> function =
+ ApiNatives::InstantiateFunction(temp).ToHandleChecked();
+ v8::PropertyAttribute attributes =
+ static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly);
+ Utils::ToLocal(object)->SetAccessorProperty(
+ Utils::ToLocal(name), Utils::ToLocal(function),
+ Local<Function>(), attributes);
+ return function;
+}
+
void WasmJs::SetupIsolateForWasm(Isolate* isolate) {
- InstallWasmFunctionMap(isolate, isolate->native_context());
- InstallWasmModuleSymbol(isolate, isolate->global_object(),
+ InstallWasmMaps(isolate, isolate->native_context());
+ InstallWasmConstructors(isolate, isolate->global_object(),
isolate->native_context());
}
-void WasmJs::InstallWasmModuleSymbol(Isolate* isolate,
+void WasmJs::InstallWasmConstructors(Isolate* isolate,
Handle<JSGlobalObject> global,
Handle<Context> context) {
Factory* factory = isolate->factory();
+
// Create private symbols.
Handle<Symbol> module_sym = factory->NewPrivateSymbol();
Handle<Symbol> instance_sym = factory->NewPrivateSymbol();
+ Handle<Symbol> table_sym = factory->NewPrivateSymbol();
+ Handle<Symbol> memory_sym = factory->NewPrivateSymbol();
context->set_wasm_module_sym(*module_sym);
context->set_wasm_instance_sym(*instance_sym);
+ context->set_wasm_table_sym(*table_sym);
+ context->set_wasm_memory_sym(*memory_sym);
// Bind the WebAssembly object.
Handle<String> name = v8_str(isolate, "WebAssembly");
@@ -348,13 +614,50 @@ void WasmJs::InstallWasmModuleSymbol(Isolate* isolate,
InstallFunc(isolate, wasm_object, "Module", WebAssemblyModule);
Handle<JSFunction> instance_constructor =
InstallFunc(isolate, wasm_object, "Instance", WebAssemblyInstance);
- i::Handle<i::Map> map = isolate->factory()->NewMap(
- i::JS_OBJECT_TYPE, i::JSObject::kHeaderSize + i::kPointerSize);
- module_constructor->set_prototype_or_initial_map(*map);
- map->SetConstructor(*module_constructor);
-
+ Handle<JSFunction> table_constructor =
+ InstallFunc(isolate, wasm_object, "Table", WebAssemblyTable);
+ Handle<JSFunction> memory_constructor =
+ InstallFunc(isolate, wasm_object, "Memory", WebAssemblyMemory);
context->set_wasm_module_constructor(*module_constructor);
context->set_wasm_instance_constructor(*instance_constructor);
+ context->set_wasm_table_constructor(*table_constructor);
+ context->set_wasm_memory_constructor(*memory_constructor);
+
+ // Set up prototypes and instance maps.
+ Handle<JSObject> module_proto =
+ factory->NewJSObject(module_constructor, TENURED);
+ i::Handle<i::Map> map = isolate->factory()->NewMap(
+ i::JS_OBJECT_TYPE, i::JSObject::kHeaderSize + i::kPointerSize);
+ JSFunction::SetInitialMap(module_constructor, map, module_proto);
+
+ Handle<JSObject> table_proto =
+ factory->NewJSObject(table_constructor, TENURED);
+ map = isolate->factory()->NewMap(
+ i::JS_OBJECT_TYPE, i::JSObject::kHeaderSize + 2*i::kPointerSize);
+ JSFunction::SetInitialMap(table_constructor, map, table_proto);
+
+ Handle<JSObject> memory_proto =
+ factory->NewJSObject(memory_constructor, TENURED);
+ map = isolate->factory()->NewMap(
+ i::JS_OBJECT_TYPE, i::JSObject::kHeaderSize + 2*i::kPointerSize);
+ JSFunction::SetInitialMap(memory_constructor, map, memory_proto);
+
+ // Add prototype properties.
+ JSObject::AddProperty(module_proto, isolate->factory()->constructor_string(),
+ module_constructor, DONT_ENUM);
+
+ JSObject::AddProperty(table_proto, isolate->factory()->constructor_string(),
+ table_constructor, DONT_ENUM);
+
+ InstallGetter(isolate, table_proto, "length", WebAssemblyTableGetLength);
+ InstallFunc(isolate, table_proto, "grow", WebAssemblyTableGrow);
+ InstallFunc(isolate, table_proto, "get", WebAssemblyTableGet);
+ InstallFunc(isolate, table_proto, "set", WebAssemblyTableSet);
+
+ JSObject::AddProperty(memory_proto, isolate->factory()->constructor_string(),
+ memory_constructor, DONT_ENUM);
+ InstallFunc(isolate, memory_proto, "grow", WebAssemblyMemoryGrow);
+ InstallGetter(isolate, memory_proto, "buffer", WebAssemblyMemoryGetBuffer);
}
void WasmJs::Install(Isolate* isolate, Handle<JSGlobalObject> global) {
@@ -366,7 +669,7 @@ void WasmJs::Install(Isolate* isolate, Handle<JSGlobalObject> global) {
// Setup wasm function map.
Handle<Context> context(global->native_context(), isolate);
- InstallWasmFunctionMap(isolate, context);
+ InstallWasmMaps(isolate, context);
if (!FLAG_expose_wasm) {
return;
@@ -399,10 +702,10 @@ void WasmJs::Install(Isolate* isolate, Handle<JSGlobalObject> global) {
JSObject::AddProperty(wasm_object, name, value, attributes);
}
}
- InstallWasmModuleSymbol(isolate, global, context);
+ InstallWasmConstructors(isolate, global, context);
}
-void WasmJs::InstallWasmFunctionMap(Isolate* isolate, Handle<Context> context) {
+void WasmJs::InstallWasmMaps(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?
« no previous file with comments | « src/wasm/wasm-js.h ('k') | src/wasm/wasm-result.h » ('j') | src/wasm/wasm-result.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698