diff options
author | luccie-cmd <luccie@sideros.org> | 2025-03-28 19:47:18 +0100 |
---|---|---|
committer | luccie-cmd <luccie@sideros.org> | 2025-03-28 19:48:15 +0100 |
commit | 8d39d3d4d02c89fd4fe4d07054b2d82f157bd326 (patch) | |
tree | 80d5ab1dc0c2fd7c210f826ae62399550c4d131c /src | |
parent | 964c25a66ce2ac06def03d76d72f138cb9a02e0a (diff) |
Added executing of mod IR in the WASM VM
Diffstat (limited to 'src')
-rw-r--r-- | src/mods/Parser.zig | 2 | ||||
-rw-r--r-- | src/mods/vm.zig | 992 |
2 files changed, 492 insertions, 502 deletions
diff --git a/src/mods/Parser.zig b/src/mods/Parser.zig index 6883fd3..48a8225 100644 --- a/src/mods/Parser.zig +++ b/src/mods/Parser.zig @@ -448,6 +448,7 @@ fn parseElemsec(self: *Parser) !void { pub const Func = struct { locals: []Valtype, code: []const u8, + ir: IR, }; const Local = struct { n: u32, @@ -477,6 +478,7 @@ fn parseCode(self: *Parser) !Func { const func = Func{ .locals = try self.allocator.alloc(Valtype, local_count), .code = &.{}, + .ir = ir, }; var li: usize = 0; diff --git a/src/mods/vm.zig b/src/mods/vm.zig index 1121550..413069f 100644 --- a/src/mods/vm.zig +++ b/src/mods/vm.zig @@ -1,6 +1,7 @@ const std = @import("std"); const wasm = @import("wasm.zig"); const Parser = @import("Parser.zig"); +const IR = @import("ir.zig"); const Allocator = std.mem.Allocator; const AllocationError = error{OutOfMemory}; @@ -34,83 +35,9 @@ pub const Module = struct { } }; -pub fn leb128Result(T: type) type { - return struct { len: usize, val: T }; -} - -pub fn leb128Decode_stream(comptime T: type, stream: anytype) !leb128Result(T) { - //switch (@typeInfo(T)) { - // .int => {}, - // else => @compileError("LEB128 integer decoding only support integers, but got " ++ @typeName(T)), - //} - - //if (@typeInfo(T).int.bits != 32 and @typeInfo(T).int.bits != 64) { - // @compileError("LEB128 integer decoding only supports 32 or 64 bits integers but got " ++ std.fmt.comptimePrint("{d} bits", .{@typeInfo(T).int.bits})); - //} - - //var result: T = 0; - //// TODO: is the type of shift important. Reading Wikipedia (not very much tho) it seems like we can use u32 and call it a day... - //var shift: if (@typeInfo(T).int.bits == 32) u5 else u6 = 0; - //var byte: u8 = undefined; - //var len: usize = 0; - //while (stream.readByte()) |b| { - // len += 1; - // result |= @as(T, @intCast((b & 0x7f))) << shift; - // if ((b & (0x1 << 7)) == 0) { - // byte = b; - // break; - // } - // shift += 7; - //} else |err| { - // return err; - //} - - //if (@typeInfo(T).int.signedness == .signed) { - // const size = @sizeOf(T) * 8; - // if (shift < size and (byte & 0x40) != 0) { - // result |= (~@as(T, 0) << shift); - // } - //} - - //return .{ .len = len, .val = result }; - - const start = try stream.context.getPos(); - const value = try switch (@typeInfo(T).int.signedness) { - .signed => std.leb.readIleb128(T, stream), - else => std.leb.readUleb128(T, stream), - }; - const end = try stream.context.getPos(); - - return .{ .len = end - start, .val = value }; -} - -fn leb128Decode(comptime T: type, bytes: []const u8) leb128Result(T) { - var fbs = std.io.fixedBufferStream(bytes); - // TODO: this catch should be unrecheable - return leb128Decode_stream(T, fbs.reader()) catch .{ .len = 0, .val = 0 }; -} - -pub fn decodeLittleEndian(comptime T: type, bytes: []u8) T { - if (T != i32 and T != i64) { - return @as(T, 0); - } else { - var value = @as(T, 0); - for (0..@sizeOf(T)) |b| { - value |= ((bytes[b]) << @intCast((@sizeOf(T) - b - 1))); - } - return value; - } -} - -pub fn encodeLittleEndian(comptime T: type, bytes: *[]u8, value: T) void { - for (0..@sizeOf(T)) |b| { - bytes.*[b] = @intCast(((value >> @intCast((@sizeOf(T) - b - 1))) & 0xff)); - } -} - pub const CallFrame = struct { program_counter: usize, - code: []const u8, + code: IR, locals: []Value, }; @@ -127,10 +54,8 @@ pub const Value = union(ValueType) { pub const Runtime = struct { module: Module, stack: std.ArrayList(Value), - call_stack: std.ArrayList(CallFrame), memory: []u8, global_runtime: *wasm.GlobalRuntime, - labels: std.ArrayList(usize), pub fn init(allocator: Allocator, module: Module, global_runtime: *wasm.GlobalRuntime) !Runtime { // if memory max is not set the memory is allowed to grow but it is not supported at the moment @@ -142,8 +67,6 @@ pub const Runtime = struct { return Runtime{ .module = module, .stack = try std.ArrayList(Value).initCapacity(allocator, 10), - .call_stack = try std.ArrayList(CallFrame).initCapacity(allocator, 5), - .labels = try std.ArrayList(usize).initCapacity(allocator, 2), .memory = memory, .global_runtime = global_runtime, }; @@ -152,460 +75,524 @@ pub const Runtime = struct { pub fn deinit(self: *Runtime, allocator: Allocator) void { self.module.deinit(allocator); self.stack.deinit(); - self.labels.deinit(); - self.call_stack.deinit(); allocator.free(self.memory); } - pub fn executeFrame(self: *Runtime, allocator: Allocator, frame: *CallFrame) !void { - var for_loop = false; + pub fn executeFrame(self: *Runtime, _: Allocator, frame: *CallFrame) !void { loop: while (true) { - const byte: u8 = frame.code[frame.program_counter]; - frame.program_counter += 1; - // std.debug.print("b: 0x{x} pc: 0x{x}\n", .{ byte, frame.program_counter-1 }); - switch (byte) { - 0x02 => { - var depth: usize = 1; - var pc = frame.program_counter; - while (depth > 0) { - const opcode = frame.code[pc]; - const operand = frame.code[pc + 1]; - if ((opcode == 0x02 and operand == 0x40) or (opcode == 0x03 and operand == 0x40) or (opcode == 0x04 and operand == 0x40)) { - depth += 1; - pc += 1; - } else if (opcode == 0x0B) { - depth -= 1; - } - pc += 1; - } - try self.labels.append(pc); - frame.program_counter += 1; + const opcode: IR.Opcode = frame.code.opcodes[frame.program_counter]; + switch (opcode) { + .br => { + // TODO(luccie-cmd): Branching like this is dangerous, we should do safety things or smth. + frame.program_counter = frame.code.indices[frame.program_counter].u32 - 1; }, - 0x03 => { - try self.labels.append(frame.program_counter - 1); - frame.program_counter += 1; - for_loop = true; - }, - 0x0c => { - const label = leb128Decode(u32, frame.code[frame.program_counter..]); - var address = @as(usize, 0); - for (0..(label.val + (if (label.val == 0) @as(u32, 1) else @as(u32, 0)))) |_| { - address = self.labels.pop().?; - } - frame.program_counter = address; - }, - 0x0d => { + .br_if => { if (self.stack.pop().?.i32 != 0) { - const label = leb128Decode(u32, frame.code[frame.program_counter..]); - var address = @as(usize, 0); - for (0..(label.val + (if (label.val == 0) @as(u32, 1) else @as(u32, 0)))) |_| { - address = self.labels.pop().?; - } - frame.program_counter = address; - } else { - frame.program_counter += 1; + // TODO(luccie-cmd): Branching like this is dangerous, we should do safety things or smth. + frame.program_counter = frame.code.indices[frame.program_counter].u32 - 1; } }, - - 0x20 => { - const integer = leb128Decode(u32, frame.code[frame.program_counter..]); - - frame.program_counter += integer.len; - try self.stack.append(frame.locals[integer.val]); + .localget => { + try self.stack.append(frame.locals[frame.code.indices[frame.program_counter].u32]); }, - 0x21 => { - const integer = leb128Decode(u32, frame.code[frame.program_counter..]); - - frame.program_counter += integer.len; - frame.locals[integer.val] = self.stack.pop().?; + .localset => { + const a = self.stack.pop().?; + frame.locals[frame.code.indices[frame.program_counter].u32] = a; }, - 0x22 => { - const integer = leb128Decode(u32, frame.code[frame.program_counter..]); - - frame.program_counter += integer.len; + .localtee => { const a = self.stack.pop().?; - frame.locals[integer.val] = a; try self.stack.append(a); + frame.locals[frame.code.indices[frame.program_counter].u32] = a; }, - 0x28 => { - const address = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += address.len; - const offset = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += offset.len; - const start = (address.val + offset.val); - const end = start + @sizeOf(u32); - try self.stack.append(Value{ .i32 = decodeLittleEndian(i32, self.memory[start..end]) }); - }, - 0x29 => { - const address = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += address.len; - const offset = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += offset.len; - const start = (address.val + offset.val); - const end = start + @sizeOf(u64); - try self.stack.append(Value{ .i64 = decodeLittleEndian(i64, self.memory[start..end]) }); - }, - 0x36 => { - const address = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += address.len; - const offset = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += offset.len; - const start = (address.val + offset.val); - const end = start + @sizeOf(u32); - try self.stack.append(Value{ .i32 = decodeLittleEndian(i32, self.memory[start..end]) }); - }, - 0x37 => { - const address = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += address.len; - const offset = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += offset.len; - const start = (address.val + offset.val); - const end = start + @sizeOf(u32); - encodeLittleEndian(i32, @constCast(&self.memory[start..end]), self.stack.pop().?.i32); + .i32_const => { + try self.stack.append(Value{ .i32 = frame.code.indices[frame.program_counter].i32 }); }, - 0x38 => { - const address = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += address.len; - const offset = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += offset.len; - const start = (address.val + offset.val); - const end = start + @sizeOf(u64); - encodeLittleEndian(i64, @constCast(&self.memory[start..end]), self.stack.pop().?.i64); - }, - 0x41 => { - const integer = leb128Decode(i32, frame.code[frame.program_counter..]); - - frame.program_counter += integer.len; - try self.stack.append(Value{ .i32 = integer.val }); + .i32_lt_u => { + const b = self.stack.pop().?.i32; + const a = self.stack.pop().?.i32; + try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(a < b))) }); }, - 0x42 => { - const integer = leb128Decode(i64, frame.code[frame.program_counter..]); - - frame.program_counter += integer.len; - try self.stack.append(Value{ .i64 = integer.val }); + .i32_ge_u => { + const b = self.stack.pop().?.i32; + const a = self.stack.pop().?.i32; + try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(a >= b))) }); }, - 0x45 => { + .i32_eqz => { try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 == 0))) }); }, - 0x46 => { - try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 == self.stack.pop().?.i32))) }); - }, - 0x47 => { - try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 != self.stack.pop().?.i32))) }); - }, - // 0x48 => { - // const a = self.stack.pop().?.i32; - // const b = self.stack.pop().?.i32; - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(b < a))) }); - // }, - 0x49 => { + .i32_add => { const a = self.stack.pop().?.i32; const b = self.stack.pop().?.i32; - try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(b < a))) }); + try self.stack.append(Value{ .i32 = a + b }); }, - // 0x4b => { - // const b = self.stack.pop().?.i32; - // const a = self.stack.pop().?.i32; - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(a > b))) }); - // }, - // 0x4d => { - // const b = self.stack.pop().?.i32; - // const a = self.stack.pop().?.i32; - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(b <= a))) }); - // }, - // 0x4a => { - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 > self.stack.pop().?.i32))) }); - // }, - // 0x4b => { - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(@as(u32, @bitCast(self.stack.pop().?.i32)) > @as(u32, @bitCast(self.stack.pop().?.i32))))) }); - // }, - // 0x4c => { - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 <= self.stack.pop().?.i32))) }); - // }, - // 0x4d => { - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(@as(u32, @bitCast(self.stack.pop().?.i32)) <= @as(u32, @bitCast(self.stack.pop().?.i32))))) }); - // }, - // 0x4e => { - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 >= self.stack.pop().?.i32))) }); - // }, - 0x4f => { + .i32_and => { const a = self.stack.pop().?.i32; const b = self.stack.pop().?.i32; - try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(a >= b))) }); + try self.stack.append(Value{ .i32 = a & b }); }, - - 0x50 => { - try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 == 0))) }); - }, - 0x51 => { - try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 == self.stack.pop().?.i64))) }); + .i64_const => { + try self.stack.append(Value{ .i64 = frame.code.indices[frame.program_counter].i64 }); }, - 0x52 => { - try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 != self.stack.pop().?.i64))) }); + .i64_add => { + const a = self.stack.pop().?.i64; + const b = self.stack.pop().?.i64; + try self.stack.append(Value{ .i64 = a + b }); }, - // 0x53 => { - // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 < self.stack.pop().?.i64))) }); - // }, - // 0x54 => { - // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(@as(u64, @bitCast(self.stack.pop().?.i64)) < @as(u64, @bitCast(self.stack.pop().?.i64))))) }); - // }, - // 0x55 => { - // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 > self.stack.pop().?.i64))) }); - // }, - // 0x56 => { - // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(@as(u64, @bitCast(self.stack.pop().?.i64)) > @as(u64, @bitCast(self.stack.pop().?.i64))))) }); - // }, - // 0x57 => { - // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 <= self.stack.pop().?.i64))) }); - // }, - // 0x58 => { - // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(@as(u64, @bitCast(self.stack.pop().?.i64)) <= @as(u64, @bitCast(self.stack.pop().?.i64))))) }); - // }, - // 0x59 => { - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 >= self.stack.pop().?.i64))) }); - // }, - // 0x5a => { - // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(@as(u64, @bitCast(self.stack.pop().?.i64)) >= @as(u64, @bitCast(self.stack.pop().?.i64))))) }); - // }, - - // 0x67 => { - // var i = @as(i32, 0); - // const number = self.stack.pop().?.i32; - // for (0..@sizeOf(i32)) |b| { - // if (number & (@as(i32, 0x1) << @intCast((@sizeOf(i32) - b - 1))) == 1) { - // break; - // } - // i += 1; - // } - // try self.stack.append(Value{ .i32 = i }); - // }, - // 0x68 => { - // var i = @as(i32, 0); - // const number = self.stack.pop().?.i32; - // for (0..@sizeOf(i32)) |b| { - // if (number & (@as(i32, 0x1) << @intCast(b)) == 1) { - // break; - // } - // i += 1; - // } - // try self.stack.append(Value{ .i32 = i }); - // }, - // 0x69 => { - // var i = @as(i32, 0); - // const number = self.stack.pop().?.i32; - // for (0..@sizeOf(i32)) |b| { - // if (number & (@as(i32, 0x1) << @intCast(b)) == 1) { - // i += 1; - // } - // } - // try self.stack.append(Value{ .i32 = i }); - // }, - 0x6a => { - const a = self.stack.pop().?; - const b = self.stack.pop().?; - try self.stack.append(.{ .i32 = a.i32 + b.i32 }); - }, - // 0x6b => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i32 = a.i32 - b.i32 }); - // }, - // 0x6c => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i32 = a.i32 * b.i32 }); - // }, - // 0x6d => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i32 = @divTrunc(a.i32, b.i32) }); - // }, - // 0x6e => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i32 = @as(i32, @bitCast(@as(u32, @bitCast(a.i32)) / @as(u32, @bitCast(b.i32)))) }); - // }, - // 0x6f => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i32 = @rem(a.i32, b.i32) }); - // }, - // 0x70 => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i32 = @as(i32, @bitCast(@as(u32, @bitCast(a.i32)) % @as(u32, @bitCast(b.i32)))) }); - // }, - 0x71 => { - const a = self.stack.pop().?; - const b = self.stack.pop().?; - try self.stack.append(.{ .i32 = a.i32 & b.i32 }); - }, - // 0x72 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i32 = a.i32 | b.i32 }); - // }, - // 0x73 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i32 = a.i32 ^ b.i32 }); - // }, - // 0x74 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i32 = a.i32 << @intCast(b.i32) }); - // }, - // 0x75 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i32 = a.i32 >> @intCast(b.i32) }); - // }, - // 0x76 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i32 = @as(i32, @bitCast(@as(u32, @bitCast(a.i32)) >> @intCast(@as(u32, @bitCast(b.i32))))) }); - // }, - // 0x77 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i32 = (a.i32 << @intCast(@as(u32, @bitCast(b.i32)))) | (a.i32 >> @intCast((@sizeOf(u32) * 8 - b.i32))) }); - // }, - // 0x78 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i32 = (a.i32 >> @intCast(@as(u32, @bitCast(b.i32)))) | (a.i32 << @intCast((@sizeOf(u32) * 8 - b.i32))) }); - // }, - - // 0x79 => { - // var i = @as(i64, 0); - // const number = self.stack.pop().?.i64; - // for (0..@sizeOf(i64)) |b| { - // if (number & (@as(i64, 0x1) << @intCast((@sizeOf(i64) - b - 1))) == 1) { - // break; - // } - // i += 1; - // } - // try self.stack.append(Value{ .i64 = i }); - // }, - // 0x7a => { - // var i = @as(i64, 0); - // const number = self.stack.pop().?.i64; - // for (0..@sizeOf(i64)) |b| { - // if (number & (@as(i64, 0x1) << @intCast(b)) == 1) { - // break; - // } - // i += 1; - // } - // try self.stack.append(Value{ .i64 = i }); - // }, - // 0x7b => { - // var i = @as(i64, 0); - // const number = self.stack.pop().?.i64; - // for (0..@sizeOf(i64)) |b| { - // if (number & (@as(i64, 0x1) << @intCast(b)) == 1) { - // i += 1; - // } - // } - // try self.stack.append(Value{ .i64 = i }); - // }, - 0x7c => { - const a = self.stack.pop().?; - const b = self.stack.pop().?; - try self.stack.append(.{ .i64 = a.i64 + b.i64 }); - }, - // 0x7d => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i64 = a.i64 - b.i64 }); - // }, - // 0x7e => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i64 = a.i64 * b.i64 }); - // }, - // 0x7f => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i64 = @divTrunc(a.i64, b.i64) }); - // }, - // 0x80 => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i64 = @as(i64, @bitCast(@as(u64, @bitCast(a.i64)) / @as(u64, @bitCast(b.i64)))) }); - // }, - // 0x81 => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i64 = @rem(a.i64, b.i64) }); - // }, - // 0x82 => { - // const b = self.stack.pop().?; - // const a = self.stack.pop().?; - // try self.stack.append(.{ .i64 = @as(i64, @bitCast(@as(u64, @bitCast(a.i64)) % @as(u64, @bitCast(b.i64)))) }); - // }, - // 0x83 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i64 = a.i64 & b.i64 }); - // }, - // 0x84 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i64 = a.i64 | b.i64 }); - // }, - // 0x85 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i64 = a.i64 ^ b.i64 }); - // }, - // 0x86 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i64 = a.i64 << @intCast(b.i64) }); - // }, - // 0x87 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i64 = a.i64 >> @intCast(b.i64) }); - // }, - // 0x88 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i64 = @as(i64, @bitCast(@as(u64, @bitCast(a.i64)) >> @intCast(@as(u64, @bitCast(b.i64))))) }); - // }, - // 0x89 => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i64 = (a.i64 << @intCast(@as(u64, @bitCast(b.i64)))) | (a.i64 >> @intCast((@sizeOf(u64) * 8 - b.i64))) }); - // }, - // 0x8a => { - // const a = self.stack.pop().?; - // const b = self.stack.pop().?; - // try self.stack.append(.{ .i64 = (a.i64 >> @intCast(@as(u64, @bitCast(b.i64)))) | (a.i64 << @intCast((@sizeOf(u64) * 8 - b.i64))) }); - // }, - - 0xad => { + .i64_extend_i32_u => { try self.stack.append(.{ .i64 = self.stack.pop().?.i32 }); }, - - 0x0f => { + .@"return" => { break :loop; }, - 0x10 => { - const integer = leb128Decode(u32, frame.code[frame.program_counter..]); - frame.program_counter += integer.len; - - self.call(allocator, integer.val, &[_]usize{}) catch {}; - }, - 0xb => { - _ = self.labels.pop(); - if (for_loop) { - for_loop = false; - } + else => { + std.log.err("instruction {any} not implemented\n", .{opcode}); + std.process.exit(1); }, - else => std.log.err("instruction {} not implemented\n", .{byte}), } - if (frame.program_counter >= frame.code.len) { + // switch (byte) { + // 0x02 => { + // var depth: usize = 1; + // var pc = frame.program_counter; + // while (depth > 0) { + // const opcode = frame.code[pc]; + // const operand = frame.code[pc + 1]; + // if ((opcode == 0x02 and operand == 0x40) or (opcode == 0x03 and operand == 0x40) or (opcode == 0x04 and operand == 0x40)) { + // depth += 1; + // pc += 1; + // } else if (opcode == 0x0B) { + // depth -= 1; + // } + // pc += 1; + // } + // try self.labels.append(pc); + // frame.program_counter += 1; + // }, + // 0x03 => { + // try self.labels.append(frame.program_counter - 1); + // frame.program_counter += 1; + // for_loop = true; + // }, + // 0x0c => { + // const label = leb128Decode(u32, frame.code[frame.program_counter..]); + // var address = @as(usize, 0); + // for (0..(label.val + (if (label.val == 0) @as(u32, 1) else @as(u32, 0)))) |_| { + // address = self.labels.pop().?; + // } + // frame.program_counter = address; + // }, + // 0x0d => { + // if (self.stack.pop().?.i32 != 0) { + // const label = leb128Decode(u32, frame.code[frame.program_counter..]); + // var address = @as(usize, 0); + // for (0..(label.val + (if (label.val == 0) @as(u32, 1) else @as(u32, 0)))) |_| { + // address = self.labels.pop().?; + // } + // frame.program_counter = address; + // } else { + // frame.program_counter += 1; + // } + // }, + + // 0x20 => { + // const integer = leb128Decode(u32, frame.code[frame.program_counter..]); + + // frame.program_counter += integer.len; + // try self.stack.append(frame.locals[integer.val]); + // }, + // 0x21 => { + // const integer = leb128Decode(u32, frame.code[frame.program_counter..]); + + // frame.program_counter += integer.len; + // frame.locals[integer.val] = self.stack.pop().?; + // }, + // 0x22 => { + // const integer = leb128Decode(u32, frame.code[frame.program_counter..]); + + // frame.program_counter += integer.len; + // const a = self.stack.pop().?; + // frame.locals[integer.val] = a; + // try self.stack.append(a); + // }, + // 0x28 => { + // const address = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += address.len; + // const offset = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += offset.len; + // const start = (address.val + offset.val); + // const end = start + @sizeOf(u32); + // try self.stack.append(Value{ .i32 = decodeLittleEndian(i32, self.memory[start..end]) }); + // }, + // 0x29 => { + // const address = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += address.len; + // const offset = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += offset.len; + // const start = (address.val + offset.val); + // const end = start + @sizeOf(u64); + // try self.stack.append(Value{ .i64 = decodeLittleEndian(i64, self.memory[start..end]) }); + // }, + // 0x36 => { + // const address = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += address.len; + // const offset = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += offset.len; + // const start = (address.val + offset.val); + // const end = start + @sizeOf(u32); + // try self.stack.append(Value{ .i32 = decodeLittleEndian(i32, self.memory[start..end]) }); + // }, + // 0x37 => { + // const address = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += address.len; + // const offset = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += offset.len; + // const start = (address.val + offset.val); + // const end = start + @sizeOf(u32); + // encodeLittleEndian(i32, @constCast(&self.memory[start..end]), self.stack.pop().?.i32); + // }, + // 0x38 => { + // const address = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += address.len; + // const offset = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += offset.len; + // const start = (address.val + offset.val); + // const end = start + @sizeOf(u64); + // encodeLittleEndian(i64, @constCast(&self.memory[start..end]), self.stack.pop().?.i64); + // }, + // 0x41 => { + // const integer = leb128Decode(i32, frame.code[frame.program_counter..]); + + // frame.program_counter += integer.len; + // try self.stack.append(Value{ .i32 = integer.val }); + // }, + // 0x42 => { + // const integer = leb128Decode(i64, frame.code[frame.program_counter..]); + + // frame.program_counter += integer.len; + // try self.stack.append(Value{ .i64 = integer.val }); + // }, + // 0x45 => { + // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 == 0))) }); + // }, + // 0x46 => { + // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 == self.stack.pop().?.i32))) }); + // }, + // 0x47 => { + // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 != self.stack.pop().?.i32))) }); + // }, + // // 0x48 => { + // // const a = self.stack.pop().?.i32; + // // const b = self.stack.pop().?.i32; + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(b < a))) }); + // // }, + // 0x49 => { + // const a = self.stack.pop().?.i32; + // const b = self.stack.pop().?.i32; + // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(b < a))) }); + // }, + // // 0x4b => { + // // const b = self.stack.pop().?.i32; + // // const a = self.stack.pop().?.i32; + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(a > b))) }); + // // }, + // // 0x4d => { + // // const b = self.stack.pop().?.i32; + // // const a = self.stack.pop().?.i32; + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(b <= a))) }); + // // }, + // // 0x4a => { + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 > self.stack.pop().?.i32))) }); + // // }, + // // 0x4b => { + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(@as(u32, @bitCast(self.stack.pop().?.i32)) > @as(u32, @bitCast(self.stack.pop().?.i32))))) }); + // // }, + // // 0x4c => { + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 <= self.stack.pop().?.i32))) }); + // // }, + // // 0x4d => { + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(@as(u32, @bitCast(self.stack.pop().?.i32)) <= @as(u32, @bitCast(self.stack.pop().?.i32))))) }); + // // }, + // // 0x4e => { + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i32 >= self.stack.pop().?.i32))) }); + // // }, + // 0x4f => { + // const a = self.stack.pop().?.i32; + // const b = self.stack.pop().?.i32; + // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(a >= b))) }); + // }, + + // 0x50 => { + // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 == 0))) }); + // }, + // 0x51 => { + // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 == self.stack.pop().?.i64))) }); + // }, + // 0x52 => { + // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 != self.stack.pop().?.i64))) }); + // }, + // // 0x53 => { + // // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 < self.stack.pop().?.i64))) }); + // // }, + // // 0x54 => { + // // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(@as(u64, @bitCast(self.stack.pop().?.i64)) < @as(u64, @bitCast(self.stack.pop().?.i64))))) }); + // // }, + // // 0x55 => { + // // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 > self.stack.pop().?.i64))) }); + // // }, + // // 0x56 => { + // // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(@as(u64, @bitCast(self.stack.pop().?.i64)) > @as(u64, @bitCast(self.stack.pop().?.i64))))) }); + // // }, + // // 0x57 => { + // // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 <= self.stack.pop().?.i64))) }); + // // }, + // // 0x58 => { + // // try self.stack.append(Value{ .i64 = @intCast(@as(u1, @bitCast(@as(u64, @bitCast(self.stack.pop().?.i64)) <= @as(u64, @bitCast(self.stack.pop().?.i64))))) }); + // // }, + // // 0x59 => { + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(self.stack.pop().?.i64 >= self.stack.pop().?.i64))) }); + // // }, + // // 0x5a => { + // // try self.stack.append(Value{ .i32 = @intCast(@as(u1, @bitCast(@as(u64, @bitCast(self.stack.pop().?.i64)) >= @as(u64, @bitCast(self.stack.pop().?.i64))))) }); + // // }, + + // // 0x67 => { + // // var i = @as(i32, 0); + // // const number = self.stack.pop().?.i32; + // // for (0..@sizeOf(i32)) |b| { + // // if (number & (@as(i32, 0x1) << @intCast((@sizeOf(i32) - b - 1))) == 1) { + // // break; + // // } + // // i += 1; + // // } + // // try self.stack.append(Value{ .i32 = i }); + // // }, + // // 0x68 => { + // // var i = @as(i32, 0); + // // const number = self.stack.pop().?.i32; + // // for (0..@sizeOf(i32)) |b| { + // // if (number & (@as(i32, 0x1) << @intCast(b)) == 1) { + // // break; + // // } + // // i += 1; + // // } + // // try self.stack.append(Value{ .i32 = i }); + // // }, + // // 0x69 => { + // // var i = @as(i32, 0); + // // const number = self.stack.pop().?.i32; + // // for (0..@sizeOf(i32)) |b| { + // // if (number & (@as(i32, 0x1) << @intCast(b)) == 1) { + // // i += 1; + // // } + // // } + // // try self.stack.append(Value{ .i32 = i }); + // // }, + // 0x6a => { + // const a = self.stack.pop().?; + // const b = self.stack.pop().?; + // try self.stack.append(.{ .i32 = a.i32 + b.i32 }); + // }, + // // 0x6b => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = a.i32 - b.i32 }); + // // }, + // // 0x6c => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = a.i32 * b.i32 }); + // // }, + // // 0x6d => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = @divTrunc(a.i32, b.i32) }); + // // }, + // // 0x6e => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = @as(i32, @bitCast(@as(u32, @bitCast(a.i32)) / @as(u32, @bitCast(b.i32)))) }); + // // }, + // // 0x6f => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = @rem(a.i32, b.i32) }); + // // }, + // // 0x70 => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = @as(i32, @bitCast(@as(u32, @bitCast(a.i32)) % @as(u32, @bitCast(b.i32)))) }); + // // }, + // 0x71 => { + // const a = self.stack.pop().?; + // const b = self.stack.pop().?; + // try self.stack.append(.{ .i32 = a.i32 & b.i32 }); + // }, + // // 0x72 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = a.i32 | b.i32 }); + // // }, + // // 0x73 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = a.i32 ^ b.i32 }); + // // }, + // // 0x74 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = a.i32 << @intCast(b.i32) }); + // // }, + // // 0x75 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = a.i32 >> @intCast(b.i32) }); + // // }, + // // 0x76 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = @as(i32, @bitCast(@as(u32, @bitCast(a.i32)) >> @intCast(@as(u32, @bitCast(b.i32))))) }); + // // }, + // // 0x77 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = (a.i32 << @intCast(@as(u32, @bitCast(b.i32)))) | (a.i32 >> @intCast((@sizeOf(u32) * 8 - b.i32))) }); + // // }, + // // 0x78 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i32 = (a.i32 >> @intCast(@as(u32, @bitCast(b.i32)))) | (a.i32 << @intCast((@sizeOf(u32) * 8 - b.i32))) }); + // // }, + + // // 0x79 => { + // // var i = @as(i64, 0); + // // const number = self.stack.pop().?.i64; + // // for (0..@sizeOf(i64)) |b| { + // // if (number & (@as(i64, 0x1) << @intCast((@sizeOf(i64) - b - 1))) == 1) { + // // break; + // // } + // // i += 1; + // // } + // // try self.stack.append(Value{ .i64 = i }); + // // }, + // // 0x7a => { + // // var i = @as(i64, 0); + // // const number = self.stack.pop().?.i64; + // // for (0..@sizeOf(i64)) |b| { + // // if (number & (@as(i64, 0x1) << @intCast(b)) == 1) { + // // break; + // // } + // // i += 1; + // // } + // // try self.stack.append(Value{ .i64 = i }); + // // }, + // // 0x7b => { + // // var i = @as(i64, 0); + // // const number = self.stack.pop().?.i64; + // // for (0..@sizeOf(i64)) |b| { + // // if (number & (@as(i64, 0x1) << @intCast(b)) == 1) { + // // i += 1; + // // } + // // } + // // try self.stack.append(Value{ .i64 = i }); + // // }, + // 0x7c => { + // const a = self.stack.pop().?; + // const b = self.stack.pop().?; + // try self.stack.append(.{ .i64 = a.i64 + b.i64 }); + // }, + // // 0x7d => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = a.i64 - b.i64 }); + // // }, + // // 0x7e => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = a.i64 * b.i64 }); + // // }, + // // 0x7f => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = @divTrunc(a.i64, b.i64) }); + // // }, + // // 0x80 => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = @as(i64, @bitCast(@as(u64, @bitCast(a.i64)) / @as(u64, @bitCast(b.i64)))) }); + // // }, + // // 0x81 => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = @rem(a.i64, b.i64) }); + // // }, + // // 0x82 => { + // // const b = self.stack.pop().?; + // // const a = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = @as(i64, @bitCast(@as(u64, @bitCast(a.i64)) % @as(u64, @bitCast(b.i64)))) }); + // // }, + // // 0x83 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = a.i64 & b.i64 }); + // // }, + // // 0x84 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = a.i64 | b.i64 }); + // // }, + // // 0x85 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = a.i64 ^ b.i64 }); + // // }, + // // 0x86 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = a.i64 << @intCast(b.i64) }); + // // }, + // // 0x87 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = a.i64 >> @intCast(b.i64) }); + // // }, + // // 0x88 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = @as(i64, @bitCast(@as(u64, @bitCast(a.i64)) >> @intCast(@as(u64, @bitCast(b.i64))))) }); + // // }, + // // 0x89 => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = (a.i64 << @intCast(@as(u64, @bitCast(b.i64)))) | (a.i64 >> @intCast((@sizeOf(u64) * 8 - b.i64))) }); + // // }, + // // 0x8a => { + // // const a = self.stack.pop().?; + // // const b = self.stack.pop().?; + // // try self.stack.append(.{ .i64 = (a.i64 >> @intCast(@as(u64, @bitCast(b.i64)))) | (a.i64 << @intCast((@sizeOf(u64) * 8 - b.i64))) }); + // // }, + + // 0xad => { + // try self.stack.append(.{ .i64 = self.stack.pop().?.i32 }); + // }, + + // 0x0f => { + // break :loop; + // }, + // 0x10 => { + // const integer = leb128Decode(u32, frame.code[frame.program_counter..]); + // frame.program_counter += integer.len; + + // self.call(allocator, integer.val, &[_]usize{}) catch {}; + // }, + // 0xb => { + // _ = self.labels.pop(); + // if (for_loop) { + // for_loop = false; + // } + // }, + // else => std.log.err("instruction {} not implemented\n", .{byte}), + // } + frame.program_counter += 1; + if (frame.program_counter >= frame.code.opcodes.len) { break :loop; } } @@ -624,9 +611,10 @@ pub const Runtime = struct { const f = self.module.funcs[function]; switch (f) { .internal => { + const ir: IR = self.module.code[f.internal].ir; const function_type = self.module.types[self.module.functions[f.internal]]; var frame = CallFrame{ - .code = self.module.code[f.internal].code, + .code = ir, .program_counter = 0x0, .locals = try allocator.alloc(Value, self.module.code[f.internal].locals.len + function_type.parameters.len), }; |