Skip to content
Open
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
6 changes: 6 additions & 0 deletions interpreter/exec/eval.mli
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ exception Crash of Source.region * string

val init : Ast.module_ -> extern list -> module_inst (* raises Link, Trap *)
val invoke : func_inst -> value list -> value list (* raises Trap *)

type ctxt
type handle_table

type cont = int32 * ctxt (* TODO: represent type properly *)
Comment on lines +14 to +17
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since these types aren't used externally, I believe we can simplify even further:

Suggested change
type ctxt
type handle_table
type cont = int32 * ctxt (* TODO: represent type properly *)
type cont

type ref_ += ContRef of cont option ref
5 changes: 3 additions & 2 deletions interpreter/script/run.ml
Original file line number Diff line number Diff line change
Expand Up @@ -412,10 +412,11 @@ let assert_ref_pat r p =
| RefTypePat Types.EqHT, (I31.I31Ref _ | Aggr.StructRef _ | Aggr.ArrayRef _)
| RefTypePat Types.I31HT, I31.I31Ref _
| RefTypePat Types.StructHT, Aggr.StructRef _
| RefTypePat Types.ArrayHT, Aggr.ArrayRef _ -> true
| RefTypePat Types.ArrayHT, Aggr.ArrayRef _
| RefTypePat Types.FuncHT, Instance.FuncRef _
| RefTypePat Types.ContHT, Eval.ContRef _
| RefTypePat Types.ExnHT, Exn.ExnRef _
| RefTypePat Types.ExternHT, _ -> true
| RefTypePat Types.ExternHT, _
| NullPat, Value.NullRef _ -> true
| _ -> false

Expand Down
1 change: 1 addition & 0 deletions interpreter/text/lexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ rule token = parse
| "ref.func" -> REF_FUNC
| "ref.struct" -> REF_STRUCT
| "ref.array" -> REF_ARRAY
| "ref.cont" -> REF_CONT
| "ref.exn" -> REF_EXN
| "ref.extern" -> REF_EXTERN
| "ref.host" -> REF_HOST
Expand Down
3 changes: 2 additions & 1 deletion interpreter/text/parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ let parse_annots (m : module_) : Custom.section list =
%token<string> OFFSET_EQ_NAT ALIGN_EQ_NAT
%token<string Source.phrase -> Ast.instr' * Value.num> CONST
%token<Ast.instr'> UNARY BINARY TEST COMPARE CONVERT
%token REF_NULL REF_FUNC REF_I31 REF_STRUCT REF_ARRAY REF_EXN REF_EXTERN REF_HOST
%token REF_NULL REF_FUNC REF_I31 REF_STRUCT REF_ARRAY REF_CONT REF_EXN REF_EXTERN REF_HOST
%token REF_EQ REF_IS_NULL REF_AS_NON_NULL REF_TEST REF_CAST
%token<Ast.instr'> I31_GET
%token<Ast.idx -> Ast.instr'> STRUCT_NEW ARRAY_NEW ARRAY_GET
Expand Down Expand Up @@ -1626,6 +1626,7 @@ result :
| LPAR REF_STRUCT RPAR { RefResult (RefTypePat StructHT) @@ $sloc }
| LPAR REF_ARRAY RPAR { RefResult (RefTypePat ArrayHT) @@ $sloc }
| LPAR REF_FUNC RPAR { RefResult (RefTypePat FuncHT) @@ $sloc }
| LPAR REF_CONT RPAR { RefResult (RefTypePat ContHT) @@ $sloc }
| LPAR REF_EXN RPAR { RefResult (RefTypePat ExnHT) @@ $sloc }
| LPAR REF_EXTERN RPAR { RefResult (RefTypePat ExternHT) @@ $sloc }
| LPAR REF_NULL RPAR { RefResult NullPat @@ $sloc }
Expand Down
345 changes: 345 additions & 0 deletions test/core/stack-switching/cont.new.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,345 @@
;; No type immediate.
(assert_malformed
(module quote
"(module"
"(func (drop (cont.new)))"
")"
)
"unexpected token"
)

(assert_malformed
(module binary
"\00asm\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section: 1 type
"\03\02\01\00" ;; Function section: 1 function
"\0a\04\01" ;; Code section: 1 function
;; function 0
"\02\00" ;; Function size and local type count
"\e0" ;; cont.new (missing type immediate)
)
"unexpected end"
)

;; Valid binary module parsing, validating, and executing correctly
(module binary
"\00\61\73\6d\01\00\00\00" ;; Magic header and version
"\01\8b\80\80\80\00\03" ;; Type section: 3 types
"\60\00\00" ;; type 0: func [] -> []
"\5d\00" ;; type 1: cont 0
"\60\00\01\64\01" ;; type 2: func [] -> [ref 1]
"\03\83\80\80\80\00\02" ;; Function section: 2 functions
"\00\02" ;; func 0: type 0, func 1: type 2
"\07\88\80\80\80\00\01" ;; Export section: 1 export
"\04\74\65\73\74\00\01" ;; "test" -> func 1
"\09\85\80\80\80\00\01" ;; Element section: 1 segment
"\03\00\01\00" ;; declarative, elem kind func, 1 func, func index 0
"\0a\93\80\80\80\00\02" ;; Code section: 2 functions
;; function 0
"\82\80\80\80\00\00\0b" ;; size 2, 0 locals, end
;; function 1
"\86\80\80\80\00\00" ;; size 6, 0 locals
"\d2\00" ;; ref.func 0
"\e0\01" ;; cont.new 1
"\0b" ;; end
)
(assert_return (invoke "test") (ref.cont))

;; Out-of-bounds type immediate.
(assert_invalid
(module
(func (drop (cont.new 0 (unreachable))))
)
"non-continuation type"
)

;; Non-continuation type.
(assert_invalid
(module
(type $f (func))
(func (drop (cont.new $f (unreachable))))
)
"non-continuation type"
)

;; Defined function ref.func operand.
(module
(type $f (func))
(type $k (cont $f))
(elem declare func $f)
(func $f (type $f))
(func (export "test") (result (ref $k)) (cont.new $k (ref.func $f)))
)
(assert_return (invoke "test") (ref.cont))

;; Imported function ref.func operand.
(module definition
(type $f (func))
(type $k (cont $f))
(elem declare func $f)
(import "" "" (func $f (type $f)))
(func (result (ref $k)) (cont.new $k (ref.func $f)))
)

;; Defined global operand.
(module
(type $f (func))
(type $k (cont $f))
(global $g (ref null $f) (ref.null nofunc))
(func (export "test") (result (ref $k)) (cont.new $k (global.get $g)))
)
(assert_trap (invoke "test") "null function reference")

;; Defined global operand (non-null at runtime).
(module
(type $f (func))
(type $k (cont $f))
(elem declare func $f)
(func $f (type $f))
(global $g (ref null $f) (ref.func $f))
(func (export "test") (result (ref $k)) (cont.new $k (global.get $g)))
)
(assert_return (invoke "test") (ref.cont))

;; Imported global operand.
(module definition
(type $f (func))
(type $k (cont $f))
(import "" "" (global $g (ref null $f)))
(func (result (ref $k)) (cont.new $k (global.get $g)))
)

;; Param operand.
(module
(type $f (func))
(type $k (cont $f))
(func (export "test") (param (ref null $f)) (result (ref $k))
(cont.new $k (local.get 0))
)
)
(assert_trap (invoke "test" (ref.null nofunc)) "null function reference")

;; Stack-polymorphic (unreachable) input.
(module
(type $f (func))
(type $k (cont $f))
(func (export "test") (result (ref $k)) (cont.new $k (unreachable)))
)
(assert_trap (invoke "test") "unreachable")

;; Stack-polymorphic (unreachable) input due to branch.
(module
(type $f (func))
(type $k (cont $f))
(func (export "test")
(drop
(block $l (result (ref $k))
(cont.new $k (return))
)
)
)
)
(assert_return (invoke "test"))

;; Uninhabitable bottom input.
(module
(type $f (func))
(type $k (cont $f))
(func (param (ref nofunc)) (result (ref $k)) (cont.new $k (local.get 0)))
)

;; Null constant input.
(module
(type $f (func))
(type $k (cont $f))
(func (export "test") (result (ref $k)) (cont.new $k (ref.null $f)))
)
(assert_trap (invoke "test") "null function reference")

;; Bottom null constant input.
(module
(type $f (func))
(type $k (cont $f))
(func (export "test") (result (ref $k)) (cont.new $k (ref.null nofunc)))
)
(assert_trap (invoke "test") "null function reference")

;; Top null constant input.
(assert_invalid
(module
(type $f (func))
(type $k (cont $f))
(func (result (ref $k)) (cont.new $k (ref.null func)))
)
"type mismatch"
)

;; Any hierarchy null constant input.
(assert_invalid
(module
(type $f (func))
(type $k (cont $f))
(func (result (ref $k)) (cont.new $k (ref.null none)))
)
"type mismatch"
)

;; Cont hierarchy null constant input.
(assert_invalid
(module
(type $f (func))
(type $k (cont $f))
(func (result (ref $k)) (cont.new $k (ref.null nocont)))
)
"type mismatch"
)

;; Top reference input.
(assert_invalid
(module
(type $f (func))
(type $k (cont $f))
(func (param funcref) (result (ref $k)) (cont.new $k (local.get 0)))
)
"type mismatch"
)

;; Declared subtype input.
(module
(type $super (sub (func)))
(type $sub (sub $super (func)))
(type $k (cont $super))
(elem declare func $sub)
(func $sub (type $sub))
(func (export "test") (result (ref $k)) (cont.new $k (ref.func $sub)))
)
(assert_return (invoke "test") (ref.cont))

;; Declared supertype input.
(assert_invalid
(module
(type $super (sub (func)))
(type $sub (sub $super (func)))
(type $k (cont $sub))
(func (param (ref null $super)) (result (ref $k)) (cont.new $k (local.get 0)))
)
"type mismatch"
)

;; Unrelated input.
(assert_invalid
(module
(rec
(type $f (func))
(type $other (func))
)
(type $k (cont $f))
(func (param (ref null $other)) (result (ref $k)) (cont.new $k (local.get 0)))
)
"type mismatch"
)

;; Missing input.
(assert_invalid
(module
(type $f (func))
(type $k (cont $f))
(func (result (ref $k)) (cont.new $k))
)
"type mismatch"
)

;; Extra input.
(assert_invalid
(module
(type $f (func))
(type $k (cont $f))
(func (param (ref null $f)) (result (ref $k)) (cont.new $k (i32.const 0) (local.get 0)))
)
"type mismatch"
)

;; Extra input matching continuation params.
(assert_invalid
(module
(type $f (func (param i32)))
(type $k (cont $f))
(func (param (ref null $f)) (result (ref $k)) (cont.new $k (i32.const 0) (local.get 0)))
)
"type mismatch"
)

;; Contref output type.
(module
(type $f (func))
(type $k (cont $f))
(func (param (ref null $f)) (result contref) (cont.new $k (local.get 0)))
)

;; Nullable cont reference output type.
(module
(type $f (func))
(type $k (cont $f))
(func (param (ref null $f)) (result (ref null cont)) (cont.new $k (local.get 0)))
)

;; Non-nullable cont reference output type.
(module
(type $f (func))
(type $k (cont $f))
(func (param (ref null $f)) (result (ref cont)) (cont.new $k (local.get 0)))
)

;; Declared supertype output type.
(module
(type $f (func))
(type $super (sub (cont $f)))
(type $sub (sub $super (cont $f)))
(func (param (ref null $f)) (result (ref $super)) (cont.new $sub (local.get 0)))
)

;; Declared subtype output type.
(assert_invalid
(module
(type $f (func))
(type $super (sub (cont $f)))
(type $sub (sub $super (cont $f)))
(func (param (ref null $f)) (result (ref $sub)) (cont.new $super (local.get 0)))
)
"type mismatch"
)

;; Unrelated output.
(assert_invalid
(module
(type $f (func))
(rec
(type $k (cont $f))
(type $other (cont $f))
)
(func (param (ref null $f)) (result (ref $other)) (cont.new $k (local.get 0)))
)
"type mismatch"
)

;; TODO: Make cont.new constant
;; https://github.com/WebAssembly/stack-switching/issues/145

;; ;; Constant expression in global definition.
;; (module
;; (type $f (func))
;; (type $k (cont $f))
;; (global $k (export "k") (ref $k) (cont.new $k (ref.func $f)))
;; (func $f (type $f))
;; )
;; (assert_return (get "k") (ref.cont))

;; ;; Constant expression in element segment definition.
;; (module
;; (type $f (func))
;; (type $k (cont $f))
;; (table $t (ref null $k) (elem (cont.new $k (ref.func $f))))
;; (func $f (type $f))
;; (func (export "get") (result (ref null $k)) (table.get $t (i32.const 0)))
;; )
;; (assert_return (invoke "get") (ref.cont))
Loading