Commit 3dcbc57e authored by bradnelson's avatar bradnelson Committed by Commit bot

Allow asm modules to be instatiated with external heaps.

This merges the instantiation logic between instantiateModule
and instantiateModuleFromAsm.

BUG= https://code.google.com/p/v8/issues/detail?id=4203
TEST=asm-wasm
R=aseemgarg@chromium.org,titzer@chromium.org
LOG=N

Review URL: https://codereview.chromium.org/1581913005

Cr-Commit-Position: refs/heads/master@{#33316}
parent 090bf558
......@@ -126,7 +126,8 @@ void CompileRun(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(i::ParseInfo* info) {
v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(i::ParseInfo* info,
ErrorThrower* thrower) {
info->set_global();
info->set_lazy(false);
info->set_allow_lazy_parsing(false);
......@@ -142,6 +143,7 @@ v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(i::ParseInfo* info) {
v8::internal::AsmTyper typer(info->isolate(), info->zone(), *(info->script()),
info->literal());
if (!typer.Validate()) {
thrower->Error("Asm.js validation failed: %s", typer.error_message());
return nullptr;
}
......@@ -162,7 +164,7 @@ void AsmCompileRun(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
if (!args[0]->IsString()) {
thrower.Error("Invalid argument count");
thrower.Error("Asm module text should be a string");
return;
}
......@@ -172,9 +174,8 @@ void AsmCompileRun(const v8::FunctionCallbackInfo<v8::Value>& args) {
i::Handle<i::Script> script = factory->NewScript(Utils::OpenHandle(*source));
i::ParseInfo info(&zone, script);
auto module = TranslateAsmModule(&info);
auto module = TranslateAsmModule(&info, &thrower);
if (module == nullptr) {
thrower.Error("Asm.js validation failed");
return;
}
......@@ -184,42 +185,35 @@ void AsmCompileRun(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
// TODO(aseemgarg): deal with arraybuffer and foreign functions
void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(args.GetIsolate());
void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
const byte* start, const byte* end,
ErrorThrower* thrower, bool must_decode) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
ErrorThrower thrower(isolate, "WASM.instantiateModuleFromAsm()");
if (args.Length() != 1) {
thrower.Error("Invalid argument count");
return;
}
if (!args[0]->IsString()) {
thrower.Error("Invalid argument count");
return;
i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null();
if (args.Length() > 2 && args[2]->IsArrayBuffer()) {
Local<Object> obj = Local<Object>::Cast(args[2]);
i::Handle<i::Object> mem_obj = v8::Utils::OpenHandle(*obj);
memory = i::Handle<i::JSArrayBuffer>(i::JSArrayBuffer::cast(*mem_obj));
}
i::Factory* factory = isolate->factory();
// Decode but avoid a redundant pass over function bodies for verification.
// Verification will happen during compilation.
i::Zone zone;
Local<String> source = Local<String>::Cast(args[0]);
i::Handle<i::Script> script = factory->NewScript(Utils::OpenHandle(*source));
i::ParseInfo info(&zone, script);
auto module = TranslateAsmModule(&info);
if (module == nullptr) {
thrower.Error("Asm.js validation failed");
return;
}
i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null();
internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
isolate, &zone, module->Begin(), module->End(), false, false);
isolate, &zone, start, end, false, false);
if (result.failed()) {
thrower.Failed("", result);
if (result.failed() && must_decode) {
thrower->Error("Asm.js converted module failed to decode");
} else if (result.failed()) {
thrower->Failed("", result);
} else {
// Success. Instantiate the module and return the object.
i::Handle<i::JSObject> ffi = i::Handle<i::JSObject>::null();
if (args.Length() > 1 && args[1]->IsObject()) {
Local<Object> obj = Local<Object>::Cast(args[1]);
ffi = i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
}
i::MaybeHandle<i::JSObject> object =
result.val->Instantiate(isolate, ffi, memory);
......@@ -233,46 +227,40 @@ void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
void InstantiateModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(args.GetIsolate());
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
ErrorThrower thrower(isolate, "WASM.instantiateModule()");
RawBuffer buffer = GetRawBufferArgument(thrower, args);
if (buffer.start == nullptr) return;
ErrorThrower thrower(isolate, "WASM.instantiateModuleFromAsm()");
i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null();
if (args.Length() > 2 && args[2]->IsArrayBuffer()) {
Local<Object> obj = Local<Object>::Cast(args[2]);
i::Handle<i::Object> mem_obj = v8::Utils::OpenHandle(*obj);
memory = i::Handle<i::JSArrayBuffer>(i::JSArrayBuffer::cast(*mem_obj));
if (!args[0]->IsString()) {
thrower.Error("Asm module text should be a string");
return;
}
// Decode but avoid a redundant pass over function bodies for verification.
// Verification will happen during compilation.
i::Factory* factory = isolate->factory();
i::Zone zone;
internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
isolate, &zone, buffer.start, buffer.end, false, false);
Local<String> source = Local<String>::Cast(args[0]);
i::Handle<i::Script> script = factory->NewScript(Utils::OpenHandle(*source));
i::ParseInfo info(&zone, script);
if (result.failed()) {
thrower.Failed("", result);
} else {
// Success. Instantiate the module and return the object.
i::Handle<i::JSObject> ffi = i::Handle<i::JSObject>::null();
if (args.Length() > 1 && args[1]->IsObject()) {
Local<Object> obj = Local<Object>::Cast(args[1]);
ffi = i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
}
auto module = TranslateAsmModule(&info, &thrower);
if (module == nullptr) {
return;
}
i::MaybeHandle<i::JSObject> object =
result.val->Instantiate(isolate, ffi, memory);
InstantiateModuleCommon(args, module->Begin(), module->End(), &thrower, true);
}
if (!object.is_null()) {
args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked()));
}
}
if (result.val) delete result.val;
void InstantiateModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(args.GetIsolate());
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
ErrorThrower thrower(isolate, "WASM.instantiateModule()");
RawBuffer buffer = GetRawBufferArgument(thrower, args);
if (buffer.start == nullptr) return;
InstantiateModuleCommon(args, buffer.start, buffer.end, &thrower, false);
}
} // namespace
......
......@@ -391,19 +391,38 @@ function TestInt32HeapAccess(stdlib, foreign, buffer) {
assertEquals(7, _WASMEXP_.asmCompileRun(TestInt32HeapAccess.toString()));
function TestInt32HeapAccessExternal() {
var memory = new ArrayBuffer(1024);
var memory_int32 = new Int32Array(memory);
var module = _WASMEXP_.instantiateModuleFromAsm(
TestInt32HeapAccess.toString(), null, memory);
module.__init__();
assertEquals(7, module.caller());
assertEquals(7, memory_int32[2]);
}
TestInt32HeapAccessExternal();
function TestHeapAccessIntTypes() {
var types = [
['Int8Array', '>> 0'],
['Uint8Array', '>> 0'],
['Int16Array', '>> 1'],
['Uint16Array', '>> 1'],
['Int32Array', '>> 2'],
['Uint32Array', '>> 2'],
[Int8Array, 'Int8Array', '>> 0'],
[Uint8Array, 'Uint8Array', '>> 0'],
[Int16Array, 'Int16Array', '>> 1'],
[Uint16Array, 'Uint16Array', '>> 1'],
[Int32Array, 'Int32Array', '>> 2'],
[Uint32Array, 'Uint32Array', '>> 2'],
];
for (var i = 0; i < types.length; i++) {
var code = TestInt32HeapAccess.toString();
code = code.replace('Int32Array', types[i][0]);
code = code.replace(/>> 2/g, types[i][1]);
code = code.replace('Int32Array', types[i][1]);
code = code.replace(/>> 2/g, types[i][2]);
var memory = new ArrayBuffer(1024);
var memory_view = new types[i][0](memory);
var module = _WASMEXP_.instantiateModuleFromAsm(code, null, memory);
module.__init__();
assertEquals(7, module.caller());
assertEquals(7, memory_view[2]);
assertEquals(7, _WASMEXP_.asmCompileRun(code));
}
}
......@@ -436,6 +455,19 @@ function TestFloatHeapAccess(stdlib, foreign, buffer) {
assertEquals(1, _WASMEXP_.asmCompileRun(TestFloatHeapAccess.toString()));
function TestFloatHeapAccessExternal() {
var memory = new ArrayBuffer(1024);
var memory_float64 = new Float64Array(memory);
var module = _WASMEXP_.instantiateModuleFromAsm(
TestFloatHeapAccess.toString(), null, memory);
module.__init__();
assertEquals(1, module.caller());
assertEquals(9.0, memory_float64[1]);
}
TestFloatHeapAccessExternal();
function TestConvertI32() {
"use asm";
......
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