malcolmstill / zware

Zig WebAssembly Runtime Engine
MIT License
285 stars 10 forks source link

Move WasmError from argument to return type #140

Closed malcolmstill closed 2 years ago

malcolmstill commented 2 years ago

Description

This is the one I've been looking forward to!

The stage 2 compiler fixes some bugs that prevent using .always_tail with a return value. As a workaround I had been doing the error returns by passing a pointer to an error as an argument to the recursive functions.

This PR moves the WasmError into its rightly place: the function return value. The added benefit is we get to use try again!

E.g.

fn call_indirect(self: *Interpreter, ip: usize, code: []Instruction, err: *?WasmError) void {
        const call_indirect_instruction = code[ip].call_indirect;
        var module = self.inst.module;

        const op_func_type_index = call_indirect_instruction.@"type";
        const table_index = call_indirect_instruction.table;

        // Read lookup index from stack
        const lookup_index = self.popOperand(u32);
        const table = self.inst.getTable(table_index) catch |e| {
            err.* = e;
            return;
        };
        const function_handle = table.lookup(lookup_index) catch |e| {
            err.* = e;
            return;
        };
        const function = self.inst.store.function(function_handle) catch |e| {
            err.* = e;
            return;
        };

        var next_ip = ip;

Becomes:

    fn call_indirect(self: *Interpreter, ip: usize, code: []Instruction) WasmError!void {
        const call_indirect_instruction = code[ip].call_indirect;
        var module = self.inst.module;

        const op_func_type_index = call_indirect_instruction.@"type";
        const table_index = call_indirect_instruction.table;

        // Read lookup index from stack
        const lookup_index = self.popOperand(u32);
        const table = try self.inst.getTable(table_index);
        const function_handle = try table.lookup(lookup_index);
        const function = try self.inst.store.function(function_handle);

        var next_ip = ip;

Beautiful!

But there's more! This change also gives us a 9% speed increase!

hyperfine ./fib ./fib-try
Benchmark 1: ./fib
  Time (mean ± σ):     11.271 s ±  0.100 s    [User: 11.212 s, System: 0.005 s]
  Range (min … max):   11.146 s … 11.416 s    10 runs

Benchmark 2: ./fib-try
  Time (mean ± σ):     10.374 s ±  0.097 s    [User: 10.317 s, System: 0.005 s]
  Range (min … max):   10.217 s … 10.554 s    10 runs

Summary
  './fib-try' ran
    1.09 ± 0.01 times faster than './fib'

fib is master, fib-try is this PR.