Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wasm] Add -wasm.page-size option #272

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions aeneas/src/main/CLOptions.v3
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ component CLOptions {
"Generate code that uses Wasm multivalue.");
def WASM_EXPORT_MEM = wasmOpt.newBoolOption("wasm.export-mem", true,
"Export the Wasm memory from generated modules.");
def WASM_PAGE_SIZE = wasmOpt.newSizeOption("wasm.page-size", 65536,
"Specify the Wasm memory page size (must be a power of 2).");
def MAIN_EXPORT = wasmOpt.newStringOption("main-export", "main",
"Specify the name of the main export from a generated Wasm module.");
def ENTRY_EXPORT = wasmOpt.newStringOption("entry-export", "entry",
Expand Down
12 changes: 10 additions & 2 deletions aeneas/src/wasm/WasmCodeGen.v3
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ class WasmCodeGen extends SsaMachGen {
WasmOp.I64_CONST.opcode,
WasmOp.I32_CONST.opcode => emitInt(a[a.length - 1]);
WasmOp.CALL.opcode => {
emitInt(a[a.length - 1]); // function_index
emitUint(a[a.length - 1]); // function_index
}
WasmOp.F32_CONST.opcode => {
var val = Operand.Immediate.!(a[0]).val;
Expand All @@ -590,7 +590,7 @@ class WasmCodeGen extends SsaMachGen {
else w.put_b64(i64.view(Float64Val.!(val).bits));
}
WasmOp.CALL_INDIRECT.opcode => {
emitInt(a[a.length - 1]); // type_index
emitUint(a[a.length - 1]); // type_index
w.putb(0); // reserved
}
}
Expand Down Expand Up @@ -620,6 +620,14 @@ class WasmCodeGen extends SsaMachGen {
_ => context.fail1("cannot convert immediate to int: %s", V3.renderVal(val));
}
}
def emitUint(o: Operand) {
var val = Operand.Immediate.!(o).val;
match (val) {
null => w.putb(0);
x: Box<int> => w.put_uleb32(u32.view(x.val));
_ => context.fail1("cannot convert immediate to unsigned int: %s", V3.renderVal(val));
}
}
def asmls(logAlign: int, a: Array<Operand>, offsetOperand: int) {
w.putb(logAlign); // flags = alignment
emitInt(a[offsetOperand]); // offset
Expand Down
40 changes: 28 additions & 12 deletions aeneas/src/wasm/WasmTarget.v3
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ component WasmComponent {
Aeneas.registerTarget(WasmTarget.new("wasm", false));
}
}
def WASM_PAGE_SIZE = 65536;
def WASM_MAGIC = 0x6d736100;
def MINIMUM_DATA_START_ADDR = 8u;
def MAXIMUM_DATA_START_ADDR = 0x8000_0000u;
def WASM_VERSION = 0x1;
def XXX: Terminal;

Expand Down Expand Up @@ -123,6 +124,13 @@ class WasmTarget extends Target {
def processIrClass(ic: IrClass) {
}
def emitWasmModule(context: SsaContext, rt: MachRuntime) -> DataWriter {
def pageSize = CLOptions.WASM_PAGE_SIZE.get();
if (!Ints.isPowerOf2(pageSize)) context.fail1("expected -wasm.page-size option to be a power of 2, got %d", pageSize);

var dataStartAddrOption = CLOptions.DATA_START_ADDR.get();
if (dataStartAddrOption > MAXIMUM_DATA_START_ADDR) context.fail1("-data-start-addr too large for Wasm target, got 0x%x", dataStartAddrOption);
def dataStartAddr = if(dataStartAddrOption < MINIMUM_DATA_START_ADDR, MINIMUM_DATA_START_ADDR, u32.view(dataStartAddrOption));

def prog = context.prog;
// Lower to machine level from V3 level
def config = MachLoweringConfig.new();
Expand Down Expand Up @@ -240,14 +248,21 @@ class WasmTarget extends Target {
//--------------------------------------------------------------------------------
out.startSection(WasmSection.MEMORY);
out.putb(1); // 1 memory
// add the size of initialized memory and runtime to the heap size
var initSize = u32.view(m.metaRegion.mark + m.dataRegion.mark);
var pages = 2u + u32.!((rt.heapSize + rt.shadowStackSize
+ initSize + u32.view(WASM_PAGE_SIZE - 1)) /
u32.view(WASM_PAGE_SIZE));
out.putb(1); // flags = contains maximum
out.put_uleb32(pages); // initial memory size
out.put_uleb32(pages); // maximum memory size
// Compute the maximum accessible data address
var maxDataAddr = dataStartAddr
+ u32.!(m.metaRegion.mark)
+ u32.!(m.dataRegion.mark)
+ u32.!(rt.heapSize + rt.shadowStackSize);

var pages = (maxDataAddr + pageSize - 1u) / pageSize;
var flags = 1;
if (pageSize != 65536) flags |= 1 << 3; // custom page size
out.putb(flags); // flags = contains maximum
out.put_uleb32(pages); // initial memory size
out.put_uleb32(pages); // maximum memory size
if (pageSize != 65536) {
out.put_uleb32(u32.!(Ints.log(pageSize))); // page size log
}
out.endSection();

// (7) Emit the export section
Expand Down Expand Up @@ -329,11 +344,11 @@ class WasmTarget extends Target {
out.putb(1); // 1 data entry
out.putb(0); // linear memory #0
out.putb(WasmOp.I32_CONST.opcode);
out.put_sleb32(WASM_PAGE_SIZE); // linear memory offset
out.put_sleb32(int.view(dataStartAddr)); // linear memory offset
out.putb(WasmOp.END.opcode);
var data_sizepos = out.skip_leb32(); // data size
var data_start = out.pos;
out.startAddr = WASM_PAGE_SIZE - out.end();
out.startAddr = int.view(dataStartAddr) - out.end();
// Encode meta region
m.layoutMeta(out);
// Encode runtime region
Expand Down Expand Up @@ -405,7 +420,8 @@ class WasmTarget extends Target {
.putx(abs)
.outln();
}
w.overwrite_uleb32(abs);
// TODO,XXX: address immediates are in i32.const, which is a signed LEB.
w.overwrite_sleb32(abs);
}
def emitTestWrappers(context: SsaContext, rt: MachRuntime, w: DataWriter, e: ExecuteTestCase) {
var prog = context.prog;
Expand Down
12 changes: 10 additions & 2 deletions lib/util/DataWriter.v3
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,22 @@ class DataWriter {
skipN(5);
return oldpos;
}
// Overwrite a 32-bit LEB at the current position.
// Overwrite a 32-bit unsigned LEB at the current position.
def overwrite_uleb32(val: int) -> this {
for (i < 4) {
putb(val | 0x80);
val >>= 7;
val >>>= 7;
}
putb(val);
}
// Overwrite a 32-bit signed LEB at the current position.
def overwrite_sleb32(val: int) -> this {
for (i < 4) {
putb(val | 0x80);
val >>= 7;
}
putb(val & 0x7F);
}
// Set the current position to {npos}.
def at(npos: int) -> this {
if (pos > max) max = pos; // remember the maximum pos
Expand Down
4 changes: 4 additions & 0 deletions lib/util/Ints.v3
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ component Ints {
def abs(a: int) -> u32 {
return u32.view(if(a < 0, 0 - a, a));
}
// Return {true} if {a} is a power of 2.
def isPowerOf2(a: u32) -> bool {
return (a & (a - 1)) == 0;
}
}

// Parse result for parsing integers and longs.
Expand Down
85 changes: 85 additions & 0 deletions test/core/big_mtable00.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//@execute =1893

class A { def m() -> int { return 33; } }

class B00 extends A { def m() -> int { return 0x00; } }
class B01 extends A { def m() -> int { return 0x01; } }
class B02 extends A { def m() -> int { return 0x02; } }
class B03 extends A { def m() -> int { return 0x03; } }
class B04 extends A { def m() -> int { return 0x04; } }
class B05 extends A { def m() -> int { return 0x05; } }
class B06 extends A { def m() -> int { return 0x06; } }
class B07 extends A { def m() -> int { return 0x07; } }
class B08 extends A { def m() -> int { return 0x08; } }
class B09 extends A { def m() -> int { return 0x09; } }
class B0A extends A { def m() -> int { return 0x0A; } }
class B0B extends A { def m() -> int { return 0x0B; } }
class B0C extends A { def m() -> int { return 0x0C; } }
class B0D extends A { def m() -> int { return 0x0D; } }
class B0E extends A { def m() -> int { return 0x0E; } }
class B0F extends A { def m() -> int { return 0x0F; } }

class B10 extends A { def m() -> int { return 0x10; } }
class B11 extends A { def m() -> int { return 0x11; } }
class B12 extends A { def m() -> int { return 0x12; } }
class B13 extends A { def m() -> int { return 0x13; } }
class B14 extends A { def m() -> int { return 0x14; } }
class B15 extends A { def m() -> int { return 0x15; } }
class B16 extends A { def m() -> int { return 0x16; } }
class B17 extends A { def m() -> int { return 0x17; } }
class B18 extends A { def m() -> int { return 0x18; } }
class B19 extends A { def m() -> int { return 0x19; } }
class B1A extends A { def m() -> int { return 0x1A; } }
class B1B extends A { def m() -> int { return 0x1B; } }
class B1C extends A { def m() -> int { return 0x1C; } }
class B1D extends A { def m() -> int { return 0x1D; } }
class B1E extends A { def m() -> int { return 0x1E; } }
class B1F extends A { def m() -> int { return 0x1F; } }

class B20 extends A { def m() -> int { return 0x20; } }
class B21 extends A { def m() -> int { return 0x21; } }
class B22 extends A { def m() -> int { return 0x22; } }
class B23 extends A { def m() -> int { return 0x23; } }
class B24 extends A { def m() -> int { return 0x24; } }
class B25 extends A { def m() -> int { return 0x25; } }
class B26 extends A { def m() -> int { return 0x26; } }
class B27 extends A { def m() -> int { return 0x27; } }
class B28 extends A { def m() -> int { return 0x28; } }
class B29 extends A { def m() -> int { return 0x29; } }
class B2A extends A { def m() -> int { return 0x2A; } }
class B2B extends A { def m() -> int { return 0x2B; } }
class B2C extends A { def m() -> int { return 0x2C; } }
class B2D extends A { def m() -> int { return 0x2D; } }
class B2E extends A { def m() -> int { return 0x2E; } }
class B2F extends A { def m() -> int { return 0x2F; } }

class B30 extends A { def m() -> int { return 0x30; } }
class B31 extends A { def m() -> int { return 0x31; } }
class B32 extends A { def m() -> int { return 0x32; } }
class B33 extends A { def m() -> int { return 0x33; } }
class B34 extends A { def m() -> int { return 0x34; } }
class B35 extends A { def m() -> int { return 0x35; } }
class B36 extends A { def m() -> int { return 0x36; } }
class B37 extends A { def m() -> int { return 0x37; } }
class B38 extends A { def m() -> int { return 0x38; } }
class B39 extends A { def m() -> int { return 0x39; } }
class B3A extends A { def m() -> int { return 0x3A; } }
class B3B extends A { def m() -> int { return 0x3B; } }
class B3C extends A { def m() -> int { return 0x3C; } }
class B3D extends A { def m() -> int { return 0x3D; } }
class B3E extends A { def m() -> int { return 0x3E; } }
class B3F extends A { def m() -> int { return 0x3F; } }

def array = [
A.new(),
B00.new(), B01.new(), B02.new(), B03.new(), B04.new(), B05.new(), B06.new(), B07.new(), B08.new(), B09.new(), B0A.new(), B0B.new(), B0C.new(), B0D.new(), B0E.new(),
B10.new(), B11.new(), B12.new(), B13.new(), B14.new(), B15.new(), B16.new(), B17.new(), B18.new(), B19.new(), B1A.new(), B1B.new(), B1C.new(), B1D.new(), B1E.new(),
B20.new(), B21.new(), B22.new(), B23.new(), B24.new(), B25.new(), B26.new(), B27.new(), B28.new(), B29.new(), B2A.new(), B2B.new(), B2C.new(), B2D.new(), B2E.new(),
B30.new(), B31.new(), B32.new(), B33.new(), B34.new(), B35.new(), B36.new(), B37.new(), B38.new(), B39.new(), B3A.new(), B3B.new(), B3C.new(), B3D.new(), B3E.new()
];

def main() -> int {
var sum = 0;
for (o in array) sum += o.m();
return sum;
}
85 changes: 85 additions & 0 deletions test/core/big_mtable01.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//@execute =1893

class A { def m() -> int { return 33; } }

class B00 extends A { def m() -> int { return 0x00; } }
class B01 extends A { def m() -> int { return 0x01; } }
class B02 extends A { def m() -> int { return 0x02; } }
class B03 extends A { def m() -> int { return 0x03; } }
class B04 extends A { def m() -> int { return 0x04; } }
class B05 extends A { def m() -> int { return 0x05; } }
class B06 extends A { def m() -> int { return 0x06; } }
class B07 extends A { def m() -> int { return 0x07; } }
class B08 extends A { def m() -> int { return 0x08; } }
class B09 extends A { def m() -> int { return 0x09; } }
class B0A extends A { def m() -> int { return 0x0A; } }
class B0B extends A { def m() -> int { return 0x0B; } }
class B0C extends A { def m() -> int { return 0x0C; } }
class B0D extends A { def m() -> int { return 0x0D; } }
class B0E extends A { def m() -> int { return 0x0E; } }
class B0F extends A { def m() -> int { return 0x0F; } }

class B10 extends A { def m() -> int { return 0x10; } }
class B11 extends A { def m() -> int { return 0x11; } }
class B12 extends A { def m() -> int { return 0x12; } }
class B13 extends A { def m() -> int { return 0x13; } }
class B14 extends A { def m() -> int { return 0x14; } }
class B15 extends A { def m() -> int { return 0x15; } }
class B16 extends A { def m() -> int { return 0x16; } }
class B17 extends A { def m() -> int { return 0x17; } }
class B18 extends A { def m() -> int { return 0x18; } }
class B19 extends A { def m() -> int { return 0x19; } }
class B1A extends A { def m() -> int { return 0x1A; } }
class B1B extends A { def m() -> int { return 0x1B; } }
class B1C extends A { def m() -> int { return 0x1C; } }
class B1D extends A { def m() -> int { return 0x1D; } }
class B1E extends A { def m() -> int { return 0x1E; } }
class B1F extends A { def m() -> int { return 0x1F; } }

class B20 extends A { def m() -> int { return 0x20; } }
class B21 extends A { def m() -> int { return 0x21; } }
class B22 extends A { def m() -> int { return 0x22; } }
class B23 extends A { def m() -> int { return 0x23; } }
class B24 extends A { def m() -> int { return 0x24; } }
class B25 extends A { def m() -> int { return 0x25; } }
class B26 extends A { def m() -> int { return 0x26; } }
class B27 extends A { def m() -> int { return 0x27; } }
class B28 extends A { def m() -> int { return 0x28; } }
class B29 extends A { def m() -> int { return 0x29; } }
class B2A extends A { def m() -> int { return 0x2A; } }
class B2B extends A { def m() -> int { return 0x2B; } }
class B2C extends A { def m() -> int { return 0x2C; } }
class B2D extends A { def m() -> int { return 0x2D; } }
class B2E extends A { def m() -> int { return 0x2E; } }
class B2F extends A { def m() -> int { return 0x2F; } }

class B30 extends A { def m() -> int { return 0x30; } }
class B31 extends A { def m() -> int { return 0x31; } }
class B32 extends A { def m() -> int { return 0x32; } }
class B33 extends A { def m() -> int { return 0x33; } }
class B34 extends A { def m() -> int { return 0x34; } }
class B35 extends A { def m() -> int { return 0x35; } }
class B36 extends A { def m() -> int { return 0x36; } }
class B37 extends A { def m() -> int { return 0x37; } }
class B38 extends A { def m() -> int { return 0x38; } }
class B39 extends A { def m() -> int { return 0x39; } }
class B3A extends A { def m() -> int { return 0x3A; } }
class B3B extends A { def m() -> int { return 0x3B; } }
class B3C extends A { def m() -> int { return 0x3C; } }
class B3D extends A { def m() -> int { return 0x3D; } }
class B3E extends A { def m() -> int { return 0x3E; } }
class B3F extends A { def m() -> int { return 0x3F; } }

def main() -> int {
def array = [
A.new(),
B00.new(), B01.new(), B02.new(), B03.new(), B04.new(), B05.new(), B06.new(), B07.new(), B08.new(), B09.new(), B0A.new(), B0B.new(), B0C.new(), B0D.new(), B0E.new(),
B10.new(), B11.new(), B12.new(), B13.new(), B14.new(), B15.new(), B16.new(), B17.new(), B18.new(), B19.new(), B1A.new(), B1B.new(), B1C.new(), B1D.new(), B1E.new(),
B20.new(), B21.new(), B22.new(), B23.new(), B24.new(), B25.new(), B26.new(), B27.new(), B28.new(), B29.new(), B2A.new(), B2B.new(), B2C.new(), B2D.new(), B2E.new(),
B30.new(), B31.new(), B32.new(), B33.new(), B34.new(), B35.new(), B36.new(), B37.new(), B38.new(), B39.new(), B3A.new(), B3B.new(), B3C.new(), B3D.new(), B3E.new()
];

var sum = 0;
for (o in array) sum += o.m();
return sum;
}