Commit df834f3f authored by titzer's avatar titzer Committed by Commit bot

[wasm] Split the compilation and instantiation API into sync and async methods.

This makes it easier to implement asynchronous compilation by hiding all the implementation details of both synchronous and asynchronous compilation within wasm-module.cc, whereas before the code in wasm-js.cc actually implemented asynchronous compilation in terms of synchronous.

BUG=

Review-Url: https://codereview.chromium.org/2695813005
Cr-Commit-Position: refs/heads/master@{#43310}
parent db624fc4
......@@ -7599,11 +7599,8 @@ MaybeLocal<WasmCompiledModule> WasmCompiledModule::Compile(Isolate* isolate,
size_t length) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::wasm::ErrorThrower thrower(i_isolate, "WasmCompiledModule::Deserialize()");
i::MaybeHandle<i::JSObject> maybe_compiled =
i::wasm::CreateModuleObjectFromBytes(
i_isolate, start, start + length, &thrower,
i::wasm::ModuleOrigin::kWasmOrigin, i::Handle<i::Script>::null(),
i::Vector<const uint8_t>::empty());
i::MaybeHandle<i::JSObject> maybe_compiled = i::wasm::SyncCompile(
i_isolate, &thrower, i::wasm::ModuleWireBytes(start, start + length));
if (maybe_compiled.is_null()) return MaybeLocal<WasmCompiledModule>();
return Local<WasmCompiledModule>::Cast(
Utils::ToLocal(maybe_compiled.ToHandleChecked()));
......
......@@ -110,7 +110,8 @@ class RegisteredExtension {
V(Proxy, JSProxy) \
V(NativeWeakMap, JSWeakMap) \
V(debug::GeneratorObject, JSGeneratorObject) \
V(debug::Script, Script)
V(debug::Script, Script) \
V(Promise, JSPromise)
class Utils {
public:
......
......@@ -188,9 +188,10 @@ MaybeHandle<FixedArray> AsmJs::CompileAsmViaWasm(CompilationInfo* info) {
base::ElapsedTimer compile_timer;
compile_timer.Start();
MaybeHandle<JSObject> compiled = wasm::CreateModuleObjectFromBytes(
info->isolate(), module->begin(), module->end(), &thrower,
internal::wasm::kAsmJsOrigin, info->script(), asm_offsets_vec);
MaybeHandle<JSObject> compiled = SyncCompileTranslatedAsmJs(
info->isolate(), &thrower,
wasm::ModuleWireBytes(module->begin(), module->end()), info->script(),
asm_offsets_vec);
DCHECK(!compiled.is_null());
double compile_time = compile_timer.Elapsed().InMillisecondsF();
DCHECK_GE(module->end(), module->begin());
......@@ -276,8 +277,7 @@ MaybeHandle<Object> AsmJs::InstantiateAsmWasm(i::Isolate* isolate,
}
i::MaybeHandle<i::Object> maybe_module_object =
i::wasm::WasmModule::Instantiate(isolate, &thrower, module, ffi_object,
memory);
i::wasm::SyncInstantiate(isolate, &thrower, module, ffi_object, memory);
if (maybe_module_object.is_null()) {
return MaybeHandle<Object>();
}
......
......@@ -1624,10 +1624,8 @@ MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
MaybeHandle<JSObject> result;
{
wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule");
result = wasm::CreateModuleObjectFromBytes(
isolate_, wire_bytes.begin(), wire_bytes.end(), &thrower,
wasm::ModuleOrigin::kWasmOrigin, Handle<Script>::null(),
Vector<const byte>::empty());
result = wasm::SyncCompile(isolate_, &thrower,
wasm::ModuleWireBytes(wire_bytes));
}
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
return result;
......
......@@ -31,6 +31,20 @@ using v8::internal::wasm::ErrorThrower;
namespace v8 {
namespace {
// TODO(wasm): move brand check to the respective types, and don't throw
// in it, rather, use a provided ErrorThrower, or let caller handle it.
static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> sym) {
if (!value->IsJSObject()) return false;
i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value);
Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym);
return has_brand.FromMaybe(false);
}
static bool BrandCheck(i::Handle<i::Object> value, i::Handle<i::Symbol> sym,
ErrorThrower* thrower, const char* msg) {
return HasBrand(value, sym) ? true : (thrower->TypeError("%s", msg), false);
}
i::Handle<i::String> v8_str(i::Isolate* isolate, const char* str) {
return isolate->factory()->NewStringFromAsciiChecked(str);
}
......@@ -38,17 +52,37 @@ 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;
size_t size() { return static_cast<size_t>(end - start); }
};
i::MaybeHandle<i::WasmModuleObject> GetFirstArgumentAsModule(
const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
v8::Isolate* isolate = args.GetIsolate();
if (args.Length() < 1) {
thrower->TypeError("Argument 0 must be a WebAssembly.Module");
return {};
}
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
if (!BrandCheck(Utils::OpenHandle(*args[0]),
i::handle(i_context->wasm_module_sym()), thrower,
"Argument 0 must be a WebAssembly.Module")) {
return {};
}
Local<Object> module_obj = Local<Object>::Cast(args[0]);
return i::Handle<i::WasmModuleObject>::cast(
v8::Utils::OpenHandle(*module_obj));
}
i::wasm::ModuleWireBytes GetFirstArgumentAsBytes(
const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
if (args.Length() < 1) {
thrower->TypeError("Argument 0 must be a buffer source");
return i::wasm::ModuleWireBytes(nullptr, nullptr);
}
RawBuffer GetRawBufferSource(
v8::Local<v8::Value> source, ErrorThrower* thrower) {
const byte* start = nullptr;
const byte* end = nullptr;
v8::Local<v8::Value> source = args[0];
if (source->IsArrayBuffer()) {
// A raw array buffer was passed.
Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(source);
......@@ -74,58 +108,29 @@ RawBuffer GetRawBufferSource(
if (start == nullptr || end == start) {
thrower->CompileError("BufferSource argument is empty");
}
return {start, end};
// TODO(titzer): use the handle as well?
return i::wasm::ModuleWireBytes(start, end);
}
static i::MaybeHandle<i::WasmModuleObject> CreateModuleObject(
v8::Isolate* isolate, const v8::Local<v8::Value> source,
ErrorThrower* thrower) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::MaybeHandle<i::JSObject> nothing;
RawBuffer buffer = GetRawBufferSource(source, thrower);
if (buffer.start == nullptr) return i::MaybeHandle<i::WasmModuleObject>();
DCHECK(source->IsArrayBuffer() || source->IsTypedArray());
return i::wasm::CreateModuleObjectFromBytes(
i_isolate, buffer.start, buffer.end, thrower, i::wasm::kWasmOrigin,
i::Handle<i::Script>::null(), i::Vector<const byte>::empty());
}
static bool ValidateModule(v8::Isolate* isolate,
const v8::Local<v8::Value> source,
ErrorThrower* thrower) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::MaybeHandle<i::JSObject> nothing;
RawBuffer buffer = GetRawBufferSource(source, thrower);
if (buffer.start == nullptr) return false;
DCHECK(source->IsArrayBuffer() || source->IsTypedArray());
return i::wasm::ValidateModuleBytes(i_isolate, buffer.start, buffer.end,
thrower,
i::wasm::ModuleOrigin::kWasmOrigin);
}
// TODO(wasm): move brand check to the respective types, and don't throw
// in it, rather, use a provided ErrorThrower, or let caller handle it.
static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> sym) {
if (!value->IsJSObject()) return false;
i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value);
Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym);
return !has_brand.IsNothing() && has_brand.ToChecked();
}
i::MaybeHandle<i::JSReceiver> GetSecondArgumentAsImports(
const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
if (args.Length() < 2) return {};
if (args[1]->IsUndefined()) return {};
static bool BrandCheck(ErrorThrower* thrower, i::Handle<i::Object> value,
i::Handle<i::Symbol> sym, const char* msg) {
return HasBrand(value, sym) ? true : (thrower->TypeError("%s", msg), false);
if (!args[1]->IsObject()) {
thrower->TypeError("Argument 1 must be an object");
return {};
}
Local<Object> obj = Local<Object>::Cast(args[1]);
return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
}
// WebAssembly.compile(bytes) -> Promise
void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
"WebAssembly.compile()");
ErrorThrower thrower(i_isolate, "WebAssembly.compile()");
Local<Context> context = isolate->GetCurrentContext();
v8::Local<v8::Promise::Resolver> resolver;
......@@ -133,34 +138,28 @@ void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(resolver->GetPromise());
if (args.Length() < 1) {
thrower.TypeError("Argument 0 must be a buffer source");
resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
return;
}
i::MaybeHandle<i::JSObject> module_obj =
CreateModuleObject(isolate, args[0], &thrower);
auto bytes = GetFirstArgumentAsBytes(args, &thrower);
if (thrower.error()) {
resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
} else {
resolver->Resolve(context, Utils::ToLocal(module_obj.ToHandleChecked()));
return;
}
i::Handle<i::JSPromise> promise = Utils::OpenHandle(*resolver->GetPromise());
i::wasm::AsyncCompile(i_isolate, promise, bytes);
}
// WebAssembly.validate(bytes) -> bool
void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
"WebAssembly.validate()");
ErrorThrower thrower(i_isolate, "WebAssembly.validate()");
if (args.Length() < 1) {
thrower.TypeError("Argument 0 must be a buffer source");
return;
}
auto bytes = GetFirstArgumentAsBytes(args, &thrower);
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
if (ValidateModule(isolate, args[0], &thrower)) {
if (!thrower.error() &&
i::wasm::SyncValidate(reinterpret_cast<i::Isolate*>(isolate), &thrower,
bytes)) {
return_value.Set(v8::True(isolate));
} else {
if (thrower.wasm_error()) thrower.Reify(); // Clear error.
......@@ -168,84 +167,25 @@ void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
}
// new WebAssembly.Module(bytes) -> WebAssembly.Module
void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
"WebAssembly.Module()");
ErrorThrower thrower(i_isolate, "WebAssembly.Module()");
if (args.Length() < 1) {
thrower.TypeError("Argument 0 must be a buffer source");
return;
}
auto bytes = GetFirstArgumentAsBytes(args, &thrower);
if (thrower.error()) return;
i::MaybeHandle<i::JSObject> module_obj =
CreateModuleObject(isolate, args[0], &thrower);
i::MaybeHandle<i::Object> module_obj =
i::wasm::SyncCompile(i_isolate, &thrower, bytes);
if (module_obj.is_null()) return;
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(Utils::ToLocal(module_obj.ToHandleChecked()));
}
MaybeLocal<Value> InstantiateModuleImpl(
i::Isolate* i_isolate, i::Handle<i::WasmModuleObject> i_module_obj,
const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
// It so happens that in both the WebAssembly.instantiate, as well as
// WebAssembly.Instance ctor, the positions of the ffi object and memory
// are the same. If that changes later, we refactor the consts into
// parameters.
static const int kFfiOffset = 1;
MaybeLocal<Value> nothing;
i::Handle<i::JSReceiver> ffi = i::Handle<i::JSObject>::null();
// This is a first - level validation of the argument. If present, we only
// check its type. {Instantiate} will further check that if the module
// has imports, the argument must be present, as well as piecemeal
// import satisfaction.
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::MaybeHandle<i::JSObject> instance =
i::wasm::WasmModule::Instantiate(i_isolate, thrower, i_module_obj, ffi);
if (instance.is_null()) {
if (!thrower->error())
thrower->RuntimeError("Could not instantiate module");
return nothing;
}
DCHECK(!i_isolate->has_pending_exception());
return Utils::ToLocal(instance.ToHandleChecked());
}
namespace {
i::MaybeHandle<i::WasmModuleObject> GetFirstArgumentAsModule(
const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
v8::Isolate* isolate = args.GetIsolate();
i::MaybeHandle<i::WasmModuleObject> nothing;
if (args.Length() < 1) {
thrower->TypeError("Argument 0 must be a WebAssembly.Module");
return nothing;
}
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
if (!BrandCheck(thrower, Utils::OpenHandle(*args[0]),
i::Handle<i::Symbol>(i_context->wasm_module_sym()),
"Argument 0 must be a WebAssembly.Module")) {
return nothing;
}
Local<Object> module_obj = Local<Object>::Cast(args[0]);
return i::Handle<i::WasmModuleObject>::cast(
v8::Utils::OpenHandle(*module_obj));
}
} // namespace
// WebAssembly.Module.imports(module) -> Array<Import>
void WebAssemblyModuleImports(const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(args.GetIsolate());
v8::Isolate* isolate = args.GetIsolate();
......@@ -253,14 +193,12 @@ void WebAssemblyModuleImports(const v8::FunctionCallbackInfo<v8::Value>& args) {
ErrorThrower thrower(i_isolate, "WebAssembly.Module.imports()");
auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
if (!maybe_module.is_null()) {
auto imports =
i::wasm::GetImports(i_isolate, maybe_module.ToHandleChecked());
args.GetReturnValue().Set(Utils::ToLocal(imports));
}
if (thrower.error()) return;
auto imports = i::wasm::GetImports(i_isolate, maybe_module.ToHandleChecked());
args.GetReturnValue().Set(Utils::ToLocal(imports));
}
// WebAssembly.Module.exports(module) -> Array<Export>
void WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(args.GetIsolate());
v8::Isolate* isolate = args.GetIsolate();
......@@ -268,14 +206,12 @@ void WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value>& args) {
ErrorThrower thrower(i_isolate, "WebAssembly.Module.exports()");
auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
if (!maybe_module.is_null()) {
auto exports =
i::wasm::GetExports(i_isolate, maybe_module.ToHandleChecked());
args.GetReturnValue().Set(Utils::ToLocal(exports));
}
if (thrower.error()) return;
auto exports = i::wasm::GetExports(i_isolate, maybe_module.ToHandleChecked());
args.GetReturnValue().Set(Utils::ToLocal(exports));
}
// WebAssembly.Module.customSections(module, name) -> Array<Section>
void WebAssemblyModuleCustomSections(
const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(args.GetIsolate());
......@@ -284,6 +220,7 @@ void WebAssemblyModuleCustomSections(
ErrorThrower thrower(i_isolate, "WebAssembly.Module.customSections()");
auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
if (thrower.error()) return;
if (args.Length() < 2) {
thrower.TypeError("Argument 1 must be a string");
......@@ -296,16 +233,14 @@ void WebAssemblyModuleCustomSections(
return;
}
if (!maybe_module.is_null()) {
auto custom_sections =
i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(),
i::Handle<i::String>::cast(name), &thrower);
if (!thrower.error()) {
args.GetReturnValue().Set(Utils::ToLocal(custom_sections));
}
}
auto custom_sections =
i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(),
i::Handle<i::String>::cast(name), &thrower);
if (thrower.error()) return;
args.GetReturnValue().Set(Utils::ToLocal(custom_sections));
}
// new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(args.GetIsolate());
v8::Isolate* isolate = args.GetIsolate();
......@@ -313,19 +248,21 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
ErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
if (thrower.error()) return;
if (!maybe_module.is_null()) {
MaybeLocal<Value> instance = InstantiateModuleImpl(
i_isolate, maybe_module.ToHandleChecked(), args, &thrower);
auto maybe_imports = GetSecondArgumentAsImports(args, &thrower);
if (thrower.error()) return;
if (instance.IsEmpty()) {
DCHECK(thrower.error());
return;
}
args.GetReturnValue().Set(instance.ToLocalChecked());
}
i::MaybeHandle<i::Object> instance_object = i::wasm::SyncInstantiate(
i_isolate, &thrower, maybe_module.ToHandleChecked(), maybe_imports,
i::MaybeHandle<i::JSArrayBuffer>());
if (instance_object.is_null()) return;
args.GetReturnValue().Set(Utils::ToLocal(instance_object.ToHandleChecked()));
}
// WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
// WebAssembly.instantiate(bytes, imports) ->
// {module: WebAssembly.Module, instance: WebAssembly.Instance}
void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
......@@ -356,50 +293,28 @@ void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
return;
}
bool want_pair =
!HasBrand(first_arg, i::Handle<i::Symbol>(i_context->wasm_module_sym()));
i::Handle<i::WasmModuleObject> module_obj;
if (want_pair) {
i::MaybeHandle<i::WasmModuleObject> maybe_module_obj =
CreateModuleObject(isolate, args[0], &thrower);
if (!maybe_module_obj.ToHandle(&module_obj)) {
DCHECK(thrower.error());
resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
return;
}
} else {
module_obj = i::Handle<i::WasmModuleObject>::cast(first_arg);
}
DCHECK(!module_obj.is_null());
MaybeLocal<Value> instance =
InstantiateModuleImpl(i_isolate, module_obj, args, &thrower);
if (instance.IsEmpty()) {
DCHECK(thrower.error());
auto maybe_imports = GetSecondArgumentAsImports(args, &thrower);
if (thrower.error()) {
resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
return;
}
i::Handle<i::JSPromise> promise = Utils::OpenHandle(*resolver->GetPromise());
if (HasBrand(first_arg, i::Handle<i::Symbol>(i_context->wasm_module_sym()))) {
// WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
auto module_object = GetFirstArgumentAsModule(args, &thrower);
i::wasm::AsyncInstantiate(i_isolate, promise,
module_object.ToHandleChecked(), maybe_imports);
} else {
DCHECK(!thrower.error());
Local<Value> retval;
if (want_pair) {
i::Handle<i::JSFunction> object_function = i::Handle<i::JSFunction>(
i_isolate->native_context()->object_function(), i_isolate);
i::Handle<i::JSObject> i_retval =
i_isolate->factory()->NewJSObject(object_function, i::TENURED);
i::Handle<i::String> module_property_name =
i_isolate->factory()->InternalizeUtf8String("module");
i::Handle<i::String> instance_property_name =
i_isolate->factory()->InternalizeUtf8String("instance");
i::JSObject::AddProperty(i_retval, module_property_name, module_obj,
i::NONE);
i::JSObject::AddProperty(i_retval, instance_property_name,
Utils::OpenHandle(*instance.ToLocalChecked()),
i::NONE);
retval = Utils::ToLocal(i_retval);
} else {
retval = instance.ToLocalChecked();
// WebAssembly.instantiate(bytes, imports) -> {module, instance}
auto bytes = GetFirstArgumentAsBytes(args, &thrower);
if (thrower.error()) {
resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
return;
}
DCHECK(!retval.IsEmpty());
resolver->Resolve(context, retval);
i::wasm::AsyncCompileAndInstantiate(i_isolate, promise, bytes,
maybe_imports);
}
}
......@@ -430,11 +345,12 @@ bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
return false;
}
// new WebAssembly.Table(args) -> WebAssembly.Table
void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
"WebAssembly.Module()");
ErrorThrower thrower(i_isolate, "WebAssembly.Module()");
if (args.Length() < 1 || !args[0]->IsObject()) {
thrower.TypeError("Argument 0 must be a table descriptor");
return;
......@@ -476,7 +392,6 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
}
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::FixedArray> fixed_array;
i::Handle<i::JSObject> table_obj =
i::WasmTableObject::New(i_isolate, initial, maximum, &fixed_array);
......@@ -486,9 +401,9 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
"WebAssembly.Memory()");
ErrorThrower thrower(i_isolate, "WebAssembly.Memory()");
if (args.Length() < 1 || !args[0]->IsObject()) {
thrower.TypeError("Argument 0 must be a memory descriptor");
return;
......@@ -514,7 +429,6 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
}
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
size_t size = static_cast<size_t>(i::wasm::WasmModule::kPageSize) *
static_cast<size_t>(initial);
i::Handle<i::JSArrayBuffer> buffer =
......@@ -531,12 +445,13 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
void WebAssemblyTableGetLength(
const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
"WebAssembly.Table.length()");
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(i_isolate, "WebAssembly.Table.length()");
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_table_sym()),
if (!BrandCheck(Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_table_sym()), &thrower,
"Receiver is not a WebAssembly.Table")) {
return;
}
......@@ -546,19 +461,20 @@ void WebAssemblyTableGetLength(
v8::Number::New(isolate, receiver->current_length()));
}
// WebAssembly.Table.grow(num) -> num
void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
"WebAssembly.Table.grow()");
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(i_isolate, "WebAssembly.Table.grow()");
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_table_sym()),
if (!BrandCheck(Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_table_sym()), &thrower,
"Receiver is not a WebAssembly.Table")) {
return;
}
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
auto receiver =
i::Handle<i::WasmTableObject>::cast(Utils::OpenHandle(*args.This()));
i::Handle<i::FixedArray> old_array(receiver->functions(), i_isolate);
......@@ -599,14 +515,16 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
return_value.Set(old_size);
}
// WebAssembly.Table.get(num) -> JSFunction
void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(i_isolate, "WebAssembly.Table.get()");
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_table_sym()),
if (!BrandCheck(Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_table_sym()), &thrower,
"Receiver is not a WebAssembly.Table")) {
return;
}
......@@ -626,14 +544,16 @@ void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
return_value.Set(Utils::ToLocal(value));
}
// WebAssembly.Table.set(num, JSFunction)
void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(i_isolate, "WebAssembly.Table.set()");
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_table_sym()),
if (!BrandCheck(Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_table_sym()), &thrower,
"Receiver is not a WebAssembly.Table")) {
return;
}
......@@ -673,14 +593,16 @@ void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
i::Handle<i::FixedArray>::cast(array)->set(i, *value);
}
// WebAssembly.Memory.grow(num) -> num
void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(i_isolate, "WebAssembly.Memory.grow()");
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_memory_sym()),
if (!BrandCheck(Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_memory_sym()), &thrower,
"Receiver is not a WebAssembly.Memory")) {
return;
}
......@@ -715,15 +637,17 @@ void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
return_value.Set(ret);
}
// WebAssembly.Memory.buffer -> ArrayBuffer
void WebAssemblyMemoryGetBuffer(
const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ErrorThrower thrower(i_isolate, "WebAssembly.Memory.buffer");
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_memory_sym()),
if (!BrandCheck(Utils::OpenHandle(*args.This()),
i::Handle<i::Symbol>(i_context->wasm_memory_sym()), &thrower,
"Receiver is not a WebAssembly.Memory")) {
return;
}
......
......@@ -898,23 +898,23 @@ int wasm::GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module,
WasmModule::WasmModule(Zone* owned)
: owned_zone(owned), pending_tasks(new base::Semaphore(0)) {}
MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
Isolate* isolate, Handle<WasmModuleWrapper> module_wrapper,
ErrorThrower* thrower, const ModuleWireBytes& wire_bytes,
Handle<Script> asm_js_script,
Vector<const byte> asm_js_offset_table_bytes) const {
MaybeHandle<WasmModuleObject> CompileToModuleObject(
Isolate* isolate, WasmModule* m, ErrorThrower* thrower,
const ModuleWireBytes& wire_bytes, Handle<Script> asm_js_script,
Vector<const byte> asm_js_offset_table_bytes) {
Factory* factory = isolate->factory();
MaybeHandle<WasmCompiledModule> nothing;
WasmInstance temp_instance(this);
MaybeHandle<WasmModuleObject> nothing;
// The {module_wrapper} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object.
Handle<WasmModuleWrapper> module_wrapper = WasmModuleWrapper::New(isolate, m);
WasmInstance temp_instance(m);
temp_instance.context = isolate->native_context();
temp_instance.mem_size = WasmModule::kPageSize * min_mem_pages;
temp_instance.mem_size = WasmModule::kPageSize * m->min_mem_pages;
temp_instance.mem_start = nullptr;
temp_instance.globals_start = nullptr;
// Initialize the indirect tables with placeholders.
int function_table_count = static_cast<int>(function_tables.size());
int function_table_count = static_cast<int>(m->function_tables.size());
Handle<FixedArray> function_tables =
factory->NewFixedArray(function_table_count, TENURED);
Handle<FixedArray> signature_tables =
......@@ -929,25 +929,25 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
HistogramTimerScope wasm_compile_module_time_scope(
isolate->counters()->wasm_compile_module_time());
ModuleBytesEnv module_env(this, &temp_instance, wire_bytes);
ModuleBytesEnv module_env(m, &temp_instance, wire_bytes);
// The {code_table} array contains import wrappers and functions (which
// are both included in {functions.size()}, and export wrappers.
int code_table_size =
static_cast<int>(functions.size() + num_exported_functions);
static_cast<int>(m->functions.size() + m->num_exported_functions);
Handle<FixedArray> code_table =
factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
// Initialize the code table with the illegal builtin. All call sites will be
// patched at instantiation.
Handle<Code> illegal_builtin = isolate->builtins()->Illegal();
for (uint32_t i = 0; i < functions.size(); ++i) {
for (uint32_t i = 0; i < m->functions.size(); ++i) {
code_table->set(static_cast<int>(i), *illegal_builtin);
temp_instance.function_code[i] = illegal_builtin;
}
isolate->counters()->wasm_functions_per_module()->AddSample(
static_cast<int>(functions.size()));
static_cast<int>(m->functions.size()));
if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) {
// Avoid a race condition by collecting results into a second vector.
std::vector<Handle<Code>> results(temp_instance.function_code);
......@@ -1002,39 +1002,40 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
// and information needed at instantiation time. This object needs to be
// serializable. Instantiation may occur off a deserialized version of this
// object.
Handle<WasmCompiledModule> ret = WasmCompiledModule::New(isolate, shared);
ret->set_num_imported_functions(num_imported_functions);
ret->set_code_table(code_table);
ret->set_min_mem_pages(min_mem_pages);
ret->set_max_mem_pages(max_mem_pages);
Handle<WasmCompiledModule> compiled_module =
WasmCompiledModule::New(isolate, shared);
compiled_module->set_num_imported_functions(m->num_imported_functions);
compiled_module->set_code_table(code_table);
compiled_module->set_min_mem_pages(m->min_mem_pages);
compiled_module->set_max_mem_pages(m->max_mem_pages);
if (function_table_count > 0) {
ret->set_function_tables(function_tables);
ret->set_signature_tables(signature_tables);
ret->set_empty_function_tables(function_tables);
compiled_module->set_function_tables(function_tables);
compiled_module->set_signature_tables(signature_tables);
compiled_module->set_empty_function_tables(function_tables);
}
// If we created a wasm script, finish it now and make it public to the
// debugger.
if (asm_js_script.is_null()) {
script->set_wasm_compiled_module(*ret);
script->set_wasm_compiled_module(*compiled_module);
isolate->debug()->OnAfterCompile(script);
}
// Compile JS->WASM wrappers for exported functions.
int func_index = 0;
for (auto exp : export_table) {
for (auto exp : m->export_table) {
if (exp.kind != kExternalFunction) continue;
Handle<Code> wasm_code =
code_table->GetValueChecked<Code>(isolate, exp.index);
Handle<Code> wrapper_code =
compiler::CompileJSToWasmWrapper(isolate, this, wasm_code, exp.index);
int export_index = static_cast<int>(functions.size() + func_index);
compiler::CompileJSToWasmWrapper(isolate, m, wasm_code, exp.index);
int export_index = static_cast<int>(m->functions.size() + func_index);
code_table->set(export_index, *wrapper_code);
RecordStats(isolate, *wrapper_code);
func_index++;
}
return ret;
return WasmModuleObject::New(isolate, compiled_module);
}
static WasmFunction* GetWasmFunctionForImportWrapper(Isolate* isolate,
......@@ -1139,17 +1140,20 @@ void wasm::UpdateDispatchTables(Isolate* isolate,
// A helper class to simplify instantiating a module from a compiled module.
// It closes over the {Isolate}, the {ErrorThrower}, the {WasmCompiledModule},
// etc.
class WasmInstanceBuilder {
class InstantiationHelper {
public:
WasmInstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
InstantiationHelper(Isolate* isolate, ErrorThrower* thrower,
Handle<WasmModuleObject> module_object,
Handle<JSReceiver> ffi, Handle<JSArrayBuffer> memory)
MaybeHandle<JSReceiver> ffi,
MaybeHandle<JSArrayBuffer> memory)
: isolate_(isolate),
module_(module_object->compiled_module()->module()),
thrower_(thrower),
module_object_(module_object),
ffi_(ffi),
memory_(memory) {}
ffi_(ffi.is_null() ? Handle<JSReceiver>::null()
: ffi.ToHandleChecked()),
memory_(memory.is_null() ? Handle<JSArrayBuffer>::null()
: memory.ToHandleChecked()) {}
// Build an instance, in all of its glory.
MaybeHandle<WasmInstanceObject> Build() {
......@@ -1526,8 +1530,8 @@ class WasmInstanceBuilder {
WasmModule* const module_;
ErrorThrower* thrower_;
Handle<WasmModuleObject> module_object_;
Handle<JSReceiver> ffi_;
Handle<JSArrayBuffer> memory_;
Handle<JSReceiver> ffi_; // TODO(titzer): Use MaybeHandle
Handle<JSArrayBuffer> memory_; // TODO(titzer): Use MaybeHandle
Handle<JSArrayBuffer> globals_;
Handle<WasmCompiledModule> compiled_module_;
std::vector<TableInstance> table_instances_;
......@@ -2243,16 +2247,6 @@ class WasmInstanceBuilder {
}
};
// Instantiates a WASM module, creating a WebAssembly.Instance from a
// WebAssembly.Module.
MaybeHandle<WasmInstanceObject> WasmModule::Instantiate(
Isolate* isolate, ErrorThrower* thrower,
Handle<WasmModuleObject> wasm_module, Handle<JSReceiver> ffi,
Handle<JSArrayBuffer> memory) {
WasmInstanceBuilder builder(isolate, thrower, wasm_module, ffi, memory);
return builder.Build();
}
bool wasm::IsWasmInstance(Object* object) {
return WasmInstanceObject::IsWasmInstanceObject(object);
}
......@@ -2268,57 +2262,6 @@ bool wasm::IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
isolate->allow_code_gen_callback()(v8::Utils::ToLocal(context));
}
// TODO(clemensh): origin can be inferred from asm_js_script; remove it.
MaybeHandle<WasmModuleObject> wasm::CreateModuleObjectFromBytes(
Isolate* isolate, const byte* start, const byte* end, ErrorThrower* thrower,
ModuleOrigin origin, Handle<Script> asm_js_script,
Vector<const byte> asm_js_offset_table_bytes) {
MaybeHandle<WasmModuleObject> nothing;
if (origin != kAsmJsOrigin &&
!IsWasmCodegenAllowed(isolate, isolate->native_context())) {
thrower->CompileError("Wasm code generation disallowed in this context");
return nothing;
}
ModuleResult result = DecodeWasmModule(isolate, start, end, false, origin);
if (result.failed()) {
if (result.val) delete result.val;
thrower->CompileFailed("Wasm decoding failed", result);
return nothing;
}
// The {module_wrapper} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object.
Handle<WasmModuleWrapper> module_wrapper =
WasmModuleWrapper::New(isolate, const_cast<WasmModule*>(result.val));
// Compile the functions of the module, producing a compiled module.
MaybeHandle<WasmCompiledModule> maybe_compiled_module =
result.val->CompileFunctions(isolate, module_wrapper, thrower,
ModuleWireBytes(start, end), asm_js_script,
asm_js_offset_table_bytes);
if (maybe_compiled_module.is_null()) return nothing;
Handle<WasmCompiledModule> compiled_module =
maybe_compiled_module.ToHandleChecked();
return WasmModuleObject::New(isolate, compiled_module);
}
bool wasm::ValidateModuleBytes(Isolate* isolate, const byte* start,
const byte* end, ErrorThrower* thrower,
ModuleOrigin origin) {
ModuleResult result = DecodeWasmModule(isolate, start, end, true, origin);
if (result.val) {
delete result.val;
} else {
DCHECK(!result.ok());
}
return result.ok();
}
MaybeHandle<JSArrayBuffer> wasm::GetInstanceMemory(
Isolate* isolate, Handle<WasmInstanceObject> object) {
auto instance = Handle<WasmInstanceObject>::cast(object);
......@@ -2825,3 +2768,143 @@ Handle<JSArray> wasm::GetCustomSections(Isolate* isolate,
return array_object;
}
bool wasm::SyncValidate(Isolate* isolate, ErrorThrower* thrower,
const ModuleWireBytes& bytes) {
if (bytes.start() == nullptr || bytes.length() == 0) return false;
ModuleResult result =
DecodeWasmModule(isolate, bytes.start(), bytes.end(), true, kWasmOrigin);
if (result.val) delete result.val;
return result.ok();
}
MaybeHandle<WasmModuleObject> wasm::SyncCompileTranslatedAsmJs(
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
Handle<Script> asm_js_script,
Vector<const byte> asm_js_offset_table_bytes) {
MaybeHandle<WasmModuleObject> nothing;
ModuleResult result = DecodeWasmModule(isolate, bytes.start(), bytes.end(),
false, kAsmJsOrigin);
if (result.failed()) {
// TODO(titzer): use Result<std::unique_ptr<const WasmModule*>>?
if (result.val) delete result.val;
thrower->CompileFailed("Wasm decoding failed", result);
return nothing;
}
return CompileToModuleObject(isolate, const_cast<WasmModule*>(result.val),
thrower, bytes, asm_js_script,
asm_js_offset_table_bytes);
}
MaybeHandle<WasmModuleObject> wasm::SyncCompile(Isolate* isolate,
ErrorThrower* thrower,
const ModuleWireBytes& bytes) {
MaybeHandle<WasmModuleObject> nothing;
if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) {
thrower->CompileError("Wasm code generation disallowed in this context");
return nothing;
}
ModuleResult result =
DecodeWasmModule(isolate, bytes.start(), bytes.end(), false, kWasmOrigin);
if (result.failed()) {
if (result.val) delete result.val;
thrower->CompileFailed("Wasm decoding failed", result);
return nothing;
}
return CompileToModuleObject(isolate, const_cast<WasmModule*>(result.val),
thrower, bytes, Handle<Script>(),
Vector<const byte>());
}
MaybeHandle<WasmInstanceObject> wasm::SyncInstantiate(
Isolate* isolate, ErrorThrower* thrower,
Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
MaybeHandle<JSArrayBuffer> memory) {
InstantiationHelper helper(isolate, thrower, module_object, imports, memory);
return helper.Build();
}
void RejectPromise(Isolate* isolate, ErrorThrower* thrower,
Handle<JSPromise> promise) {
v8::Local<v8::Promise::Resolver> resolver =
v8::Utils::PromiseToLocal(promise).As<v8::Promise::Resolver>();
Handle<Context> context(isolate->context(), isolate);
resolver->Reject(v8::Utils::ToLocal(context),
v8::Utils::ToLocal(thrower->Reify()));
}
void ResolvePromise(Isolate* isolate, Handle<JSPromise> promise,
Handle<Object> result) {
v8::Local<v8::Promise::Resolver> resolver =
v8::Utils::PromiseToLocal(promise).As<v8::Promise::Resolver>();
Handle<Context> context(isolate->context(), isolate);
resolver->Resolve(v8::Utils::ToLocal(context), v8::Utils::ToLocal(result));
}
void wasm::AsyncCompile(Isolate* isolate, Handle<JSPromise> promise,
const ModuleWireBytes& bytes) {
ErrorThrower thrower(isolate, nullptr);
MaybeHandle<WasmModuleObject> module_object =
SyncCompile(isolate, &thrower, bytes);
if (thrower.error()) {
RejectPromise(isolate, &thrower, promise);
return;
}
ResolvePromise(isolate, promise, module_object.ToHandleChecked());
}
void wasm::AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise,
Handle<WasmModuleObject> module_object,
MaybeHandle<JSReceiver> imports) {
ErrorThrower thrower(isolate, nullptr);
MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null());
if (thrower.error()) {
RejectPromise(isolate, &thrower, promise);
return;
}
ResolvePromise(isolate, promise, instance_object.ToHandleChecked());
}
void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
Handle<JSPromise> promise,
const ModuleWireBytes& bytes,
MaybeHandle<JSReceiver> imports) {
ErrorThrower thrower(isolate, nullptr);
// Compile the module.
MaybeHandle<WasmModuleObject> module_object =
SyncCompile(isolate, &thrower, bytes);
if (thrower.error()) {
RejectPromise(isolate, &thrower, promise);
return;
}
Handle<WasmModuleObject> module = module_object.ToHandleChecked();
// Instantiate the module.
MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
isolate, &thrower, module, imports, Handle<JSArrayBuffer>::null());
if (thrower.error()) {
RejectPromise(isolate, &thrower, promise);
return;
}
Handle<JSFunction> object_function =
Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
Handle<JSObject> ret =
isolate->factory()->NewJSObject(object_function, TENURED);
Handle<String> module_property_name =
isolate->factory()->InternalizeUtf8String("module");
Handle<String> instance_property_name =
isolate->factory()->InternalizeUtf8String("instance");
JSObject::AddProperty(ret, module_property_name, module, NONE);
JSObject::AddProperty(ret, instance_property_name,
instance_object.ToHandleChecked(), NONE);
ResolvePromise(isolate, promise, ret);
}
......@@ -28,7 +28,6 @@ class WasmMemoryObject;
namespace compiler {
class CallDescriptor;
class WasmCompilationUnit;
}
namespace wasm {
......@@ -217,18 +216,6 @@ struct V8_EXPORT_PRIVATE WasmModule {
~WasmModule() {
if (owned_zone) delete owned_zone;
}
// Creates a new instantiation of the module in the given isolate.
static MaybeHandle<WasmInstanceObject> Instantiate(
Isolate* isolate, ErrorThrower* thrower,
Handle<WasmModuleObject> wasm_module, Handle<JSReceiver> ffi,
Handle<JSArrayBuffer> memory = Handle<JSArrayBuffer>::null());
MaybeHandle<WasmCompiledModule> CompileFunctions(
Isolate* isolate, Handle<Managed<WasmModule>> module_wrapper,
ErrorThrower* thrower, const ModuleWireBytes& wire_bytes,
Handle<Script> asm_js_script,
Vector<const byte> asm_js_offset_table_bytes) const;
};
typedef Managed<WasmModule> WasmModuleWrapper;
......@@ -359,6 +346,7 @@ struct V8_EXPORT_PRIVATE ModuleEnv {
return instance->function_code[index];
}
// TODO(titzer): move these into src/compiler/wasm-compiler.cc
static compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone,
FunctionSig* sig);
static compiler::CallDescriptor* GetI32WasmCallDescriptor(
......@@ -425,11 +413,6 @@ V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
ErrorThrower* thrower);
V8_EXPORT_PRIVATE bool ValidateModuleBytes(Isolate* isolate, const byte* start,
const byte* end,
ErrorThrower* thrower,
ModuleOrigin origin);
// Get the offset of the code of a function within a module.
int GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module,
int func_index);
......@@ -464,15 +447,43 @@ void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
void GrowDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
uint32_t old_size, uint32_t count);
namespace testing {
//============================================================================
//== Compilation and instantiation ===========================================
//============================================================================
V8_EXPORT_PRIVATE bool SyncValidate(Isolate* isolate, ErrorThrower* thrower,
const ModuleWireBytes& bytes);
V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> SyncCompileTranslatedAsmJs(
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
Handle<Script> asm_js_script, Vector<const byte> asm_js_offset_table_bytes);
V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> SyncCompile(
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes);
V8_EXPORT_PRIVATE MaybeHandle<WasmInstanceObject> SyncInstantiate(
Isolate* isolate, ErrorThrower* thrower,
Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
MaybeHandle<JSArrayBuffer> memory);
V8_EXPORT_PRIVATE void AsyncCompile(Isolate* isolate, Handle<JSPromise> promise,
const ModuleWireBytes& bytes);
V8_EXPORT_PRIVATE void AsyncInstantiate(Isolate* isolate,
Handle<JSPromise> promise,
Handle<WasmModuleObject> module_object,
MaybeHandle<JSReceiver> imports);
V8_EXPORT_PRIVATE void AsyncCompileAndInstantiate(
Isolate* isolate, Handle<JSPromise> promise, const ModuleWireBytes& bytes,
MaybeHandle<JSReceiver> imports);
namespace testing {
void ValidateInstancesChain(Isolate* isolate,
Handle<WasmModuleObject> module_obj,
int instance_count);
void ValidateModuleState(Isolate* isolate, Handle<WasmModuleObject> module_obj);
void ValidateOrphanedInstance(Isolate* isolate,
Handle<WasmInstanceObject> instance);
} // namespace testing
} // namespace wasm
} // namespace internal
......
......@@ -271,9 +271,9 @@ class WasmSerializationTest {
0);
}
Handle<JSObject> instance =
WasmModule::Instantiate(current_isolate(), &thrower, module_object,
Handle<JSReceiver>::null(),
Handle<JSArrayBuffer>::null())
SyncInstantiate(current_isolate(), &thrower, module_object,
Handle<JSReceiver>::null(),
MaybeHandle<JSArrayBuffer>())
.ToHandleChecked();
Handle<Object> params[1] = {
Handle<Object>(Smi::FromInt(41), current_isolate())};
......@@ -318,19 +318,13 @@ class WasmSerializationTest {
HandleScope scope(serialization_isolate);
testing::SetupIsolateForWasmModule(serialization_isolate);
ModuleResult decoding_result =
DecodeWasmModule(serialization_isolate, buffer.begin(), buffer.end(),
false, kWasmOrigin);
CHECK(!decoding_result.failed());
MaybeHandle<WasmModuleObject> module_object =
SyncCompile(serialization_isolate, &thrower,
ModuleWireBytes(buffer.begin(), buffer.end()));
Handle<WasmModuleWrapper> module_wrapper = WasmModuleWrapper::New(
serialization_isolate, const_cast<WasmModule*>(decoding_result.val));
MaybeHandle<WasmCompiledModule> compiled_module =
decoding_result.val->CompileFunctions(
serialization_isolate, module_wrapper, &thrower,
ModuleWireBytes(buffer.begin(), buffer.end()),
Handle<Script>::null(), Vector<const byte>::empty());
MaybeHandle<WasmCompiledModule> compiled_module(
module_object.ToHandleChecked()->compiled_module(),
serialization_isolate);
CHECK(!compiled_module.is_null());
Handle<JSObject> module_obj = WasmModuleObject::New(
serialization_isolate, compiled_module.ToHandleChecked());
......@@ -437,10 +431,8 @@ TEST(BlockWasmCodeGen) {
CcTest::isolate()->SetAllowCodeGenerationFromStringsCallback(False);
ErrorThrower thrower(isolate, "block codegen");
MaybeHandle<WasmModuleObject> ret = wasm::CreateModuleObjectFromBytes(
isolate, buffer.begin(), buffer.end(), &thrower,
wasm::ModuleOrigin::kWasmOrigin, Handle<v8::internal::Script>::null(),
Vector<const byte>::empty());
MaybeHandle<WasmModuleObject> ret = wasm::SyncCompile(
isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
CcTest::isolate()->SetAllowCodeGenerationFromStringsCallback(nullptr);
CHECK(ret.is_null());
CHECK(thrower.error());
......
......@@ -59,17 +59,15 @@ const Handle<WasmInstanceObject> InstantiateModuleForTesting(
// Although we decoded the module for some pre-validation, run the bytes
// again through the normal pipeline.
// TODO(wasm): Use {module} instead of decoding the module bytes again.
MaybeHandle<WasmModuleObject> module_object = CreateModuleObjectFromBytes(
isolate, wire_bytes.start(), wire_bytes.end(), thrower,
ModuleOrigin::kWasmOrigin, Handle<Script>::null(),
Vector<const byte>::empty());
MaybeHandle<WasmModuleObject> module_object =
SyncCompile(isolate, thrower, wire_bytes);
if (module_object.is_null()) {
thrower->CompileError("Module pre-validation failed.");
return Handle<WasmInstanceObject>::null();
}
MaybeHandle<WasmInstanceObject> maybe_instance =
WasmModule::Instantiate(isolate, thrower, module_object.ToHandleChecked(),
Handle<JSReceiver>::null());
SyncInstantiate(isolate, thrower, module_object.ToHandleChecked(),
Handle<JSReceiver>::null(), MaybeHandle<JSArrayBuffer>());
Handle<WasmInstanceObject> instance;
if (!maybe_instance.ToHandle(&instance)) {
return Handle<WasmInstanceObject>::null();
......
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