[wasm] Implement importing of WebAssembly.Memory.
R=mtrofin@chromium.org,gdeepti@chromium.org BUG=chromium:575167 Review-Url: https://codereview.chromium.org/2392943006 Cr-Commit-Position: refs/heads/master@{#40076}
This commit is contained in:
parent
e5b07adfb1
commit
e3ff4cf8c9
@ -310,9 +310,9 @@ class ModuleDecoder : public Decoder {
|
||||
}
|
||||
case kExternalMemory: {
|
||||
// ===== Imported memory =========================================
|
||||
// import->index =
|
||||
// static_cast<uint32_t>(module->memories.size());
|
||||
// TODO(titzer): imported memories
|
||||
consume_resizable_limits(
|
||||
"memory", "pages", WasmModule::kMaxLegalPages,
|
||||
&module->min_mem_pages, &module->max_mem_pages);
|
||||
break;
|
||||
}
|
||||
case kExternalGlobal: {
|
||||
@ -774,7 +774,7 @@ class ModuleDecoder : public Decoder {
|
||||
uint32_t offset = pc_offset();
|
||||
const byte* string_start = pc_;
|
||||
// Consume bytes before validation to guarantee that the string is not oob.
|
||||
consume_bytes(*length, "string");
|
||||
if (*length > 0) consume_bytes(*length, "string");
|
||||
if (ok() && validate_utf8 &&
|
||||
!unibrow::Utf8::Validate(string_start, *length)) {
|
||||
error(string_start, "no valid UTF-8 string");
|
||||
|
@ -27,6 +27,8 @@ using v8::internal::wasm::ErrorThrower;
|
||||
|
||||
namespace v8 {
|
||||
|
||||
static const int kWasmMemoryBufferFieldIndex = 0;
|
||||
|
||||
namespace {
|
||||
i::Handle<i::String> v8_str(i::Isolate* isolate, const char* str) {
|
||||
return isolate->factory()->NewStringFromAsciiChecked(str);
|
||||
@ -509,7 +511,8 @@ void WebAssemblyMemoryGetBuffer(
|
||||
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);
|
||||
i::Handle<i::Object> buffer(
|
||||
receiver->GetInternalField(kWasmMemoryBufferFieldIndex), i_isolate);
|
||||
DCHECK(buffer->IsJSArrayBuffer());
|
||||
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
|
||||
return_value.Set(Utils::ToLocal(buffer));
|
||||
@ -523,7 +526,7 @@ i::Handle<i::JSObject> i::WasmJs::CreateWasmMemoryObject(
|
||||
i_isolate->native_context()->wasm_memory_constructor());
|
||||
i::Handle<i::JSObject> memory_obj =
|
||||
i_isolate->factory()->NewJSObject(memory_ctor);
|
||||
memory_obj->SetInternalField(0, *buffer);
|
||||
memory_obj->SetInternalField(kWasmMemoryBufferFieldIndex, *buffer);
|
||||
memory_obj->SetInternalField(
|
||||
1, has_maximum
|
||||
? static_cast<i::Object*>(i::Smi::FromInt(maximum))
|
||||
@ -737,5 +740,24 @@ void WasmJs::InstallWasmMapsIfNeeded(Isolate* isolate,
|
||||
}
|
||||
}
|
||||
|
||||
bool WasmJs::IsWasmMemoryObject(Isolate* isolate, Handle<Object> value) {
|
||||
if (value->IsJSObject()) {
|
||||
i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value);
|
||||
i::Handle<i::Symbol> sym(isolate->context()->wasm_memory_sym(), isolate);
|
||||
Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym);
|
||||
if (has_brand.IsNothing()) return false;
|
||||
if (has_brand.ToChecked()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle<JSArrayBuffer> WasmJs::GetWasmMemoryArrayBuffer(Isolate* isolate,
|
||||
Handle<Object> value) {
|
||||
DCHECK(IsWasmMemoryObject(isolate, value));
|
||||
Handle<Object> buf(
|
||||
JSObject::cast(*value)->GetInternalField(kWasmMemoryBufferFieldIndex),
|
||||
isolate);
|
||||
return Handle<JSArrayBuffer>::cast(buf);
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -27,6 +27,11 @@ class WasmJs {
|
||||
static Handle<JSObject> CreateWasmMemoryObject(Isolate* isolate,
|
||||
Handle<JSArrayBuffer> buffer,
|
||||
bool has_maximum, int maximum);
|
||||
|
||||
static bool IsWasmMemoryObject(Isolate* isolate, Handle<Object> value);
|
||||
|
||||
static Handle<JSArrayBuffer> GetWasmMemoryArrayBuffer(Isolate* isolate,
|
||||
Handle<Object> value);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -53,6 +53,7 @@ enum WasmInstanceObjectFields {
|
||||
kWasmCompiledModule = 0,
|
||||
kWasmModuleFunctionTable,
|
||||
kWasmModuleCodeTable,
|
||||
kWasmMemObject,
|
||||
kWasmMemArrayBuffer,
|
||||
kWasmGlobalsArrayBuffer,
|
||||
kWasmDebugInfo,
|
||||
@ -1243,6 +1244,36 @@ class WasmInstanceBuilder {
|
||||
JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
|
||||
Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED);
|
||||
instance->SetInternalField(kWasmModuleCodeTable, *code_table);
|
||||
instance->SetInternalField(kWasmMemObject, *factory->undefined_value());
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Set up the globals for the new instance.
|
||||
//--------------------------------------------------------------------------
|
||||
MaybeHandle<JSArrayBuffer> old_globals;
|
||||
MaybeHandle<JSArrayBuffer> globals;
|
||||
uint32_t globals_size = compiled_module_->globals_size();
|
||||
if (globals_size > 0) {
|
||||
Handle<JSArrayBuffer> global_buffer =
|
||||
NewArrayBuffer(isolate_, globals_size);
|
||||
globals = global_buffer;
|
||||
if (globals.is_null()) {
|
||||
thrower_->Error("Out of memory: wasm globals");
|
||||
return nothing;
|
||||
}
|
||||
Address old_address =
|
||||
owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate(
|
||||
*factory->undefined_value(),
|
||||
JSObject::cast(*owner));
|
||||
RelocateGlobals(instance, old_address,
|
||||
static_cast<Address>(global_buffer->backing_store()));
|
||||
instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process the imports for the module.
|
||||
//--------------------------------------------------------------------------
|
||||
int num_imported_functions = ProcessImports(globals, code_table, instance);
|
||||
if (num_imported_functions < 0) return nothing;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Set up the memory for the new instance.
|
||||
@ -1278,35 +1309,6 @@ class WasmInstanceBuilder {
|
||||
compiled_module_->set_heap(memory_);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Set up the globals for the new instance.
|
||||
//--------------------------------------------------------------------------
|
||||
MaybeHandle<JSArrayBuffer> old_globals;
|
||||
MaybeHandle<JSArrayBuffer> globals;
|
||||
uint32_t globals_size = compiled_module_->globals_size();
|
||||
if (globals_size > 0) {
|
||||
Handle<JSArrayBuffer> global_buffer =
|
||||
NewArrayBuffer(isolate_, globals_size);
|
||||
globals = global_buffer;
|
||||
if (globals.is_null()) {
|
||||
thrower_->Error("Out of memory: wasm globals");
|
||||
return nothing;
|
||||
}
|
||||
Address old_address =
|
||||
owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate(
|
||||
*factory->undefined_value(),
|
||||
JSObject::cast(*owner));
|
||||
RelocateGlobals(instance, old_address,
|
||||
static_cast<Address>(global_buffer->backing_store()));
|
||||
instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process the imports for the module.
|
||||
//--------------------------------------------------------------------------
|
||||
int num_imported_functions = ProcessImports(globals, code_table);
|
||||
if (num_imported_functions < 0) return nothing;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process the initialization for the module's globals.
|
||||
//--------------------------------------------------------------------------
|
||||
@ -1626,7 +1628,7 @@ class WasmInstanceBuilder {
|
||||
// order, loading them from the {ffi_} object. Returns the number of imported
|
||||
// functions.
|
||||
int ProcessImports(MaybeHandle<JSArrayBuffer> globals,
|
||||
Handle<FixedArray> code_table) {
|
||||
Handle<FixedArray> code_table, Handle<JSObject> instance) {
|
||||
int num_imported_functions = 0;
|
||||
if (!compiled_module_->has_imports()) return num_imported_functions;
|
||||
|
||||
@ -1668,9 +1670,17 @@ class WasmInstanceBuilder {
|
||||
case kExternalTable:
|
||||
// TODO(titzer): Table imports must be a WebAssembly.Table.
|
||||
break;
|
||||
case kExternalMemory:
|
||||
// TODO(titzer): Memory imports must be a WebAssembly.Memory.
|
||||
case kExternalMemory: {
|
||||
Handle<Object> object = result.ToHandleChecked();
|
||||
if (!WasmJs::IsWasmMemoryObject(isolate_, object)) {
|
||||
ReportFFIError("memory import must be a WebAssembly.Memory object",
|
||||
index, module_name, function_name);
|
||||
return -1;
|
||||
}
|
||||
instance->SetInternalField(kWasmMemObject, *object);
|
||||
memory_ = WasmJs::GetWasmMemoryArrayBuffer(isolate_, object);
|
||||
break;
|
||||
}
|
||||
case kExternalGlobal: {
|
||||
// Global imports are converted to numbers and written into the
|
||||
// {globals} array buffer.
|
||||
@ -1787,13 +1797,21 @@ class WasmInstanceBuilder {
|
||||
// TODO(titzer): should it have the same identity as an import?
|
||||
break;
|
||||
case kExternalMemory: {
|
||||
// TODO(titzer): should memory have the same identity as an
|
||||
// import?
|
||||
Handle<JSArrayBuffer> buffer =
|
||||
Handle<JSArrayBuffer>(JSArrayBuffer::cast(
|
||||
instance->GetInternalField(kWasmMemArrayBuffer)));
|
||||
desc.set_value(
|
||||
WasmJs::CreateWasmMemoryObject(isolate_, buffer, false, 0));
|
||||
// Export the memory as a WebAssembly.Memory object.
|
||||
Handle<Object> memory_object(
|
||||
instance->GetInternalField(kWasmMemObject), isolate_);
|
||||
if (memory_object->IsUndefined(isolate_)) {
|
||||
// If there was no imported WebAssembly.Memory object, create one.
|
||||
Handle<JSArrayBuffer> buffer(
|
||||
JSArrayBuffer::cast(
|
||||
instance->GetInternalField(kWasmMemArrayBuffer)),
|
||||
isolate_);
|
||||
memory_object =
|
||||
WasmJs::CreateWasmMemoryObject(isolate_, buffer, false, 0);
|
||||
instance->SetInternalField(kWasmMemObject, *memory_object);
|
||||
}
|
||||
|
||||
desc.set_value(memory_object);
|
||||
break;
|
||||
}
|
||||
case kExternalGlobal: {
|
||||
|
82
test/mjsunit/wasm/import-memory.js
Normal file
82
test/mjsunit/wasm/import-memory.js
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --expose-wasm
|
||||
|
||||
load("test/mjsunit/wasm/wasm-constants.js");
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
(function TestOne() {
|
||||
print("TestOne");
|
||||
let memory = new WebAssembly.Memory({initial: 1});
|
||||
assertEquals(kPageSize, memory.buffer.byteLength);
|
||||
let i32 = new Int32Array(memory.buffer);
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addImportedMemory("mine");
|
||||
builder.addFunction("main", kSig_i_v)
|
||||
.addBody([
|
||||
kExprI32Const, 0,
|
||||
kExprI32LoadMem, 0, 0])
|
||||
.exportAs("main");
|
||||
|
||||
let main = builder.instantiate({mine: memory}).exports.main;
|
||||
assertEquals(0, main());
|
||||
|
||||
i32[0] = 993377;
|
||||
|
||||
assertEquals(993377, main());
|
||||
})();
|
||||
|
||||
(function TestIdentity() {
|
||||
print("TestIdentity");
|
||||
let memory = new WebAssembly.Memory({initial: 1});
|
||||
let i32 = new Int32Array(memory.buffer);
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addImportedMemory("garg");
|
||||
builder.exportMemoryAs("daggle");
|
||||
|
||||
let instance = builder.instantiate({garg: memory});
|
||||
assertSame(memory, instance.exports.daggle);
|
||||
})();
|
||||
|
||||
|
||||
(function TestImportExport() {
|
||||
print("TestImportExport");
|
||||
var i1;
|
||||
{
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addMemory(1, 1, false);
|
||||
builder.exportMemoryAs("exported_mem");
|
||||
builder.addFunction("foo", kSig_i_i)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprI32LoadMem, 0, 0])
|
||||
.exportAs("foo");
|
||||
i1 = builder.instantiate();
|
||||
}
|
||||
|
||||
var i2;
|
||||
{
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addMemory(1, 1, false);
|
||||
builder.addImportedMemory("imported_mem");
|
||||
builder.addFunction("bar", kSig_i_i)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprI32LoadMem, 0, 0])
|
||||
.exportAs("bar");
|
||||
i2 = builder.instantiate({imported_mem: i1.exports.exported_mem});
|
||||
}
|
||||
|
||||
let i32 = new Int32Array(i1.exports.exported_mem.buffer);
|
||||
|
||||
for (var i = 0; i < 1e11; i = i * 3 + 5) {
|
||||
for (var j = 0; j < 10; j++) {
|
||||
var val = i + 99077 + j;
|
||||
i32[j] = val;
|
||||
assertEquals(val | 0, i1.exports.foo(j * 4));
|
||||
assertEquals(val | 0, i2.exports.bar(j * 4));
|
||||
}
|
||||
}
|
||||
})();
|
@ -194,11 +194,20 @@ class WasmModuleBuilder {
|
||||
return this.num_imported_globals++;
|
||||
}
|
||||
|
||||
addImportedMemory(module, name, initial = 0, maximum) {
|
||||
let o = {module: module, name: name, kind: kExternalMemory, initial: initial, maximum: maximum};
|
||||
this.imports.push(o);
|
||||
}
|
||||
|
||||
addDataSegment(addr, data, init) {
|
||||
this.segments.push({addr: addr, data: data, init: init});
|
||||
return this.segments.length - 1;
|
||||
}
|
||||
|
||||
exportMemoryAs(name) {
|
||||
this.exports.push({name: name, kind: kExternalMemory, index: 0});
|
||||
}
|
||||
|
||||
appendToTable(array) {
|
||||
this.table.push(...array);
|
||||
return this;
|
||||
@ -244,6 +253,11 @@ class WasmModuleBuilder {
|
||||
} else if (imp.kind == kExternalGlobal) {
|
||||
section.emit_u32v(imp.type);
|
||||
section.emit_u8(imp.mutable);
|
||||
} else if (imp.kind == kExternalMemory) {
|
||||
var has_max = (typeof imp.maximum) != "undefined";
|
||||
section.emit_u8(has_max ? 1 : 0); // flags
|
||||
section.emit_u32v(imp.initial); // initial
|
||||
if (has_max) section.emit_u32v(imp.maximum); // maximum
|
||||
} else {
|
||||
throw new Error("unknown/unsupported import kind " + imp.kind);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user