| Index: src/wasm/wasm-module.cc
|
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
|
| index 6e28f8757ca42423d141596cc1768395f7664f92..f262421174894abea16ea68715867fe796a83e39 100644
|
| --- a/src/wasm/wasm-module.cc
|
| +++ b/src/wasm/wasm-module.cc
|
| @@ -183,25 +183,81 @@ Handle<FixedArray> BuildFunctionTable(Isolate* isolate, WasmModule* module) {
|
| return fixed;
|
| }
|
|
|
| -
|
| -Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, int size,
|
| +Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
|
| byte** backing_store) {
|
| - void* memory = isolate->array_buffer_allocator()->Allocate(size);
|
| - if (!memory) return Handle<JSArrayBuffer>::null();
|
| + if (size > (1 << WasmModule::kMaxMemSize)) {
|
| + // TODO(titzer): lift restriction on maximum memory allocated here.
|
| + *backing_store = nullptr;
|
| + return Handle<JSArrayBuffer>::null();
|
| + }
|
| + void* memory =
|
| + isolate->array_buffer_allocator()->Allocate(static_cast<int>(size));
|
| + if (!memory) {
|
| + *backing_store = nullptr;
|
| + return Handle<JSArrayBuffer>::null();
|
| + }
|
| +
|
| *backing_store = reinterpret_cast<byte*>(memory);
|
|
|
| #if DEBUG
|
| // Double check the API allocator actually zero-initialized the memory.
|
| - for (int i = 0; i < size; i++) {
|
| - DCHECK_EQ(0, (*backing_store)[i]);
|
| + byte* bytes = reinterpret_cast<byte*>(*backing_store);
|
| + for (size_t i = 0; i < size; i++) {
|
| + DCHECK_EQ(0, bytes[i]);
|
| }
|
| #endif
|
|
|
| Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
| - JSArrayBuffer::Setup(buffer, isolate, false, memory, size);
|
| + JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size));
|
| buffer->set_is_neuterable(false);
|
| return buffer;
|
| }
|
| +
|
| +// Set the memory for a module instance to be the {memory} array buffer.
|
| +void SetMemory(WasmModuleInstance* instance, Handle<JSArrayBuffer> memory) {
|
| + memory->set_is_neuterable(false);
|
| + instance->mem_start = reinterpret_cast<byte*>(memory->backing_store());
|
| + instance->mem_size = memory->byte_length()->Number();
|
| + instance->mem_buffer = memory;
|
| +}
|
| +
|
| +// Allocate memory for a module instance as a new JSArrayBuffer.
|
| +bool AllocateMemory(ErrorThrower* thrower, Isolate* isolate,
|
| + WasmModuleInstance* instance) {
|
| + DCHECK(instance->module);
|
| + DCHECK(instance->mem_buffer.is_null());
|
| +
|
| + if (instance->module->min_mem_size_log2 > WasmModule::kMaxMemSize) {
|
| + thrower->Error("Out of memory: wasm memory too large");
|
| + return false;
|
| + }
|
| + instance->mem_size = static_cast<size_t>(1)
|
| + << instance->module->min_mem_size_log2;
|
| + instance->mem_buffer =
|
| + NewArrayBuffer(isolate, instance->mem_size, &instance->mem_start);
|
| + if (!instance->mem_start) {
|
| + thrower->Error("Out of memory: wasm memory");
|
| + instance->mem_size = 0;
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate,
|
| + WasmModuleInstance* instance) {
|
| + instance->globals_size = AllocateGlobalsOffsets(instance->module->globals);
|
| +
|
| + if (instance->globals_size > 0) {
|
| + instance->globals_buffer = NewArrayBuffer(isolate, instance->globals_size,
|
| + &instance->globals_start);
|
| + if (!instance->globals_start) {
|
| + // Not enough space for backing store of globals.
|
| + thrower->Error("Out of memory: wasm globals");
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| } // namespace
|
|
|
|
|
| @@ -232,90 +288,63 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
| Handle<JSArrayBuffer> memory) {
|
| this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate.
|
| ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
|
| -
|
| Factory* factory = isolate->factory();
|
| - // Memory is bigger than maximum supported size.
|
| - if (memory.is_null() && min_mem_size_log2 > kMaxMemSize) {
|
| - thrower.Error("Out of memory: wasm memory too large");
|
| - return MaybeHandle<JSObject>();
|
| - }
|
|
|
| + //-------------------------------------------------------------------------
|
| + // Allocate the instance and its JS counterpart.
|
| + //-------------------------------------------------------------------------
|
| Handle<Map> map = factory->NewMap(
|
| JS_OBJECT_TYPE,
|
| JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
|
| -
|
| - //-------------------------------------------------------------------------
|
| - // Allocate the module object.
|
| - //-------------------------------------------------------------------------
|
| - Handle<JSObject> module = factory->NewJSObjectFromMap(map, TENURED);
|
| + WasmModuleInstance instance(this);
|
| + instance.context = isolate->native_context();
|
| + instance.js_object = factory->NewJSObjectFromMap(map, TENURED);
|
| Handle<FixedArray> code_table =
|
| factory->NewFixedArray(static_cast<int>(functions->size()), TENURED);
|
| + instance.js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
|
|
|
| //-------------------------------------------------------------------------
|
| - // Allocate the linear memory.
|
| + // Allocate and initialize the linear memory.
|
| //-------------------------------------------------------------------------
|
| - uint32_t mem_size = 1 << min_mem_size_log2;
|
| - byte* mem_addr = nullptr;
|
| - Handle<JSArrayBuffer> mem_buffer;
|
| - if (!memory.is_null()) {
|
| - memory->set_is_neuterable(false);
|
| - mem_addr = reinterpret_cast<byte*>(memory->backing_store());
|
| - mem_size = memory->byte_length()->Number();
|
| - mem_buffer = memory;
|
| - } else {
|
| - mem_buffer = NewArrayBuffer(isolate, mem_size, &mem_addr);
|
| - if (!mem_addr) {
|
| - // Not enough space for backing store of memory
|
| - thrower.Error("Out of memory: wasm memory");
|
| + if (memory.is_null()) {
|
| + if (!AllocateMemory(&thrower, isolate, &instance)) {
|
| return MaybeHandle<JSObject>();
|
| }
|
| + } else {
|
| + SetMemory(&instance, memory);
|
| }
|
| -
|
| - // Load initialized data segments.
|
| - LoadDataSegments(this, mem_addr, mem_size);
|
| -
|
| - module->SetInternalField(kWasmMemArrayBuffer, *mem_buffer);
|
| + instance.js_object->SetInternalField(kWasmMemArrayBuffer,
|
| + *instance.mem_buffer);
|
| + LoadDataSegments(this, instance.mem_start, instance.mem_size);
|
|
|
| if (mem_export) {
|
| // Export the memory as a named property.
|
| Handle<String> name = factory->InternalizeUtf8String("memory");
|
| - JSObject::AddProperty(module, name, mem_buffer, READ_ONLY);
|
| + JSObject::AddProperty(instance.js_object, name, instance.mem_buffer,
|
| + READ_ONLY);
|
| }
|
|
|
| //-------------------------------------------------------------------------
|
| // Allocate the globals area if necessary.
|
| //-------------------------------------------------------------------------
|
| - size_t globals_size = AllocateGlobalsOffsets(globals);
|
| - byte* globals_addr = nullptr;
|
| - if (globals_size > 0) {
|
| - Handle<JSArrayBuffer> globals_buffer =
|
| - NewArrayBuffer(isolate, mem_size, &globals_addr);
|
| - if (!globals_addr) {
|
| - // Not enough space for backing store of globals.
|
| - thrower.Error("Out of memory: wasm globals");
|
| - return MaybeHandle<JSObject>();
|
| - }
|
| -
|
| - module->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer);
|
| - } else {
|
| - module->SetInternalField(kWasmGlobalsArrayBuffer, Smi::FromInt(0));
|
| + if (!AllocateGlobals(&thrower, isolate, &instance)) {
|
| + return MaybeHandle<JSObject>();
|
| + }
|
| + if (!instance.globals_buffer.is_null()) {
|
| + instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer,
|
| + *instance.globals_buffer);
|
| }
|
|
|
| //-------------------------------------------------------------------------
|
| // Compile all functions in the module.
|
| //-------------------------------------------------------------------------
|
| + instance.function_table = BuildFunctionTable(isolate, this);
|
| int index = 0;
|
| WasmLinker linker(isolate, functions->size());
|
| ModuleEnv module_env;
|
| module_env.module = this;
|
| - module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr);
|
| - module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr) + mem_size;
|
| - module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr);
|
| + module_env.instance = &instance;
|
| module_env.linker = &linker;
|
| - module_env.function_code = nullptr;
|
| - module_env.function_table = BuildFunctionTable(isolate, this);
|
| - module_env.memory = memory;
|
| - module_env.context = isolate->native_context();
|
| module_env.asm_js = false;
|
|
|
| // First pass: compile each function and initialize the code table.
|
| @@ -358,8 +387,8 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
| return MaybeHandle<JSObject>();
|
| }
|
| if (func.exported) {
|
| - function = compiler::CompileJSToWasmWrapper(isolate, &module_env, name,
|
| - code, module, index);
|
| + function = compiler::CompileJSToWasmWrapper(
|
| + isolate, &module_env, name, code, instance.js_object, index);
|
| }
|
| }
|
| if (!code.is_null()) {
|
| @@ -369,24 +398,25 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
| }
|
| if (func.exported) {
|
| // Exported functions are installed as read-only properties on the module.
|
| - JSObject::AddProperty(module, name, function, READ_ONLY);
|
| + JSObject::AddProperty(instance.js_object, name, function, READ_ONLY);
|
| }
|
| index++;
|
| }
|
|
|
| // Second pass: patch all direct call sites.
|
| - linker.Link(module_env.function_table, this->function_table);
|
| -
|
| - module->SetInternalField(kWasmModuleFunctionTable, Smi::FromInt(0));
|
| - module->SetInternalField(kWasmModuleCodeTable, *code_table);
|
| - return module;
|
| + linker.Link(instance.function_table, this->function_table);
|
| + instance.js_object->SetInternalField(kWasmModuleFunctionTable,
|
| + Smi::FromInt(0));
|
| + return instance.js_object;
|
| }
|
|
|
|
|
| Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) {
|
| DCHECK(IsValidFunction(index));
|
| if (linker) return linker->GetFunctionCode(index);
|
| - if (function_code) return function_code->at(index);
|
| + if (instance && instance->function_code) {
|
| + return instance->function_code->at(index);
|
| + }
|
| return Handle<Code>::null();
|
| }
|
|
|
| @@ -426,33 +456,30 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
|
|
|
| int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
|
| ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
|
| + WasmModuleInstance instance(module);
|
|
|
| - // Allocate temporary linear memory and globals.
|
| - size_t mem_size = 1 << module->min_mem_size_log2;
|
| - size_t globals_size = AllocateGlobalsOffsets(module->globals);
|
| + // Allocate and initialize the linear memory.
|
| + if (!AllocateMemory(&thrower, isolate, &instance)) {
|
| + return -1;
|
| + }
|
| + LoadDataSegments(module, instance.mem_start, instance.mem_size);
|
|
|
| - base::SmartArrayPointer<byte> mem_addr(new byte[mem_size]);
|
| - base::SmartArrayPointer<byte> globals_addr(new byte[globals_size]);
|
| + // Allocate the globals area if necessary.
|
| + if (!AllocateGlobals(&thrower, isolate, &instance)) {
|
| + return -1;
|
| + }
|
|
|
| - memset(mem_addr.get(), 0, mem_size);
|
| - memset(globals_addr.get(), 0, globals_size);
|
| + // Build the function table.
|
| + instance.function_table = BuildFunctionTable(isolate, module);
|
|
|
| // Create module environment.
|
| WasmLinker linker(isolate, module->functions->size());
|
| ModuleEnv module_env;
|
| module_env.module = module;
|
| - module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr.get());
|
| - module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr.get()) + mem_size;
|
| - module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr.get());
|
| + module_env.instance = &instance;
|
| module_env.linker = &linker;
|
| - module_env.function_code = nullptr;
|
| - module_env.function_table = BuildFunctionTable(isolate, module);
|
| module_env.asm_js = false;
|
|
|
| - // Load data segments.
|
| - // TODO(titzer): throw instead of crashing if segments don't fit in memory?
|
| - LoadDataSegments(module, mem_addr.get(), mem_size);
|
| -
|
| // Compile all functions.
|
| Handle<Code> main_code = Handle<Code>::null(); // record last code.
|
| int index = 0;
|
| @@ -479,7 +506,7 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
|
| return -1;
|
| }
|
|
|
| - linker.Link(module_env.function_table, module->function_table);
|
| + linker.Link(instance.function_table, instance.module->function_table);
|
|
|
| // Wrap the main code so it can be called as a JS function.
|
| Handle<String> name = isolate->factory()->NewStringFromStaticChars("main");
|
|
|