Added support for parsing tables
This commit is contained in:
parent
a15e0c06ca
commit
b39fb34942
3 changed files with 111 additions and 63 deletions
|
|
@ -21,7 +21,7 @@ globalValues: []vm.Value,
|
||||||
globalTypes: []Globaltype,
|
globalTypes: []Globaltype,
|
||||||
|
|
||||||
const Parser = @This();
|
const Parser = @This();
|
||||||
const PAGE_SIZE = 65536;
|
pub const PAGE_SIZE = 65536;
|
||||||
|
|
||||||
pub const Error = error{
|
pub const Error = error{
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
|
|
@ -93,7 +93,6 @@ pub fn module(self: *Parser) vm.Module {
|
||||||
.min = self.memory.lim.min,
|
.min = self.memory.lim.min,
|
||||||
.max = self.memory.lim.max,
|
.max = self.memory.lim.max,
|
||||||
},
|
},
|
||||||
.imported_funcs = self.importCount,
|
|
||||||
.exported_memory = self.exported_memory,
|
.exported_memory = self.exported_memory,
|
||||||
.functions = self.functions,
|
.functions = self.functions,
|
||||||
.exports = self.exports,
|
.exports = self.exports,
|
||||||
|
|
@ -184,6 +183,14 @@ pub fn parseVector(self: *Parser, parse_fn: anytype) ![]VectorFnResult(parse_fn)
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
pub fn parseVectorU32(self: *Parser) ![]u32 {
|
||||||
|
const n = try self.readU32();
|
||||||
|
const ret = try self.allocator.alloc(u32, n);
|
||||||
|
for (ret) |*i| {
|
||||||
|
i.* = try self.readU32();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
fn parseNumtype(self: *Parser) !std.wasm.Valtype {
|
fn parseNumtype(self: *Parser) !std.wasm.Valtype {
|
||||||
return switch (try self.readByte()) {
|
return switch (try self.readByte()) {
|
||||||
|
|
@ -387,6 +394,8 @@ fn parseImportsec(self: *Parser) !void {
|
||||||
} else {
|
} else {
|
||||||
std.debug.panic("imported function {s} not supported\n", .{i.name});
|
std.debug.panic("imported function {s} not supported\n", .{i.name});
|
||||||
}
|
}
|
||||||
|
self.functions = try self.allocator.realloc(self.functions, index + 1);
|
||||||
|
self.functions[index].typ = .{ .external = index };
|
||||||
index += 1;
|
index += 1;
|
||||||
},
|
},
|
||||||
.mem => {
|
.mem => {
|
||||||
|
|
@ -413,10 +422,10 @@ fn parseFuncsec(self: *Parser) !void {
|
||||||
const types = try self.parseVector(Parser.readU32);
|
const types = try self.parseVector(Parser.readU32);
|
||||||
defer self.allocator.free(types);
|
defer self.allocator.free(types);
|
||||||
|
|
||||||
if (self.functions.len != 0) return Error.duplicated_funcsec;
|
if (self.functions.len != self.importCount) return Error.duplicated_funcsec;
|
||||||
self.functions = try self.allocator.alloc(vm.Function, types.len);
|
self.functions = try self.allocator.realloc(self.functions, self.importCount + types.len);
|
||||||
|
|
||||||
for (types, 0..) |t, i| {
|
for (types, self.importCount..) |t, i| {
|
||||||
self.functions[i].func_type = .{
|
self.functions[i].func_type = .{
|
||||||
.parameters = try self.allocator.alloc(vm.Valtype, self.types[t].parameters.len),
|
.parameters = try self.allocator.alloc(vm.Valtype, self.types[t].parameters.len),
|
||||||
.returns = try self.allocator.alloc(vm.Valtype, self.types[t].returns.len),
|
.returns = try self.allocator.alloc(vm.Valtype, self.types[t].returns.len),
|
||||||
|
|
@ -426,7 +435,7 @@ fn parseFuncsec(self: *Parser) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(ernesto): run this check not only in debug
|
// TODO(ernesto): run this check not only in debug
|
||||||
std.debug.assert(types.len == self.functions.len);
|
std.debug.assert(types.len + self.importCount == self.functions.len);
|
||||||
|
|
||||||
// TODO: run this check not only on debug
|
// TODO: run this check not only on debug
|
||||||
std.debug.assert(self.byte_idx == end_idx);
|
std.debug.assert(self.byte_idx == end_idx);
|
||||||
|
|
@ -547,7 +556,7 @@ fn parseExportsec(self: *Parser) !void {
|
||||||
switch (e.exportdesc) {
|
switch (e.exportdesc) {
|
||||||
.func => {
|
.func => {
|
||||||
if (std.mem.eql(u8, e.name, "init")) {
|
if (std.mem.eql(u8, e.name, "init")) {
|
||||||
self.exports.init = e.exportdesc.func;
|
self.exports.init = e.exportdesc.func + self.importCount;
|
||||||
} else {
|
} else {
|
||||||
std.log.warn("exported function {s} not supported\n", .{e.name});
|
std.log.warn("exported function {s} not supported\n", .{e.name});
|
||||||
}
|
}
|
||||||
|
|
@ -690,9 +699,9 @@ fn parseCodesec(self: *Parser) !void {
|
||||||
const codes = try self.parseVector(Parser.parseCode);
|
const codes = try self.parseVector(Parser.parseCode);
|
||||||
defer self.allocator.free(codes);
|
defer self.allocator.free(codes);
|
||||||
// TODO: run this check not only on debug
|
// TODO: run this check not only on debug
|
||||||
std.debug.assert(codes.len == self.functions.len);
|
std.debug.assert(codes.len == self.functions.len - self.importCount);
|
||||||
|
|
||||||
for (codes, self.functions) |code, *f| {
|
for (codes, self.functions[self.importCount..]) |code, *f| {
|
||||||
f.typ = .{ .internal = .{
|
f.typ = .{ .internal = .{
|
||||||
.locals = code.locals,
|
.locals = code.locals,
|
||||||
.ir = code.ir,
|
.ir = code.ir,
|
||||||
|
|
|
||||||
|
|
@ -603,7 +603,9 @@ const IRParserState = struct {
|
||||||
parser: *Parser,
|
parser: *Parser,
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
|
||||||
branches: std.AutoHashMapUnmanaged(u32, u32),
|
// branches: std.AutoHashMapUnmanaged(u32, u32),
|
||||||
|
branches: std.ArrayListUnmanaged( struct { pc: u32, index: u32, table: bool } ),
|
||||||
|
br_table_vectors: std.ArrayListUnmanaged(u32),
|
||||||
|
|
||||||
opcodes: std.ArrayListUnmanaged(Opcode),
|
opcodes: std.ArrayListUnmanaged(Opcode),
|
||||||
indices: std.ArrayListUnmanaged(Index),
|
indices: std.ArrayListUnmanaged(Index),
|
||||||
|
|
@ -628,7 +630,8 @@ const IRParserState = struct {
|
||||||
0x02...0x03 => self.parseBlock(b),
|
0x02...0x03 => self.parseBlock(b),
|
||||||
0x04 => self.parseIf(),
|
0x04 => self.parseIf(),
|
||||||
0x0C...0x0D => self.parseBranch(b),
|
0x0C...0x0D => self.parseBranch(b),
|
||||||
0x0E => self.parseTableBranch(b),
|
// 0x0E => self.parseTableBranch(b),
|
||||||
|
0x0E => self.parseBrTable(b),
|
||||||
0x0F => self.push(@enumFromInt(b), .{ .u64 = 0 }),
|
0x0F => self.push(@enumFromInt(b), .{ .u64 = 0 }),
|
||||||
0x10 => self.push(@enumFromInt(b), .{ .u32 = try self.parser.readU32() }),
|
0x10 => self.push(@enumFromInt(b), .{ .u32 = try self.parser.readU32() }),
|
||||||
0x11 => self.push(@enumFromInt(b), .{ .indirect = .{ .y = try self.parser.readU32(), .x = try self.parser.readU32() } }),
|
0x11 => self.push(@enumFromInt(b), .{ .indirect = .{ .y = try self.parser.readU32(), .x = try self.parser.readU32() } }),
|
||||||
|
|
@ -790,40 +793,44 @@ const IRParserState = struct {
|
||||||
var todel: std.ArrayListUnmanaged(u32) = .{};
|
var todel: std.ArrayListUnmanaged(u32) = .{};
|
||||||
defer todel.deinit(self.allocator);
|
defer todel.deinit(self.allocator);
|
||||||
|
|
||||||
var it = self.branches.iterator();
|
var idx: u32 = 0;
|
||||||
while (it.next()) |branch| {
|
for (self.branches.items) |branch| {
|
||||||
if (start <= branch.key_ptr.* and branch.key_ptr.* < end) {
|
if (start <= branch.pc and branch.pc < end) {
|
||||||
if (branch.value_ptr.* == 0) {
|
const ptr = if (branch.table) &self.br_table_vectors.items[branch.index] else &self.indices.items[branch.index].u32;
|
||||||
self.indices.items[branch.key_ptr.*].u32 = jump_addr;
|
if (ptr.* == 0) {
|
||||||
try todel.append(self.allocator, branch.key_ptr.*);
|
ptr.* = jump_addr;
|
||||||
|
try todel.append(self.allocator, @intCast(idx));
|
||||||
|
idx += 1;
|
||||||
} else {
|
} else {
|
||||||
branch.value_ptr.* -= 1;
|
ptr.* -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(ernesto): need better way of deleting from the array (this looks ugly)
|
||||||
|
std.mem.sort(u32, todel.items, {}, comptime std.sort.desc(u32));
|
||||||
for (todel.items) |d| {
|
for (todel.items) |d| {
|
||||||
// TODO: Do we need to assert this is true?
|
// TODO: Do we need to assert this is true?
|
||||||
_ = self.branches.remove(d);
|
_ = self.branches.swapRemove(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseBranch(self: *IRParserState, b: u8) !void {
|
fn parseBranch(self: *IRParserState, b: u8) !void {
|
||||||
const idx = try self.parser.readU32();
|
const idx = try self.parser.readU32();
|
||||||
try self.branches.put(self.allocator, @intCast(self.opcodes.items.len), idx);
|
try self.branches.append(self.allocator, .{ .pc = @intCast(self.opcodes.items.len), .index = @intCast(self.indices.items.len), .table = false });
|
||||||
try self.push(@enumFromInt(b), .{ .u64 = 0 });
|
try self.push(@enumFromInt(b), .{ .u32 = idx });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseTableBranch(self: *IRParserState, b: u8) !void {
|
fn parseBrTable(self: *IRParserState, b: u8) !void {
|
||||||
const n = try self.parser.readU32();
|
const idxs = try self.parser.parseVectorU32();
|
||||||
const idxs = try self.allocator.alloc(u32, n);
|
const idxN = try self.parser.readU32();
|
||||||
// defer self.allocator.free(idxs);
|
const table_vectors_len = self.br_table_vectors.items.len;
|
||||||
for (idxs) |*i| {
|
try self.br_table_vectors.appendSlice(self.allocator, idxs);
|
||||||
i.* = try self.parser.readU32();
|
try self.br_table_vectors.append(self.allocator, idxN);
|
||||||
try self.branches.put(self.allocator, @intCast(self.opcodes.items.len), i.*);
|
for (0..idxs.len+1) |i| {
|
||||||
|
try self.branches.append(self.allocator, .{ .pc = @intCast(self.opcodes.items.len), .index = @intCast(table_vectors_len + i), .table = true });
|
||||||
}
|
}
|
||||||
try self.branches.put(self.allocator, @intCast(self.opcodes.items.len), try self.parser.readU32());
|
try self.push(@enumFromInt(b), .{ .indirect = .{ .x = @intCast(table_vectors_len), .y = @intCast(idxs.len) }});
|
||||||
try self.push(@enumFromInt(b), .{ .u64 = 0 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseVector(self: *IRParserState) !void {
|
fn parseVector(self: *IRParserState) !void {
|
||||||
|
|
@ -848,6 +855,7 @@ const IRParserState = struct {
|
||||||
|
|
||||||
pub fn parse(parser: *Parser) !IR {
|
pub fn parse(parser: *Parser) !IR {
|
||||||
var state = IRParserState{
|
var state = IRParserState{
|
||||||
|
.br_table_vectors = .{},
|
||||||
.opcodes = .{},
|
.opcodes = .{},
|
||||||
.indices = .{},
|
.indices = .{},
|
||||||
.branches = .{},
|
.branches = .{},
|
||||||
|
|
@ -855,7 +863,7 @@ pub fn parse(parser: *Parser) !IR {
|
||||||
.allocator = parser.allocator,
|
.allocator = parser.allocator,
|
||||||
};
|
};
|
||||||
try state.parseFunction();
|
try state.parseFunction();
|
||||||
if (state.branches.count() != 0) return Parser.Error.unresolved_branch;
|
// if (state.branches.count() != 0) return Parser.Error.unresolved_branch;
|
||||||
return .{
|
return .{
|
||||||
.opcodes = try state.opcodes.toOwnedSlice(state.allocator),
|
.opcodes = try state.opcodes.toOwnedSlice(state.allocator),
|
||||||
.indices = try state.indices.toOwnedSlice(state.allocator),
|
.indices = try state.indices.toOwnedSlice(state.allocator),
|
||||||
|
|
@ -865,6 +873,7 @@ pub fn parse(parser: *Parser) !IR {
|
||||||
|
|
||||||
pub fn parseGlobalExpr(parser: *Parser) !IR {
|
pub fn parseGlobalExpr(parser: *Parser) !IR {
|
||||||
var state = IRParserState{
|
var state = IRParserState{
|
||||||
|
.br_table_vectors = .{},
|
||||||
.opcodes = .{},
|
.opcodes = .{},
|
||||||
.indices = .{},
|
.indices = .{},
|
||||||
.branches = .{},
|
.branches = .{},
|
||||||
|
|
@ -881,6 +890,7 @@ pub fn parseGlobalExpr(parser: *Parser) !IR {
|
||||||
|
|
||||||
pub fn parseSingleExpr(parser: *Parser) !IR {
|
pub fn parseSingleExpr(parser: *Parser) !IR {
|
||||||
var state = IRParserState{
|
var state = IRParserState{
|
||||||
|
.br_table_vectors = .{},
|
||||||
.opcodes = .{},
|
.opcodes = .{},
|
||||||
.indices = .{},
|
.indices = .{},
|
||||||
.branches = .{},
|
.branches = .{},
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ pub const Function = struct { func_type: Functype, typ: union(enum) {
|
||||||
locals: []Valtype,
|
locals: []Valtype,
|
||||||
ir: IR,
|
ir: IR,
|
||||||
},
|
},
|
||||||
external: void,
|
external: u32
|
||||||
} };
|
} };
|
||||||
|
|
||||||
pub const ExportFunction = enum {
|
pub const ExportFunction = enum {
|
||||||
|
|
@ -55,7 +55,6 @@ pub const Module = struct {
|
||||||
functions: []Function,
|
functions: []Function,
|
||||||
exports: Exports,
|
exports: Exports,
|
||||||
exported_memory: u32,
|
exported_memory: u32,
|
||||||
imported_funcs: u32,
|
|
||||||
data: []const u8,
|
data: []const u8,
|
||||||
tables: []Parser.Tabletype,
|
tables: []Parser.Tabletype,
|
||||||
elems: [][]u32,
|
elems: [][]u32,
|
||||||
|
|
@ -72,7 +71,7 @@ pub const Module = struct {
|
||||||
allocator.free(f.typ.internal.ir.select_valtypes);
|
allocator.free(f.typ.internal.ir.select_valtypes);
|
||||||
allocator.free(f.typ.internal.locals);
|
allocator.free(f.typ.internal.locals);
|
||||||
},
|
},
|
||||||
.external => @panic("UNIMPLEMENTED"),
|
.external => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allocator.free(self.functions);
|
allocator.free(self.functions);
|
||||||
|
|
@ -142,6 +141,7 @@ pub const Runtime = struct {
|
||||||
},
|
},
|
||||||
.br_table => @panic("UNIMPLEMENTED"),
|
.br_table => @panic("UNIMPLEMENTED"),
|
||||||
.@"return" => break :loop,
|
.@"return" => break :loop,
|
||||||
|
// TODO: Move this to callExternal
|
||||||
.call => {
|
.call => {
|
||||||
if (index.u32 == self.module.exports.logDebug) {
|
if (index.u32 == self.module.exports.logDebug) {
|
||||||
const size: usize = @intCast(self.stack.pop().?.i64);
|
const size: usize = @intCast(self.stack.pop().?.i64);
|
||||||
|
|
@ -170,24 +170,24 @@ pub const Runtime = struct {
|
||||||
} else {
|
} else {
|
||||||
var parameters = std.ArrayList(Value).init(allocator);
|
var parameters = std.ArrayList(Value).init(allocator);
|
||||||
defer parameters.deinit();
|
defer parameters.deinit();
|
||||||
for (self.module.functions[index.u32 - self.module.imported_funcs].func_type.parameters) |_| {
|
for (self.module.functions[index.u32].func_type.parameters) |_| {
|
||||||
try parameters.append(self.stack.pop().?);
|
try parameters.append(self.stack.pop().?);
|
||||||
}
|
}
|
||||||
try self.call(allocator, index.u32 - self.module.imported_funcs, parameters.items);
|
try self.call(allocator, index.u32, parameters.items);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.call_indirect => {
|
.call_indirect => {
|
||||||
std.debug.panic("call_indirect: {any}\n", .{self.stack.pop().?});
|
|
||||||
if (self.module.tables[index.indirect.x].et != std.wasm.RefType.funcref) {
|
if (self.module.tables[index.indirect.x].et != std.wasm.RefType.funcref) {
|
||||||
std.debug.panic("Table at index {any} is not a `funcref` table\n", .{index.indirect.x});
|
std.debug.panic("Table at index {any} is not a `funcref` table\n", .{index.indirect.x});
|
||||||
}
|
}
|
||||||
const funcIdx = self.module.elems[index.indirect.x][index.indirect.y];
|
const j: u32 = @intCast(self.stack.pop().?.i32);
|
||||||
|
const funcIdx = self.module.elems[index.indirect.x][j];
|
||||||
var parameters = std.ArrayList(Value).init(allocator);
|
var parameters = std.ArrayList(Value).init(allocator);
|
||||||
defer parameters.deinit();
|
defer parameters.deinit();
|
||||||
for (self.module.functions[funcIdx - self.module.imported_funcs].func_type.parameters) |_| {
|
for (self.module.functions[funcIdx].func_type.parameters) |_| {
|
||||||
try parameters.append(self.stack.pop().?);
|
try parameters.append(self.stack.pop().?);
|
||||||
}
|
}
|
||||||
try self.call(allocator, funcIdx - self.module.imported_funcs, parameters.items);
|
try self.call(allocator, funcIdx, parameters.items);
|
||||||
},
|
},
|
||||||
|
|
||||||
.refnull => @panic("UNIMPLEMENTED"),
|
.refnull => @panic("UNIMPLEMENTED"),
|
||||||
|
|
@ -321,7 +321,12 @@ pub const Runtime = struct {
|
||||||
.i64_store32 => @panic("UNIMPLEMENTED"),
|
.i64_store32 => @panic("UNIMPLEMENTED"),
|
||||||
|
|
||||||
.memorysize => @panic("UNIMPLEMENTED"),
|
.memorysize => @panic("UNIMPLEMENTED"),
|
||||||
.memorygrow => @panic("UNIMPLEMENTED"),
|
.memorygrow => {
|
||||||
|
const newPages = self.stack.pop().?.i32;
|
||||||
|
const oldPages: i32 = @intCast(self.memory.len / Parser.PAGE_SIZE);
|
||||||
|
self.memory = try allocator.realloc(self.memory, self.memory.len + @as(usize, @intCast(newPages * Parser.PAGE_SIZE)));
|
||||||
|
try self.stack.append(.{ .i32 = oldPages });
|
||||||
|
},
|
||||||
.memoryinit => @panic("UNIMPLEMENTED"),
|
.memoryinit => @panic("UNIMPLEMENTED"),
|
||||||
.datadrop => @panic("UNIMPLEMENTED"),
|
.datadrop => @panic("UNIMPLEMENTED"),
|
||||||
.memorycopy => {
|
.memorycopy => {
|
||||||
|
|
@ -426,34 +431,36 @@ pub const Runtime = struct {
|
||||||
.f64_le => @panic("UNIMPLEMENTED"),
|
.f64_le => @panic("UNIMPLEMENTED"),
|
||||||
.f64_ge => @panic("UNIMPLEMENTED"),
|
.f64_ge => @panic("UNIMPLEMENTED"),
|
||||||
|
|
||||||
.i32_clz => @panic("UNIMPLEMENTED"),
|
.i32_clz => {
|
||||||
|
try self.stack.append(.{ .i32 = @clz(self.stack.pop().?.i32) });
|
||||||
|
},
|
||||||
.i32_ctz => @panic("UNIMPLEMENTED"),
|
.i32_ctz => @panic("UNIMPLEMENTED"),
|
||||||
.i32_popcnt => @panic("UNIMPLEMENTED"),
|
.i32_popcnt => @panic("UNIMPLEMENTED"),
|
||||||
.i32_add => {
|
.i32_add => {
|
||||||
const a = self.stack.pop().?.i32;
|
const a = self.stack.pop().?.i32;
|
||||||
const b = self.stack.pop().?.i32;
|
const b = self.stack.pop().?.i32;
|
||||||
try self.stack.append(Value{ .i32 = a + b });
|
try self.stack.append(.{ .i32 = a + b });
|
||||||
},
|
},
|
||||||
.i32_sub => {
|
.i32_sub => {
|
||||||
const a = self.stack.pop().?.i32;
|
const a = self.stack.pop().?.i32;
|
||||||
const b = self.stack.pop().?.i32;
|
const b = self.stack.pop().?.i32;
|
||||||
try self.stack.append(Value{ .i32 = b - a });
|
try self.stack.append(.{ .i32 = b - a });
|
||||||
},
|
},
|
||||||
.i32_and => {
|
.i32_and => {
|
||||||
const a = self.stack.pop().?.i32;
|
const a = self.stack.pop().?.i32;
|
||||||
const b = self.stack.pop().?.i32;
|
const b = self.stack.pop().?.i32;
|
||||||
try self.stack.append(Value{ .i32 = a & b });
|
try self.stack.append(.{ .i32 = a & b });
|
||||||
},
|
},
|
||||||
.i32_mul => {
|
.i32_mul => {
|
||||||
const a = self.stack.pop().?.i32;
|
const a = self.stack.pop().?.i32;
|
||||||
const b = self.stack.pop().?.i32;
|
const b = self.stack.pop().?.i32;
|
||||||
try self.stack.append(Value{ .i32 = a * b });
|
try self.stack.append(.{ .i32 = a * b });
|
||||||
},
|
},
|
||||||
.i32_div_s => @panic("UNIMPLEMENTED"),
|
.i32_div_s => @panic("UNIMPLEMENTED"),
|
||||||
.i32_div_u => {
|
.i32_div_u => {
|
||||||
const a_unsigned = @as(u32, @bitCast(self.stack.pop().?.i32));
|
const a_unsigned = @as(u32, @bitCast(self.stack.pop().?.i32));
|
||||||
const b_unsigned = @as(u32, @bitCast(self.stack.pop().?.i32));
|
const b_unsigned = @as(u32, @bitCast(self.stack.pop().?.i32));
|
||||||
try self.stack.append(Value{ .i32 = @bitCast(b_unsigned / a_unsigned) });
|
try self.stack.append(.{ .i32 = @bitCast(b_unsigned / a_unsigned) });
|
||||||
},
|
},
|
||||||
.i32_rem_s => @panic("UNIMPLEMENTED"),
|
.i32_rem_s => @panic("UNIMPLEMENTED"),
|
||||||
.i32_rem_u => {
|
.i32_rem_u => {
|
||||||
|
|
@ -462,32 +469,32 @@ pub const Runtime = struct {
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
std.debug.panic("Divide by 0\n", .{});
|
std.debug.panic("Divide by 0\n", .{});
|
||||||
}
|
}
|
||||||
try self.stack.append(Value{ .i32 = @intCast(dividend - divisor * @divTrunc(dividend, divisor)) });
|
try self.stack.append(.{ .i32 = @intCast(dividend - divisor * @divTrunc(dividend, divisor)) });
|
||||||
},
|
},
|
||||||
.i32_or => {
|
.i32_or => {
|
||||||
const a = self.stack.pop().?.i32;
|
const a = self.stack.pop().?.i32;
|
||||||
const b = self.stack.pop().?.i32;
|
const b = self.stack.pop().?.i32;
|
||||||
try self.stack.append(Value{ .i32 = a | b });
|
try self.stack.append(.{ .i32 = a | b });
|
||||||
},
|
},
|
||||||
.i32_xor => {
|
.i32_xor => {
|
||||||
const a = self.stack.pop().?.i32;
|
const a = self.stack.pop().?.i32;
|
||||||
const b = self.stack.pop().?.i32;
|
const b = self.stack.pop().?.i32;
|
||||||
try self.stack.append(Value{ .i32 = a ^ b });
|
try self.stack.append(.{ .i32 = a ^ b });
|
||||||
},
|
},
|
||||||
.i32_shl => {
|
.i32_shl => {
|
||||||
const a = self.stack.pop().?.i32;
|
const a = self.stack.pop().?.i32;
|
||||||
const b = self.stack.pop().?.i32;
|
const b = self.stack.pop().?.i32;
|
||||||
try self.stack.append(Value{ .i32 = (b << @as(u5, @intCast(a))) });
|
try self.stack.append(.{ .i32 = (b << @as(u5, @intCast(a))) });
|
||||||
},
|
},
|
||||||
.i32_shr_s => {
|
.i32_shr_s => {
|
||||||
const a = self.stack.pop().?.i32;
|
const a = self.stack.pop().?.i32;
|
||||||
const b = self.stack.pop().?.i32;
|
const b = self.stack.pop().?.i32;
|
||||||
try self.stack.append(Value{ .i32 = (b >> @as(u5, @intCast(a))) });
|
try self.stack.append(.{ .i32 = (b >> @as(u5, @intCast(a))) });
|
||||||
},
|
},
|
||||||
.i32_shr_u => {
|
.i32_shr_u => {
|
||||||
const a = @as(u32, @intCast(self.stack.pop().?.i32));
|
const a = @as(u32, @intCast(self.stack.pop().?.i32));
|
||||||
const b = @as(u32, @intCast(self.stack.pop().?.i32));
|
const b = @as(u32, @intCast(self.stack.pop().?.i32));
|
||||||
try self.stack.append(Value{ .i32 = @intCast(b >> @as(u5, @intCast(a))) });
|
try self.stack.append(.{ .i32 = @intCast(b >> @as(u5, @intCast(a))) });
|
||||||
},
|
},
|
||||||
.i32_rotl => @panic("UNIMPLEMENTED"),
|
.i32_rotl => @panic("UNIMPLEMENTED"),
|
||||||
.i32_rotr => @panic("UNIMPLEMENTED"),
|
.i32_rotr => @panic("UNIMPLEMENTED"),
|
||||||
|
|
@ -498,20 +505,40 @@ pub const Runtime = struct {
|
||||||
.i64_add => {
|
.i64_add => {
|
||||||
const a = self.stack.pop().?.i64;
|
const a = self.stack.pop().?.i64;
|
||||||
const b = self.stack.pop().?.i64;
|
const b = self.stack.pop().?.i64;
|
||||||
try self.stack.append(Value{ .i64 = a + b });
|
try self.stack.append(.{ .i64 = a + b });
|
||||||
|
},
|
||||||
|
.i64_sub => {
|
||||||
|
const a = self.stack.pop().?.i64;
|
||||||
|
const b = self.stack.pop().?.i64;
|
||||||
|
try self.stack.append(.{ .i64 = b - a });
|
||||||
|
},
|
||||||
|
.i64_mul => {
|
||||||
|
const a = self.stack.pop().?.i64;
|
||||||
|
const b = self.stack.pop().?.i64;
|
||||||
|
try self.stack.append(.{ .i64 = a * b });
|
||||||
},
|
},
|
||||||
.i64_sub => @panic("UNIMPLEMENTED"),
|
|
||||||
.i64_mul => @panic("UNIMPLEMENTED"),
|
|
||||||
.i64_div_s => @panic("UNIMPLEMENTED"),
|
.i64_div_s => @panic("UNIMPLEMENTED"),
|
||||||
.i64_div_u => @panic("UNIMPLEMENTED"),
|
.i64_div_u => @panic("UNIMPLEMENTED"),
|
||||||
.i64_rem_s => @panic("UNIMPLEMENTED"),
|
.i64_rem_s => @panic("UNIMPLEMENTED"),
|
||||||
.i64_rem_u => @panic("UNIMPLEMENTED"),
|
.i64_rem_u => @panic("UNIMPLEMENTED"),
|
||||||
.i64_and => @panic("UNIMPLEMENTED"),
|
.i64_and => {
|
||||||
|
const a = self.stack.pop().?.i64;
|
||||||
|
const b = self.stack.pop().?.i64;
|
||||||
|
try self.stack.append(.{ .i64 = a & b });
|
||||||
|
},
|
||||||
.i64_or => @panic("UNIMPLEMENTED"),
|
.i64_or => @panic("UNIMPLEMENTED"),
|
||||||
.i64_xor => @panic("UNIMPLEMENTED"),
|
.i64_xor => @panic("UNIMPLEMENTED"),
|
||||||
.i64_shl => @panic("UNIMPLEMENTED"),
|
.i64_shl => {
|
||||||
|
const a = self.stack.pop().?.i64;
|
||||||
|
const b = self.stack.pop().?.i64;
|
||||||
|
try self.stack.append(.{ .i64 = (b << @as(u6, @intCast(a))) });
|
||||||
|
},
|
||||||
.i64_shr_s => @panic("UNIMPLEMENTED"),
|
.i64_shr_s => @panic("UNIMPLEMENTED"),
|
||||||
.i64_shr_u => @panic("UNIMPLEMENTED"),
|
.i64_shr_u => {
|
||||||
|
const a = @as(u64, @intCast(self.stack.pop().?.i64));
|
||||||
|
const b = @as(u64, @intCast(self.stack.pop().?.i64));
|
||||||
|
try self.stack.append(.{ .i64 = @intCast(b >> @as(u6, @intCast(a))) });
|
||||||
|
},
|
||||||
.i64_rotl => @panic("UNIMPLEMENTED"),
|
.i64_rotl => @panic("UNIMPLEMENTED"),
|
||||||
.i64_rotr => @panic("UNIMPLEMENTED"),
|
.i64_rotr => @panic("UNIMPLEMENTED"),
|
||||||
|
|
||||||
|
|
@ -545,14 +572,16 @@ pub const Runtime = struct {
|
||||||
.f64_max => @panic("UNIMPLEMENTED"),
|
.f64_max => @panic("UNIMPLEMENTED"),
|
||||||
.f64_copysign => @panic("UNIMPLEMENTED"),
|
.f64_copysign => @panic("UNIMPLEMENTED"),
|
||||||
|
|
||||||
.i32_wrap_i64 => @panic("UNIMPLEMENTED"),
|
.i32_wrap_i64 => {
|
||||||
|
try self.stack.append(.{ .i32 = @truncate(self.stack.pop().?.i64) });
|
||||||
|
},
|
||||||
.i32_trunc_f32_s => @panic("UNIMPLEMENTED"),
|
.i32_trunc_f32_s => @panic("UNIMPLEMENTED"),
|
||||||
.i32_trunc_f32_u => @panic("UNIMPLEMENTED"),
|
.i32_trunc_f32_u => @panic("UNIMPLEMENTED"),
|
||||||
.i32_trunc_f64_s => @panic("UNIMPLEMENTED"),
|
.i32_trunc_f64_s => @panic("UNIMPLEMENTED"),
|
||||||
.i32_trunc_f64_u => @panic("UNIMPLEMENTED"),
|
.i32_trunc_f64_u => @panic("UNIMPLEMENTED"),
|
||||||
.i64_extend_i32_s => @panic("UNIMPLEMENTED"),
|
.i64_extend_i32_s => @panic("UNIMPLEMENTED"),
|
||||||
.i64_extend_i32_u => {
|
.i64_extend_i32_u => {
|
||||||
try self.stack.append(.{ .i64 = @as(u32, @intCast(self.stack.pop().?.i32)) });
|
try self.stack.append(.{ .i64 = @intCast(self.stack.pop().?.i32) });
|
||||||
},
|
},
|
||||||
.i64_trunc_f32_s => @panic("UNIMPLEMENTED"),
|
.i64_trunc_f32_s => @panic("UNIMPLEMENTED"),
|
||||||
.i64_trunc_f32_u => @panic("UNIMPLEMENTED"),
|
.i64_trunc_f32_u => @panic("UNIMPLEMENTED"),
|
||||||
|
|
@ -595,7 +624,7 @@ pub const Runtime = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Do name resolution at parseTime
|
// TODO: Do name resolution at parseTime
|
||||||
pub fn callExternal(self: *Runtime, allocator: Allocator, name: ExportFunction, parameters: []Value) !void {
|
pub fn externalCall(self: *Runtime, allocator: Allocator, name: ExportFunction, parameters: []Value) !void {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
.init => {
|
.init => {
|
||||||
if (self.module.exports.init) |func| {
|
if (self.module.exports.init) |func| {
|
||||||
|
|
@ -657,7 +686,7 @@ pub const Runtime = struct {
|
||||||
allocator.free(frame.locals);
|
allocator.free(frame.locals);
|
||||||
},
|
},
|
||||||
.external => {
|
.external => {
|
||||||
std.debug.panic("TODO: Handle external function {any}\n", .{function});
|
std.debug.panic("TODO: Handle external function {any} {any}\n", .{f.typ.external, self.module.exports});
|
||||||
// TODO(ernesto): handle external functions
|
// TODO(ernesto): handle external functions
|
||||||
// const name = self.module.imports[f.external].name;
|
// const name = self.module.imports[f.external].name;
|
||||||
// if (self.global_runtime.functions.get(name)) |external| {
|
// if (self.global_runtime.functions.get(name)) |external| {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue