Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

[interpreter] Implement basic reference types and multiple tables #2

Merged
merged 8 commits into from
Mar 24, 2018
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
49 changes: 30 additions & 19 deletions interpreter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ float: <num>.<num>?(e|E <num>)? | 0x<hexnum>.<hexnum>?(p|P <num>)?
name: $(<letter> | <digit> | _ | . | + | - | * | / | \ | ^ | ~ | = | < | > | ! | ? | @ | # | $ | % | & | | | : | ' | `)+
string: "(<char> | \n | \t | \\ | \' | \" | \<hex><hex> | \u{<hex>+})*"

value: <int> | <float>
var: <nat> | <name>
num: <int> | <float>
var: <nat> | <name>

unop: ctz | clz | popcnt | ...
binop: add | sub | mul | ...
Expand All @@ -183,12 +183,13 @@ offset: offset=<nat>
align: align=(1|2|4|8|...)
cvtop: trunc_s | trunc_u | extend_s | extend_u | ...

val_type: i32 | i64 | f32 | f64
elem_type: anyfunc
num_type: i32 | i64 | f32 | f64
ref_type: anyref | anyfunc | anyeqref
val_type: num_type | ref_type
block_type : ( result <val_type>* )*
func_type: ( type <var> )? <param>* <result>*
global_type: <val_type> | ( mut <val_type> )
table_type: <nat> <nat>? <elem_type>
table_type: <nat> <nat>? <ref_type>
memory_type: <nat> <nat>?

expr:
Expand Down Expand Up @@ -223,16 +224,21 @@ op:
tee_local <var>
get_global <var>
set_global <var>
<val_type>.load((8|16|32)_<sign>)? <offset>? <align>?
<val_type>.store(8|16|32)? <offset>? <align>?
get_table <var>
set_table <var>
<num_type>.load((8|16|32)_<sign>)? <offset>? <align>?
<num_type>.store(8|16|32)? <offset>? <align>?
current_memory
grow_memory
<val_type>.const <value>
<val_type>.<unop>
<val_type>.<binop>
<val_type>.<testop>
<val_type>.<relop>
<val_type>.<cvtop>/<val_type>
ref.null
ref.isnull
ref.eq
<num_type>.const <num>
<num_type>.<unop>
<num_type>.<binop>
<num_type>.<testop>
<num_type>.<relop>
<num_type>.<cvtop>/<num_type>

func: ( func <name>? <func_type> <local>* <instr>* )
( func <name>? ( export <string> ) <...> ) ;; = (export <string> (func <N>)) (func <name>? <...>)
Expand All @@ -247,7 +253,7 @@ global: ( global <name>? <global_type> <instr>* )
table: ( table <name>? <table_type> )
( table <name>? ( export <string> ) <...> ) ;; = (export <string> (table <N>)) (table <name>? <...>)
( table <name>? ( import <string> <string> ) <table_type> ) ;; = (import <name>? <string> <string> (table <table_type>))
( table <name>? ( export <string> )* <elem_type> ( elem <var>* ) ) ;; = (table <name>? ( export <string> )* <size> <size> <elem_type>) (elem (i32.const 0) <var>*)
( table <name>? ( export <string> )* <ref_type> ( elem <var>* ) ) ;; = (table <name>? ( export <string> )* <size> <size> <ref_type>) (elem (i32.const 0) <var>*)
elem: ( elem <var>? (offset <instr>* ) <var>* )
( elem <var>? <expr> <var>* ) ;; = (elem <var>? (offset <expr>) <var>*)
memory: ( memory <name>? <memory_type> )
Expand All @@ -272,9 +278,9 @@ exkind: ( func <var> )
( table <var> )
( memory <var> )

module: ( module <name>? <typedef>* <func>* <import>* <export>* <table>? <memory>? <global>* <elem>* <data>* <start>? )
<typedef>* <func>* <import>* <export>* <table>? <memory>? <global>* <elem>* <data>* <start>? ;; =
( module <typedef>* <func>* <import>* <export>* <table>? <memory>? <global>* <elem>* <data>* <start>? )
module: ( module <name>? <typedef>* <func>* <import>* <export>* <table>* <memory>? <global>* <elem>* <data>* <start>? )
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does elem_type need to change in this file as well to support eqref and anyref in addition to anyfunc?

Copy link

@cretz cretz Mar 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, val_type I suppose (or rather, split it and change what param, result, local, etc can handle to include refs)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, you're right. Fixed.

<typedef>* <func>* <import>* <export>* <table>* <memory>? <global>* <elem>* <data>* <start>? ;; =
( module <typedef>* <func>* <import>* <export>* <table>* <memory>? <global>* <elem>* <data>* <start>? )
```

Here, productions marked with respective comments are abbreviation forms for equivalent expansions (see the explanation of the AST below).
Expand Down Expand Up @@ -320,11 +326,16 @@ module:
( module <name>? quote <string>* ) ;; module quoted in text (may be malformed)

action:
( invoke <name>? <string> <expr>* ) ;; invoke function export
( invoke <name>? <string> <const>* ) ;; invoke function export
( get <name>? <string> ) ;; get global export

const:
( <num_type>.const <num> ) ;; number value
( ref.null ) ;; null reference
( ref.host <nat> ) ;; host reference

assertion:
( assert_return <action> <expr>* ) ;; assert action has expected results
( assert_return <action> <const>* ) ;; assert action has expected results
( assert_return_canonical_nan <action> ) ;; assert action results in NaN in a canonical form
( assert_return_arithmetic_nan <action> ) ;; assert action results in NaN with 1 in MSB of fraction field
( assert_trap <action> <failure> ) ;; assert action traps with given failure string
Expand Down
33 changes: 25 additions & 8 deletions interpreter/binary/decode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,25 @@ let sized f s =

open Types

let value_type s =
let num_type s =
match vs7 s with
| -0x01 -> I32Type
| -0x02 -> I64Type
| -0x03 -> F32Type
| -0x04 -> F64Type
| _ -> error s (pos s - 1) "invalid value type"
| _ -> error s (pos s - 1) "invalid number type"

let elem_type s =
let ref_type s =
match vs7 s with
| -0x10 -> AnyFuncType
| _ -> error s (pos s - 1) "invalid element type"
| -0x11 -> AnyRefType
| -0x12 -> AnyEqRefType
| _ -> error s (pos s - 1) "invalid reference type"

let value_type s =
match peek s with
| Some n when n > 0x70 -> NumType (num_type s)
| _ -> RefType (ref_type s)

let stack_type s =
match peek s with
Expand All @@ -164,7 +171,7 @@ let limits vu s =
{min; max}

let table_type s =
let t = elem_type s in
let t = ref_type s in
let lim = limits vu32 s in
TableType (lim, t)

Expand Down Expand Up @@ -243,9 +250,9 @@ let rec instr s =

| 0x10 -> call (at var s)
| 0x11 ->
let y = at var s in
let x = at var s in
expect 0x00 s "zero flag expected";
call_indirect x
call_indirect x y

| 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b

Expand All @@ -259,8 +266,10 @@ let rec instr s =
| 0x22 -> tee_local (at var s)
| 0x23 -> get_global (at var s)
| 0x24 -> set_global (at var s)
| 0x25 -> get_table (at var s)
| 0x26 -> set_table (at var s)

| 0x25 | 0x26 | 0x27 as b -> illegal s pos b
| 0x27 as b -> illegal s pos b

| 0x28 -> let a, o = memop s in i32_load a o
| 0x29 -> let a, o = memop s in i64_load a o
Expand Down Expand Up @@ -432,6 +441,14 @@ let rec instr s =
| 0xbe -> f32_reinterpret_i32
| 0xbf -> f64_reinterpret_i64

| 0xc0 | 0xc1 | 0xc2 | 0xc3 | 0xc4 | 0xc5 | 0xc6 | 0xc7
| 0xc8 | 0xc9 | 0xca | 0xcb | 0xcc | 0xcd | 0xce | 0xcf as b -> illegal s pos b

(* TODO: Allocate more adequate opcodes *)
| 0xd0 -> ref_null
| 0xd1 -> ref_isnull
| 0xd2 -> ref_eq

| b -> illegal s pos b

and instr_block s = List.rev (instr_block' s [])
Expand Down
25 changes: 20 additions & 5 deletions interpreter/binary/encode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,21 @@ let encode m =

open Types

let value_type = function
let num_type = function
| I32Type -> vs7 (-0x01)
| I64Type -> vs7 (-0x02)
| F32Type -> vs7 (-0x03)
| F64Type -> vs7 (-0x04)

let elem_type = function
let ref_type = function
| AnyFuncType -> vs7 (-0x10)
| AnyRefType -> vs7 (-0x11)
| AnyEqRefType -> vs7 (-0x12)
| NullRefType -> assert false

let value_type = function
| NumType t -> num_type t
| RefType t -> ref_type t

let stack_type = function
| [] -> vs7 (-0x40)
Expand All @@ -107,13 +114,14 @@ let encode m =
"cannot encode stack type with arity > 1 (yet)"

let func_type = function
| FuncType (ins, out) -> vs7 (-0x20); vec value_type ins; vec value_type out
| FuncType (ins, out) ->
vs7 (-0x20); vec value_type ins; vec value_type out

let limits vu {min; max} =
bool (max <> None); vu min; opt vu max

let table_type = function
| TableType (lim, t) -> elem_type t; limits vu32 lim
| TableType (lim, t) -> ref_type t; limits vu32 lim

let memory_type = function
| MemoryType lim -> limits vu32 lim
Expand Down Expand Up @@ -156,7 +164,7 @@ let encode m =
| BrTable (xs, x) -> op 0x0e; vec var xs; var x
| Return -> op 0x0f
| Call x -> op 0x10; var x
| CallIndirect x -> op 0x11; var x; u8 0x00
| CallIndirect (x, y) -> op 0x11; var y; var x

| Drop -> op 0x1a
| Select -> op 0x1b
Expand All @@ -166,6 +174,8 @@ let encode m =
| TeeLocal x -> op 0x22; var x
| GetGlobal x -> op 0x23; var x
| SetGlobal x -> op 0x24; var x
| GetTable x -> op 0x25; var x
| SetTable x -> op 0x26; var x

| Load ({ty = I32Type; sz = None; _} as mo) -> op 0x28; memop mo
| Load ({ty = I64Type; sz = None; _} as mo) -> op 0x29; memop mo
Expand Down Expand Up @@ -363,6 +373,11 @@ let encode m =
| Convert (F64 F64Op.DemoteF64) -> assert false
| Convert (F64 F64Op.ReinterpretInt) -> op 0xbf

(* TODO: Allocate more adequate opcodes *)
| Null -> op 0xd0
| IsNull -> op 0xd1
| Same -> op 0xd2

let const c =
list instr c.it; end_ ()

Expand Down
Loading