Chromium Code Reviews| Index: src/wasm/wasm-module.cc |
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc |
| index 6e28f8757ca42423d141596cc1768395f7664f92..b4d51702d95197621f586ada808e976ee87a7f99 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 m |
|
bradnelson
2016/01/26 17:36:07
Something seems missing.
titzer
2016/01/27 09:03:52
Done.
|
| +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) |
|
bradnelson
2016/01/26 17:36:07
Use SetMemory rather than reach in?
titzer
2016/01/27 09:03:52
Just avoiding chained initialization (avoiding lat
|
| + << 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) { |
|
bradnelson
2016/01/26 17:36:07
Are you working towards allow us to set these for
titzer
2016/01/27 09:03:52
Mostly just factoring out the code to be shared by
|
| + 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"); |