Commit 640ae3f9 authored by titzer's avatar titzer Committed by Commit bot

[wasm] Base address for data segments can also be the value of a global variable.

R=rossberg@chromium.org
BUG=chromium:575167

Review-Url: https://codereview.chromium.org/2403823002
Cr-Commit-Position: refs/heads/master@{#40121}
parent 879fac3b
......@@ -90,7 +90,7 @@ enum WasmGlobalInitData {
};
enum WasmSegmentInfo {
kDestInitKind, // 0 = constant, 1 = global index
kDestAddrKind, // 0 = constant, 1 = global index
kDestAddrValue, // Smi. an uint32_t
kSourceSize, // Smi. an uint32_t
kWasmSegmentInfoSize // Sentinel value.
......@@ -127,9 +127,18 @@ void SaveDataSegmentInfo(Factory* factory, const WasmModule* module,
if (segment.source_size == 0) continue;
Handle<ByteArray> js_segment =
factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED);
// TODO(titzer): add support for global offsets for dest_addr
CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind);
js_segment->set_int(kDestAddrValue, segment.dest_addr.val.i32_const);
if (segment.dest_addr.kind == WasmInitExpr::kGlobalIndex) {
// The destination address is the value of a global variable.
js_segment->set_int(kDestAddrKind, 1);
uint32_t offset =
module->globals[segment.dest_addr.val.global_index].offset;
js_segment->set_int(kDestAddrValue, static_cast<int>(offset));
} else {
// The destination address is a constant.
CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind);
js_segment->set_int(kDestAddrKind, 0);
js_segment->set_int(kDestAddrValue, segment.dest_addr.val.i32_const);
}
js_segment->set_int(kSourceSize, segment.source_size);
segments->set(i, *js_segment);
data->copy_in(last_insertion_pos,
......@@ -1275,6 +1284,11 @@ class WasmInstanceBuilder {
int num_imported_functions = ProcessImports(globals, code_table, instance);
if (num_imported_functions < 0) return nothing;
//--------------------------------------------------------------------------
// Process the initialization for the module's globals.
//--------------------------------------------------------------------------
ProcessInits(globals);
//--------------------------------------------------------------------------
// Set up the memory for the new instance.
//--------------------------------------------------------------------------
......@@ -1295,7 +1309,7 @@ class WasmInstanceBuilder {
Address mem_start = static_cast<Address>(memory_->backing_store());
uint32_t mem_size =
static_cast<uint32_t>(memory_->byte_length()->Number());
LoadDataSegments(mem_start, mem_size);
LoadDataSegments(globals, mem_start, mem_size);
uint32_t old_mem_size = compiled_module_->has_heap()
? compiled_module_->mem_size()
......@@ -1309,11 +1323,6 @@ class WasmInstanceBuilder {
compiled_module_->set_heap(memory_);
}
//--------------------------------------------------------------------------
// Process the initialization for the module's globals.
//--------------------------------------------------------------------------
ProcessInits(globals);
//--------------------------------------------------------------------------
// Set up the runtime support for the new instance.
//--------------------------------------------------------------------------
......@@ -1502,7 +1511,8 @@ class WasmInstanceBuilder {
}
// Load data segments into the memory.
void LoadDataSegments(Address mem_addr, size_t mem_size) {
void LoadDataSegments(MaybeHandle<JSArrayBuffer> globals, Address mem_addr,
size_t mem_size) {
CHECK(compiled_module_->has_data_segments() ==
compiled_module_->has_data_segments_info());
......@@ -1518,6 +1528,12 @@ class WasmInstanceBuilder {
Handle<ByteArray>(ByteArray::cast(segments->get(i)));
uint32_t dest_addr =
static_cast<uint32_t>(segment->get_int(kDestAddrValue));
if (segment->get_int(kDestAddrKind) == 1) {
// The destination address is the value of a global variable.
dest_addr =
*reinterpret_cast<uint32_t*>(raw_buffer_ptr(globals, dest_addr));
}
uint32_t source_size =
static_cast<uint32_t>(segment->get_int(kSourceSize));
CHECK_LT(dest_addr, mem_size);
......
// 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");
var debug = false;
function SimpleDataSegmentTest(offset) {
print("SimpleDataSegmentTest(" + offset + ")...");
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, false);
builder.addFunction("load", kSig_i_i)
.addBody([kExprGetLocal, 0, kExprI32LoadMem, 0, 0])
.exportAs("load");
builder.addDataSegment(offset, [9, 9, 9, 9]);
var buffer = builder.toBuffer(debug);
var instance = Wasm.instantiateModule(buffer);
for (var i = offset - 20; i < offset + 20; i += 4) {
if (i < 0) continue;
var expected = (i == offset) ? 151587081 : 0;
assertEquals(expected, instance.exports.load(i));
}
}
SimpleDataSegmentTest(0);
SimpleDataSegmentTest(4);
SimpleDataSegmentTest(12);
SimpleDataSegmentTest(1064);
function GlobalInitTest(offset) {
print("GlobalInitTest(" + offset + ")...");
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, false);
var g = builder.addGlobal(kAstI32, false);
g.init = offset;
builder.addFunction("load", kSig_i_i)
.addBody([kExprGetLocal, 0, kExprI32LoadMem, 0, 0])
.exportAs("load");
builder.addDataSegment(g.index, [7, 7, 7, 7], true);
var buffer = builder.toBuffer(debug);
var instance = Wasm.instantiateModule(buffer);
for (var i = offset - 20; i < offset + 20; i += 4) {
if (i < 0) continue;
var expected = i == offset ? 117901063 : 0;
assertEquals(expected, instance.exports.load(i));
}
}
GlobalInitTest(0);
GlobalInitTest(12);
GlobalInitTest(3040);
function GlobalImportedInitTest(pad) {
print("GlobaleImportedInitTest(" + pad + ")...");
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, false);
while (pad-- > 0) builder.addGlobal(kAstI32); // pad
var g = builder.addImportedGlobal("offset", undefined, kAstI32);
while (pad-- > 0) builder.addGlobal(kAstI32); // pad
builder.addFunction("load", kSig_i_i)
.addBody([kExprGetLocal, 0, kExprI32LoadMem, 0, 0])
.exportAs("load");
builder.addDataSegment(g.index, [5, 5, 5, 5], true);
var buffer = builder.toBuffer(debug);
var module = new WebAssembly.Module(buffer);
for (var offset of [0, 12, 192, 1024]) {
var instance = new WebAssembly.Instance(module, {offset: offset});
for (var i = offset - 20; i < offset + 20; i += 4) {
if (i < 0) continue;
var expected = i == offset ? 84215045 : 0;
assertEquals(expected, instance.exports.load(i));
}
}
}
GlobalImportedInitTest(0);
GlobalImportedInitTest(1);
GlobalImportedInitTest(4);
......@@ -105,7 +105,7 @@ var debug = true;
module.addFunction("load", kSig_i_i)
.addBody([kExprGetLocal, 0, kExprI32LoadMem, 0, 0])
.exportAs("load");
module.addDataSegment(0, [9, 9, 9, 9], true);
module.addDataSegment(0, [9, 9, 9, 9]);
var buffer = module.toBuffer(debug);
var instance = Wasm.instantiateModule(buffer);
......
......@@ -199,8 +199,8 @@ class WasmModuleBuilder {
this.imports.push(o);
}
addDataSegment(addr, data, init) {
this.segments.push({addr: addr, data: data, init: init});
addDataSegment(addr, data, is_global = false) {
this.segments.push({addr: addr, data: data, is_global: is_global});
return this.segments.length - 1;
}
......@@ -444,8 +444,15 @@ class WasmModuleBuilder {
section.emit_u32v(wasm.segments.length);
for (let seg of wasm.segments) {
section.emit_u8(0); // linear memory index 0
section.emit_u8(kExprI32Const);
section.emit_u32v(seg.addr);
if (seg.is_global) {
// initializer is a global variable
section.emit_u8(kExprGetGlobal);
section.emit_u32v(seg.addr);
} else {
// initializer is a constant
section.emit_u8(kExprI32Const);
section.emit_u32v(seg.addr);
}
section.emit_u8(kExprEnd);
section.emit_u32v(seg.data.length);
section.emit_bytes(seg.data);
......
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