diff --git a/src/arrange.ml b/src/arrange.ml index ce8cce742c0..4ec0a34ae36 100644 --- a/src/arrange.ml +++ b/src/arrange.ml @@ -157,7 +157,15 @@ and dec d = match d.it with | LetD (p, e) -> "LetD" $$ [pat p; exp e] | VarD (i, e) -> "VarD" $$ [id i; exp e] | FuncD (s, i, tp, p, t, e) -> - "FuncD" $$ [Atom (sharing s.it); id i] @ List.map typ_bind tp @ [pat p; typ t; exp e] + "FuncD" $$ [ + Atom (Type.string_of_typ d.note.note_typ); + Atom (sharing s.it); + id i] @ + List.map typ_bind tp @ [ + pat p; + typ t; + exp e + ] | TypD (i, tp, t) -> "TypD" $$ [id i] @ List.map typ_bind tp @ [typ t] | ClassD (i, j, tp, s, p, i', efs) -> diff --git a/src/async.ml b/src/async.ml index baba351f8c2..9c36c1b038e 100644 --- a/src/async.ml +++ b/src/async.ml @@ -18,12 +18,11 @@ let localS = at=no_region; note=()} -(* + let sharableS = {it=T.Call T.Sharable; at=no_region; note=()} -*) let replyT typ = T.Func(T.Call T.Sharable, T.Returns, [], [typ], []) @@ -62,7 +61,8 @@ let prelude_new_async t1 = at = no_region; } -let contTT t = funcT(localS,[],t,unitT) +(* let contTT t = funcT(localS,[],t,unitT) *) +let replyTT t = funcT(sharableS,[],t,unitT) let shared_funcD f x e = @@ -171,8 +171,8 @@ let rec t_typ (t:T.typ) = Func(s, c, List.map t_bind tbs, List.map t_typ t1, List.map t_typ t2) | [Async t2] -> Func (s, c, List.map t_bind tbs, - extendTup (List.map t_typ t1) (contT (t_typ t2)), []) - | _ -> failwith "t_typT'" + extendTup (List.map t_typ t1) (replyT (* contT*) (t_typ t2)), []) + | _ -> failwith "t_typ" end | _ -> Func (s, c, List.map t_bind tbs, List.map t_typ t1, List.map t_typ t2) @@ -361,9 +361,9 @@ and t_dec' dec' = | T.Async res_typ -> let res_typ = t_typ res_typ in let pat = t_pat pat in - let cont_typ = contT res_typ in + let reply_typ = replyT res_typ in let typT' = tupT [] in - let k = fresh_id cont_typ in + let k = fresh_id reply_typ in let pat',d = extendTupP pat (varP k) in (* let pat' = tupP [pat;varP k] in *) let typbinds' = t_typbinds typbinds in @@ -453,7 +453,7 @@ and t_typT' t = FuncT (s, t_typbinds tbs, t_typT t1, t_typT t2) | AsyncT t2 -> FuncT (localS, t_typbinds tbs, - tupT [t_typT t1; contTT (t_typT t2)], unitT) + tupT [t_typT t1; replyTT (t_typT t2)], unitT) | _ -> failwith "t_typT'" end | _ -> diff --git a/src/interpret.ml b/src/interpret.ml index 03ed0a89a61..25a914bf339 100644 --- a/src/interpret.ml +++ b/src/interpret.ml @@ -41,7 +41,7 @@ let find id env = try V.Env.find id env with Not_found -> trap no_region "unbound identifier %s" id - + (* Tracing *) let trace_depth = ref 0 @@ -136,21 +136,35 @@ let actor_msg id f v (k : V.value V.cont) = incr trace_depth; f v k ) - + let make_unit_message id v = - let _, f = V.as_func v in - V.Func (None, fun v k -> actor_msg id f v (fun _ -> ()); k V.unit) + let _, call_conv, f = V.as_func v in + match call_conv with + | (T.Call T.Sharable, _ , arg_c, 0) -> + Value.message_func 0 (fun v k -> + actor_msg id f v (fun _ -> ()); + k V.unit + ) + | _ -> + failwith ("unexpected call_conv " ^ (V.string_of_call_conv call_conv)) +(* assert (false) *) let make_async_message id v = - assert (not !Flags.async_lowering); - let _, f = V.as_func v in - V.Func (None, fun v k -> + assert (not !Flags.async_lowering); + let _, call_conv, f = V.as_func v in + match call_conv with + | (T.Call T.Sharable, T.Promises, arg_c,1) -> + Value.async_func arg_c 1 (fun v k -> let async = make_async () in actor_msg id f v (fun v_async -> get_async (V.as_async v_async) (fun v_r -> set_async async v_r) ); k (V.Async async) ) + | _ -> + failwith ("unexpected call_conv " ^ (V.string_of_call_conv call_conv)) + (* assert (false) *) + let make_message id t v : V.value = match t with @@ -163,16 +177,16 @@ let make_message id t v : V.value = failwith (Printf.sprintf "actorfield: %s %s" id.it (T.string_of_typ t)) (* assert false *) - + let extended_prim s at = match s with | "@async" -> assert(!Flags.await_lowering && not(!Flags.async_lowering)); fun v k -> - let (call,f) = V.as_func v in + let (call,_,f) = V.as_func v in async at (fun k' -> - let k' = V.Func(None,fun v _ -> k' v) in + let k' = Value.local_func 1 0 (fun v _ -> k' v) in f k' V.as_unit) k | "@await" -> @@ -181,13 +195,12 @@ let extended_prim s at = begin match V.as_tup v with | [async; w] -> - let (_,f) = V.as_func w in + let (_,_,f) = V.as_func w in await at (V.as_async async) (fun v -> f v k) | _ -> assert false end | _ -> Prelude.prim s - (* Literals *) let interpret_lit env lit : V.value = @@ -208,6 +221,15 @@ let interpret_lit env lit : V.value = (* Expressions *) +let check_call_conv exp ((func_sort,control,args,res) as call_conv) = + let ((exp_func_sort,exp_control,exp_args,exp_res) as exp_call_conv) = V.call_conv_of_typ exp.note.note_typ in + (* TODO: Check the full calling convention here *) + if not (exp_func_sort = func_sort) then + failwith (Printf.sprintf "call_conv mismatch: function %s expect %s, found %s" + (Wasm.Sexpr.to_string 80 (Arrange.exp exp)) + (V.string_of_call_conv exp_call_conv) + (V.string_of_call_conv call_conv)) + let rec interpret_exp env exp (k : V.value V.cont) = interpret_exp_mut env exp (function V.Mut r -> k !r | v -> k v) @@ -217,7 +239,7 @@ and interpret_exp_mut env exp (k : V.value V.cont) = match exp.it with | PrimE s -> let at = exp.at in - k (V.Func (None, extended_prim s at)) + k (V.Func (None, V.call_conv_of_typ exp.note.note_typ, extended_prim s at)) | VarE id -> (match Lib.Promise.value_opt (find id.it env.vals) with | Some v -> k v @@ -281,7 +303,9 @@ and interpret_exp_mut env exp (k : V.value V.cont) = | CallE (exp1, typs, exp2) -> interpret_exp env exp1 (fun v1 -> interpret_exp env exp2 (fun v2 -> - let _, f = V.as_func v1 in f v2 k + let _, call_conv, f = V.as_func v1 in + check_call_conv exp1 call_conv; + f v2 k (* try @@ -338,7 +362,7 @@ and interpret_exp_mut env exp (k : V.value V.cont) = | ForE (pat, exp1, exp2) -> interpret_exp env exp1 (fun v1 -> let _, fs = V.as_obj v1 in - let _, next = V.as_func (find "next" fs) in + let _, _, next = V.as_func (find "next" fs) in let rec k_continue = fun v -> V.as_unit v; next V.unit (fun v' -> @@ -384,7 +408,7 @@ and interpret_exp_mut env exp (k : V.value V.cont) = let b = match v1 with | V.Obj (Some c1, _) -> - let c2, _ = V.as_func v2 in + let c2, _, _ = V.as_func v2 in Some c1 = c2 | _ -> false in k (V.Bool b) @@ -618,20 +642,20 @@ and interpret_dec env dec (k : V.value V.cont) = | FuncD (_sort, id, _typbinds, pat, _typ, exp) -> let f = interpret_func env id pat (fun env' -> interpret_exp env' exp) in - let v = V.Func (None, f) in + let v = V.Func (None, V.call_conv_of_typ dec.note.note_typ, f) in let v = match _sort.it with | T.Sharable -> make_message id dec.note.note_typ v | T.Local -> v - in + in define_id env id v; k v - | ClassD (id, _, _typbinds, sort, pat, id', fields) -> + | ClassD (id, _, _typbinds, sort, pat, id', fields) -> let c = V.new_class () in let f = interpret_func env id pat (fun env' k' -> interpret_obj env' sort id' (Some c) fields k') in - let v = V.Func (Some c, f) in + let v = V.Func (Some c, V.call_conv_of_typ dec.note.note_typ, f) in define_id env id v; k v diff --git a/src/prelude.ml b/src/prelude.ml index bd7504fe712..fc5cc4a4281 100644 --- a/src/prelude.ml +++ b/src/prelude.ml @@ -95,7 +95,7 @@ let prim = function (match Value.as_tup v with | [len; g] -> let len_nat = Int.to_int (as_int len) in - let (_, g') = Value.as_func g in + let (_, _, g') = Value.as_func g in let rec go prefix k i = if i == len_nat then k (Array (Array.of_list (prefix []))) diff --git a/src/type.mli b/src/type.mli index 19ce186aeb6..b57608b1051 100644 --- a/src/type.mli +++ b/src/type.mli @@ -141,6 +141,7 @@ module Env : Env.S with type key = string (* Pretty printing *) val string_of_prim : prim -> string +val string_of_func_sort: func_sort -> string val string_of_typ : typ -> string val string_of_kind : kind -> string val strings_of_kind : kind -> string * string * string diff --git a/src/value.ml b/src/value.ml index 7ae1e39a659..66ed19496d9 100644 --- a/src/value.ml +++ b/src/value.ml @@ -1,9 +1,9 @@ open Printf - +module T = Type (* Environments *) -module Env = Env.Make(String) +module Env = Env.Make(String) (* Numeric Representations *) @@ -53,7 +53,7 @@ struct let neg i = inj (Rep.neg (proj i)) let add i j = inj (Rep.add (proj i) (proj j)) let sub i j = inj (Rep.sub (proj i) (proj j)) - let mul i j = inj (Rep.mul (proj i) (proj j)) + let mul i j = inj (Rep.mul (proj i) (proj j)) let div i j = inj (Rep.div (proj i) (proj j)) let rem i j = inj (Rep.rem (proj i) (proj j)) let logand = Rep.logand @@ -190,7 +190,15 @@ end type unicode = int type class_ = int -type func = value -> value cont -> unit +type call_conv = Type.func_sort * Type.control * int * int + +let call_conv_of_typ typ = + match typ with + | Type.Func(s,c,tbds,dom,res) -> (s, c, List.length dom, List.length res) + | _ -> raise (Invalid_argument "call_conv_of_typ") + +type func = + (value -> value cont -> unit) and value = | Null | Bool of bool @@ -206,7 +214,7 @@ and value = | Opt of value | Array of value array | Obj of class_ option * value Env.t - | Func of class_ option * func + | Func of class_ option * call_conv * func | Async of async | Mut of value ref @@ -215,6 +223,12 @@ and def = value Lib.Promise.t and 'a cont = 'a -> unit +(* Smart constructors *) + +let local_func n m f = Func (None, (T.Call T.Local, T.Returns, n, m), f) +let message_func n f = Func (None, (T.Call T.Sharable, T.Returns, n, 0), f) +let async_func n m f = Func (None, (T.Call T.Sharable, T.Promises, n, m), f) + (* Classes *) let class_counter = ref 0 @@ -243,52 +257,44 @@ let as_unit = function Tup [] -> () | _ -> invalid "as_unit" let as_pair = function Tup [v1; v2] -> v1, v2 | _ -> invalid "as_pair" let obj_of_array a = - let get = - Func (None, fun v k -> - let n = as_int v in - if Nat.lt n (Nat.of_int (Array.length a)) then - k (a.(Nat.to_int n)) - else - raise (Invalid_argument "array index out of bounds") - ) - in - let set = - Func (None, fun v k -> - let v1, v2 = as_pair v in - let n = as_int v1 in - if Nat.lt n (Nat.of_int (Array.length a)) then - k (a.(Nat.to_int n) <- v2; Tup []) - else - raise (Invalid_argument "array index out of bounds") - ) - in - let len = - Func (None, fun v k -> as_unit v; k (Int (Nat.of_int (Array.length a)))) - in - let keys = - Func (None, fun v k -> - as_unit v; - let i = ref 0 in - let next = fun v k' -> + let get = local_func 1 1 @@ fun v k -> + let n = as_int v in + if Nat.lt n (Nat.of_int (Array.length a)) then + k (a.(Nat.to_int n)) + else + raise (Invalid_argument "array index out of bounds") in + + let set = local_func 1 1 @@ fun v k -> + let v1, v2 = as_pair v in + let n = as_int v1 in + if Nat.lt n (Nat.of_int (Array.length a)) then + k (a.(Nat.to_int n) <- v2; Tup []) + else + raise (Invalid_argument "array index out of bounds") in + + let len = local_func 0 1 @@ fun v k -> + as_unit v; k (Int (Nat.of_int (Array.length a))) in + + let keys = local_func 0 1 @@ fun v k -> + as_unit v; + let i = ref 0 in + let next = local_func 0 1 @@ fun v k' -> if !i = Array.length a then k' Null else - let v = Opt (Int (Nat.of_int !i)) in incr i; k' v - in k (Obj (None, Env.singleton "next" (Func (None, next)))) - ) - in - let vals = - Func (None, fun v k -> - as_unit v; - let i = ref 0 in - let next = fun v k' -> + let v = Opt (Int (Nat.of_int !i)) in incr i; k' v + in k (Obj (None, Env.singleton "next" next)) in + + let vals = local_func 0 1 @@ fun v k -> + as_unit v; + let i = ref 0 in + let next = local_func 0 1 @@ fun v k' -> if !i = Array.length a then k' Null else - let v = Opt (a.(!i)) in incr i; k' v - in k (Obj (None, Env.singleton "next" (Func (None, next)))) - ) - in + let v = Opt (a.(!i)) in incr i; k' v + in k (Obj (None, Env.singleton "next" next)) in + Env.from_list ["get", get; "set", set; "len", len; "keys", keys; "vals", vals] let as_obj = function Obj (co, ve) -> co, ve | Array a -> None, obj_of_array a | _ -> invalid "as_obj" -let as_func = function Func (co, f) -> co, f | _ -> invalid "as_func" +let as_func = function Func (co, cc, f) -> co, cc, f | _ -> invalid "as_func" let as_async = function Async a -> a | _ -> invalid "as_async" let as_mut = function Mut r -> r | _ -> invalid "as_mut" @@ -363,8 +369,8 @@ let rec string_of_val_nullary d = function | Array a -> sprintf "[%s]" (String.concat ", " (List.map (string_of_val' d) (Array.to_list a))) - | Func (None, _) -> "func" - | Func (Some _, _) -> "class" + | Func (None, _, _) -> "func" + | Func (Some _, _, _) -> "class" | v -> "(" ^ string_of_val' d v ^ ")" and string_of_val' d = function @@ -388,3 +394,12 @@ and string_of_def' d def = let string_of_val v = string_of_val' !Flags.print_depth v let string_of_def d = string_of_def' !Flags.print_depth d + +let string_of_call_conv (sort,control,args,results) = + sprintf "(%s %i %s %i)" + (T.string_of_func_sort sort) + args + (match control with + | T.Returns -> "->" + | T.Promises -> "@>") + results diff --git a/src/value.mli b/src/value.mli index 7900fc5fd2d..b25123d5c93 100644 --- a/src/value.mli +++ b/src/value.mli @@ -60,6 +60,10 @@ module Env : Env.S with type key = string type unicode = int type class_ +type call_conv = Type.func_sort * Type.control * int * int + +val call_conv_of_typ : Type.typ -> call_conv + type func = value -> value cont -> unit and value = | Null @@ -76,7 +80,7 @@ and value = | Opt of value | Array of value array | Obj of class_ option * value Env.t - | Func of class_ option * func + | Func of class_ option * call_conv * func | Async of async | Mut of value ref @@ -90,6 +94,12 @@ and 'a cont = 'a -> unit val unit : value +(* Smart constructors *) + +val local_func : int -> int -> func -> value +val message_func : int -> func -> value +val async_func : int -> int -> func -> value + (* Projections *) val as_null : value -> unit @@ -108,7 +118,7 @@ val as_unit : value -> unit val as_pair : value -> value * value val as_opt : value -> value val as_obj : value -> class_ option * value Env.t -val as_func : value -> class_ option * (value -> value cont -> unit) +val as_func : value -> class_ option * call_conv * func val as_async : value -> async val as_mut : value -> value ref @@ -128,3 +138,4 @@ val compare : value -> value -> int val string_of_val : value -> string val string_of_def : def -> string +val string_of_call_conv : call_conv -> string