[wasm] Fix memory initialization on instantiate

Memory instantiate on initialize should always patch memory
references. If memory references are not patched for no initial
memory, on subsequent calls to grow_memory in wasm functions for
instances that share a module, the references will be patched
without resetting cloned compiled values to their correct initial
values.

BUG=chromium:763439

Change-Id: I666439332379b02aa344e99d61ef3dc88ab86cc8
Reviewed-on: https://chromium-review.googlesource.com/674707
Reviewed-by: Mircea Trofin <mtrofin@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Deepti Gandluri <gdeepti@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48097}
This commit is contained in:
Deepti Gandluri 2017-09-20 15:19:34 -07:00 committed by Commit Bot
parent c701bd2ebf
commit 327df0b8c2
3 changed files with 60 additions and 10 deletions

View File

@ -1013,27 +1013,29 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
//--------------------------------------------------------------------------
// Initialize memory.
//--------------------------------------------------------------------------
uint32_t mem_size = 0;
Address mem_start = nullptr;
// Stash old values of mem_start, and mem_size before
// SetSpecializationMemInfoFrom, to patch memory references
uint32_t old_mem_size = compiled_module_->GetEmbeddedMemSizeOrZero();
Address old_mem_start = compiled_module_->GetEmbeddedMemStartOrNull();
if (!memory_.is_null()) {
Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
Address mem_start = static_cast<Address>(memory->backing_store());
uint32_t mem_size;
mem_start = static_cast<Address>(memory->backing_store());
CHECK(memory->byte_length()->ToUint32(&mem_size));
LoadDataSegments(mem_start, mem_size);
uint32_t old_mem_size = compiled_module_->GetEmbeddedMemSizeOrZero();
Address old_mem_start = compiled_module_->GetEmbeddedMemStartOrNull();
// We might get instantiated again with the same memory. No patching
// needed in this case.
if (old_mem_start != mem_start || old_mem_size != mem_size) {
code_specialization.RelocateMemoryReferences(old_mem_start, old_mem_size,
mem_start, mem_size);
}
// Just like with globals, we need to keep both the JSArrayBuffer
// and save the start pointer.
instance->set_memory_buffer(*memory);
WasmCompiledModule::SetSpecializationMemInfoFrom(factory, compiled_module_,
memory);
}
// We might get instantiated again with the same memory. No patching
// needed in this case.
code_specialization.RelocateMemoryReferences(old_mem_start, old_mem_size,
mem_start, mem_size);
//--------------------------------------------------------------------------
// Set up the runtime support for the new instance.

View File

@ -0,0 +1,22 @@
// Copyright 2017 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.
load('test/mjsunit/wasm/wasm-constants.js');
load('test/mjsunit/wasm/wasm-module-builder.js');
var builder = new WasmModuleBuilder();
builder.addMemory(0, 1234, false);
builder.addFunction('f', kSig_i_v)
.addBody([
kExprI32Const, 0x1d, // --
kExprGrowMemory, 0x00, // --
kExprI32LoadMem, 0x00, 0xff, 0xff, 0x45, // --
])
.exportFunc();
var module = new WebAssembly.Module(builder.toBuffer());
var instance1 = new WebAssembly.Instance(module);
instance1.exports.f();
var instance2 = new WebAssembly.Instance(module);
instance2.exports.f();

View File

@ -442,3 +442,29 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertEquals(0, buffer.byteLength);
assertEquals(3*kPageSize, memory.buffer.byteLength);
})();
(function TestInitialMemorySharedModule() {
print("TestInitialMemorySharedModule");
var builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "imported_mem");
builder.addFunction('f', kSig_i_v)
.addBody([
kExprI32Const, 0x1d, // --
kExprI32Const, 0x20, // --
kExprI32StoreMem, 0, 0, // --
kExprI32Const, 0x1d, // --
kExprI32LoadMem, 0, 0, // --
])
.exportFunc();
// First instance load/store success
var module = new WebAssembly.Module(builder.toBuffer());
let memory1= new WebAssembly.Memory({initial: 1, maximum: 20});
let instance1 = new WebAssembly.Instance(module, {m: {imported_mem: memory1}});
assertEquals(0x20, instance1.exports.f());
// Second instance should trap as it has no initial memory
let memory2= new WebAssembly.Memory({initial: 0, maximum: 2});
let instance2 = new WebAssembly.Instance(module, {m: {imported_mem: memory2}});
assertTraps(kTrapMemOutOfBounds, () => instance2.exports.f());
})();