Skip to content

Commit

Permalink
feat: add prim deadline for receiver-side best-effort messages (#4795)
Browse files Browse the repository at this point in the history
Cf. `ic0.msg_deadline` in dfinity/portal#3764

Adds `prim "deadline"` and access to it via `func replyDeadline` in `mo:prim`.

All mainnet subnets are providing the system interface API, so this is safe to deploy.

Feature flag for `drun` is `Enabled`.

[`motoko-base` support](dfinity/motoko-base/#677) will be merged in short order.
  • Loading branch information
ggreif authored Dec 5, 2024
1 parent 2873db9 commit 491a820
Show file tree
Hide file tree
Showing 21 changed files with 74 additions and 19 deletions.
11 changes: 11 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Motoko compiler changelog

## 0.13.5 (FUTURE)

* motoko (`moc`)

* Breaking change (minor):
Expand Down Expand Up @@ -33,6 +35,15 @@
On upgrade, the transient variable `invocations` will be reset to `0` and `value`, now implicitly `stable`, will retain its current value.
Legacy actors and classes declared without the `persistent` keyword have the same semantics as before.
* Added new primitive `replyDeadline : () -> Nat64` to obtain when a response for a best-effort message is due (#4795).
* motoko-base
* Added `Text.fromList` and `Text.toList` functions (dfinity/motoko-base#676).
* Added `Text.fromArray/fromVarArray` functions (dfinity/motoko-base#674).
## 0.13.4 (2024-11-29)
* motoko (`moc`)
Expand Down
6 changes: 3 additions & 3 deletions nix/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
"homepage": "",
"owner": "luc-blaeser",
"repo": "ic",
"rev": "33075cd385ea2ec4170f522406b1ff8f507fa744",
"sha256": "0swx7r78wjybx7fkfqsn9p3lqxmszgg24q4hrnxmscvyhb22hqia",
"rev": "bebe89514a6abd26e940b295323823169911a965",
"sha256": "1g68fyi5acbcgs2kjribk97fj8ki5g6pd99nwl5azz1rw1b0xycx",
"type": "tarball",
"url": "https://github.com/luc-blaeser/ic/archive/33075cd385ea2ec4170f522406b1ff8f507fa744.tar.gz",
"url": "https://github.com/luc-blaeser/ic/archive/bebe89514a6abd26e940b295323823169911a965.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"ic-hs": {
Expand Down
21 changes: 16 additions & 5 deletions src/codegen/compile_classical.ml
Original file line number Diff line number Diff line change
Expand Up @@ -5086,6 +5086,7 @@ module IC = struct
E.add_func_import env "ic0" "msg_reject" (i32s 2) [];
E.add_func_import env "ic0" "msg_reply_data_append" (i32s 2) [];
E.add_func_import env "ic0" "msg_reply" [] [];
E.add_func_import env "ic0" "msg_deadline" [] [I64Type];
E.add_func_import env "ic0" "performance_counter" [I32Type] [I64Type];
E.add_func_import env "ic0" "trap" (i32s 2) [];
E.add_func_import env "ic0" "stable64_write" (i64s 3) [];
Expand Down Expand Up @@ -5351,7 +5352,7 @@ module IC = struct
(fun env -> system_call env "msg_caller_copy")
(fun env -> compile_unboxed_const 0l)
| _ ->
E.trap_with env (Printf.sprintf "cannot get caller when running locally")
E.trap_with env "cannot get caller when running locally"

let method_name env =
match E.mode env with
Expand All @@ -5361,7 +5362,7 @@ module IC = struct
(fun env -> system_call env "msg_method_name_copy")
(fun env -> compile_unboxed_const 0l)
| _ ->
E.trap_with env (Printf.sprintf "cannot get method_name when running locally")
E.trap_with env "cannot get method_name when running locally"

let arg_data env =
match E.mode env with
Expand All @@ -5371,7 +5372,14 @@ module IC = struct
(fun env -> system_call env "msg_arg_data_copy")
(fun env -> compile_unboxed_const 0l)
| _ ->
E.trap_with env (Printf.sprintf "cannot get arg_data when running locally")
E.trap_with env "cannot get arg_data when running locally"

let deadline env =
match E.mode env with
| Flags.(ICMode | RefMode) ->
system_call env "msg_deadline"
| _ ->
E.trap_with env "cannot get deadline when running locally"

let reject env arg_instrs =
match E.mode env with
Expand All @@ -5381,7 +5389,7 @@ module IC = struct
Blob.as_ptr_len env ^^
system_call env "msg_reject"
| _ ->
E.trap_with env (Printf.sprintf "cannot reject when running locally")
E.trap_with env "cannot reject when running locally"

let error_code env =
Func.share_code0 Func.Always env "error_code" [I32Type] (fun env ->
Expand Down Expand Up @@ -12095,7 +12103,7 @@ and compile_prim_invocation (env : E.t) ae p es at =
Serialization.serialize env ts ^^
IC.reply_with_data env
| _ ->
E.trap_with env (Printf.sprintf "cannot reply when running locally")
E.trap_with env "cannot reply when running locally"
end

| ICRejectPrim, [e] ->
Expand Down Expand Up @@ -12144,6 +12152,9 @@ and compile_prim_invocation (env : E.t) ae p es at =
| ICMethodNamePrim, [] ->
SR.Vanilla, IC.method_name env

| ICReplyDeadlinePrim, [] ->
SR.UnboxedWord64 Type.Nat64, IC.deadline env

| ICStableRead ty, [] ->
(*
* On initial install:
Expand Down
21 changes: 16 additions & 5 deletions src/codegen/compile_enhanced.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4744,6 +4744,7 @@ module IC = struct
E.add_func_import env "ic0" "msg_reject" (i64s 2) [];
E.add_func_import env "ic0" "msg_reply_data_append" (i64s 2) [];
E.add_func_import env "ic0" "msg_reply" [] [];
E.add_func_import env "ic0" "msg_deadline" [] [I64Type];
E.add_func_import env "ic0" "performance_counter" [I32Type] [I64Type];
E.add_func_import env "ic0" "trap" (i64s 2) [];
E.add_func_import env "ic0" "stable64_write" (i64s 3) [];
Expand Down Expand Up @@ -5071,7 +5072,7 @@ module IC = struct
system_call env "msg_caller_copy")
(fun env -> compile_unboxed_const 0L)
| _ ->
E.trap_with env (Printf.sprintf "cannot get caller when running locally")
E.trap_with env "cannot get caller when running locally"

let method_name env =
match E.mode env with
Expand All @@ -5083,7 +5084,7 @@ module IC = struct
system_call env "msg_method_name_copy")
(fun env -> compile_unboxed_const 0L)
| _ ->
E.trap_with env (Printf.sprintf "cannot get method_name when running locally")
E.trap_with env "cannot get method_name when running locally"

let arg_data env =
match E.mode env with
Expand All @@ -5095,7 +5096,14 @@ module IC = struct
system_call env "msg_arg_data_copy")
(fun env -> compile_unboxed_const 0L)
| _ ->
E.trap_with env (Printf.sprintf "cannot get arg_data when running locally")
E.trap_with env "cannot get arg_data when running locally"

let deadline env =
match E.mode env with
| Flags.(ICMode | RefMode) ->
system_call env "msg_deadline"
| _ ->
E.trap_with env "cannot get deadline when running locally"

let reject env arg_instrs =
match E.mode env with
Expand All @@ -5105,7 +5113,7 @@ module IC = struct
Blob.as_ptr_len env ^^
system_call env "msg_reject"
| _ ->
E.trap_with env (Printf.sprintf "cannot reject when running locally")
E.trap_with env "cannot reject when running locally"

let error_code env =
Func.share_code0 Func.Always env "error_code" [I64Type] (fun env ->
Expand Down Expand Up @@ -12190,7 +12198,7 @@ and compile_prim_invocation (env : E.t) ae p es at =
Serialization.serialize env ts ^^
IC.reply_with_data env
| _ ->
E.trap_with env (Printf.sprintf "cannot reply when running locally")
E.trap_with env "cannot reply when running locally"
end

| ICRejectPrim, [e] ->
Expand Down Expand Up @@ -12239,6 +12247,9 @@ and compile_prim_invocation (env : E.t) ae p es at =
| ICMethodNamePrim, [] ->
SR.Vanilla, IC.method_name env

| ICReplyDeadlinePrim, [] ->
SR.UnboxedWord64 Type.Nat64, IC.deadline env

| ICStableRead ty, [] ->
SR.Vanilla,
Persistence.load env ty
Expand Down
1 change: 1 addition & 0 deletions src/ir_def/arrange_ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ and prim = function
| ICCallPrim -> Atom "ICCallPrim"
| ICCallRawPrim -> Atom "ICCallRawPrim"
| ICMethodNamePrim -> Atom "ICMethodNamePrim"
| ICReplyDeadlinePrim -> Atom "ICReplyDeadlinePrim"
| ICStableWrite t -> "ICStableWrite" $$ [typ t]
| ICStableRead t -> "ICStableRead" $$ [typ t]

Expand Down
2 changes: 2 additions & 0 deletions src/ir_def/check_ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,8 @@ let rec check_exp env (exp:Ir.exp) : unit =
T.unit <: t
| ICMethodNamePrim, [] ->
T.text <: t
| ICReplyDeadlinePrim, [] ->
T.nat64 <: t
| ICStableRead t1, [] ->
check_typ env t1;
check (store_typ t1) "Invalid type argument to ICStableRead";
Expand Down
4 changes: 3 additions & 1 deletion src/ir_def/ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ and prim =
| ICCallPrim
| ICCallRawPrim
| ICMethodNamePrim
| ICReplyDeadlinePrim
| ICArgDataPrim
| ICStableWrite of Type.typ (* serialize value of stable type to stable memory *)
| ICStableRead of Type.typ (* deserialize value of stable type from stable memory *)
Expand Down Expand Up @@ -322,7 +323,8 @@ let map_prim t_typ t_id p =
| ICCallerPrim
| ICCallPrim
| ICCallRawPrim
| ICMethodNamePrim -> p
| ICMethodNamePrim
| ICReplyDeadlinePrim -> p
| ICStableWrite t -> ICStableWrite (t_typ t)
| ICStableRead t -> ICStableRead (t_typ t)
| ICStableSize t -> ICStableSize (t_typ t)
2 changes: 2 additions & 0 deletions src/ir_interpreter/interpret_ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,8 @@ and interpret_exp_mut env exp (k : V.value V.cont) =
f (V.Tup[vc; kv; rv; cv]) v2 k
| ICCallerPrim, [] ->
k env.caller
| ICReplyDeadlinePrim, [] ->
k (V.Nat64 Numerics.Nat64.zero)
| ICStableRead t, [] ->
let (_, tfs) = T.as_obj t in
let ve = List.fold_left
Expand Down
3 changes: 3 additions & 0 deletions src/lowering/desugar.ml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ and exp' at note = function
| S.CallE ({it=S.AnnotE ({it=S.PrimE "caller";_},_);_}, _, {it=S.TupE es;_}) ->
assert (es = []);
I.PrimE (I.ICCallerPrim, [])
| S.CallE ({it=S.AnnotE ({it=S.PrimE "deadline";_},_);_}, _, {it=S.TupE es;_}) ->
assert (es = []);
I.PrimE (I.ICReplyDeadlinePrim, [])
| S.CallE ({it=S.AnnotE ({it=S.PrimE "time";_},_);_}, _, {it=S.TupE es;_}) ->
assert (es = []);
I.PrimE (I.SystemTimePrim, [])
Expand Down
1 change: 1 addition & 0 deletions src/mo_values/prim.ml
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ let prim trap =
| "rts_upgrade_instructions") ->
fun _ v k -> as_unit v; k (Int (Int.of_int 0))
| "time" -> fun _ v k -> as_unit v; k (Value.Nat64 (Numerics.Nat64.of_int 42))
| "deadline" -> fun _ v k -> as_unit v; k (Value.Nat64 Numerics.Nat64.zero)
| "idlHash" -> fun _ v k ->
let s = as_text v in
k (Nat32 (Nat32.wrapping_of_big_int (Big_int.big_int_of_int32 (Lib.Uint32.to_int32 (Idllib.IdlHash.idl_hash s)))))
Expand Down
4 changes: 4 additions & 0 deletions src/prelude/prim.mo
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,10 @@ func error(message : Text) : Error {
func errorCode(e : Error) : ErrorCode = ((prim "cast" : Error -> (ErrorCode, Text)) e).0;
func errorMessage(e : Error) : Text = ((prim "cast" : Error -> (ErrorCode, Text)) e).1;
// Message deadline (best-effort messaging)
func replyDeadline() : Nat64 = (prim "deadline" : () -> Nat64) ();
// Time
func time() : Nat64 = (prim "time" : () -> Nat64)();
Expand Down
1 change: 1 addition & 0 deletions test/fail/ok/no-timer-canc.tc.ok
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ no-timer-canc.mo:3.10-3.21: type error [M0119], object field cancelTimer is not
regionStoreNat32 : (Region, Nat64, Nat32) -> ();
regionStoreNat64 : (Region, Nat64, Nat64) -> ();
regionStoreNat8 : (Region, Nat64, Nat8) -> ();
replyDeadline : () -> Nat64;
rts_callback_table_count : () -> Nat;
rts_callback_table_size : () -> Nat;
rts_collector_instructions : () -> Nat;
Expand Down
1 change: 1 addition & 0 deletions test/fail/ok/no-timer-set.tc.ok
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ no-timer-set.mo:3.10-3.18: type error [M0119], object field setTimer is not cont
regionStoreNat32 : (Region, Nat64, Nat32) -> ();
regionStoreNat64 : (Region, Nat64, Nat64) -> ();
regionStoreNat8 : (Region, Nat64, Nat8) -> ();
replyDeadline : () -> Nat64;
rts_callback_table_count : () -> Nat;
rts_callback_table_size : () -> Nat;
rts_collector_instructions : () -> Nat;
Expand Down
1 change: 1 addition & 0 deletions test/fail/ok/suggest-long-ai.tc.ok
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ suggest-long-ai.mo:4.1-4.5: type error [M0072], field stableM does not exist in
regionStoreNat32 : (Region, Nat64, Nat32) -> ();
regionStoreNat64 : (Region, Nat64, Nat64) -> ();
regionStoreNat8 : (Region, Nat64, Nat8) -> ();
replyDeadline : () -> Nat64;
rts_callback_table_count : () -> Nat;
rts_callback_table_size : () -> Nat;
rts_collector_instructions : () -> Nat;
Expand Down
1 change: 1 addition & 0 deletions test/fail/ok/suggest-short-ai.tc.ok
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ suggest-short-ai.mo:4.1-4.5: type error [M0072], field s does not exist in type:
regionStoreNat32 : (Region, Nat64, Nat32) -> ();
regionStoreNat64 : (Region, Nat64, Nat64) -> ();
regionStoreNat8 : (Region, Nat64, Nat8) -> ();
replyDeadline : () -> Nat64;
rts_callback_table_count : () -> Nat;
rts_callback_table_size : () -> Nat;
rts_collector_instructions : () -> Nat;
Expand Down
1 change: 1 addition & 0 deletions test/run-drun/composite-query.mo
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ actor Composites {
};

public composite query func cq1() : async () {
assert 0 : Nat64 == Prim.replyDeadline();
};

public composite query func cq2() : async () {
Expand Down
4 changes: 2 additions & 2 deletions test/run-drun/ok/composite-query.tc.ok
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
composite-query.mo:30.11-30.13: warning [M0145], this pattern of type
composite-query.mo:31.11-31.13: warning [M0145], this pattern of type
?Class__1
does not cover value
null
composite-query.mo:35.11-35.13: warning [M0145], this pattern of type
composite-query.mo:36.11-36.13: warning [M0145], this pattern of type
?Class__1
does not cover value
null
2 changes: 1 addition & 1 deletion test/run-drun/ok/query2.run-ir.ok
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ In read:
6
6
The following fails in the interpreter, for lack of query semantics
query2.mo:35.4-35.18: execution error, assertion failure
query2.mo:37.4-37.18: execution error, assertion failure
2 changes: 1 addition & 1 deletion test/run-drun/ok/query2.run-low.ok
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ In read:
6
6
The following fails in the interpreter, for lack of query semantics
query2.mo:35.4-35.18: execution error, assertion failure
query2.mo:37.4-37.18: execution error, assertion failure
2 changes: 1 addition & 1 deletion test/run-drun/ok/query2.run.ok
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ In read:
6
6
The following fails in the interpreter, for lack of query semantics
query2.mo:35.4-35.18: execution error, assertion failure
query2.mo:37.4-37.18: execution error, assertion failure
2 changes: 2 additions & 0 deletions test/run-drun/query2.mo
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ actor counter = {
Prim.debugPrintNat c;
};
public func printCounter () : async () {
assert 0 : Nat64 == Prim.replyDeadline();
Prim.debugPrintNat c;
};
public func get() : async Nat {
return c
};
public query func read() : async Nat {
assert 0 : Nat64 == Prim.replyDeadline();
let tmp = c;
c += 1;
Prim.debugPrint "In read:";
Expand Down

0 comments on commit 491a820

Please sign in to comment.