Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

experiment: attach optional migration expression to actor (class) as actor [exp]? #4812

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
03476d6
attach optional migration expression to actor (class) as actor [exp]?
crusso Dec 10, 2024
67425f7
first draft of logic
crusso Dec 13, 2024
ee545f5
test (not working)
crusso Dec 13, 2024
bb81d3f
working with loose ends
crusso Dec 17, 2024
e3621d6
working (without type-checking)
crusso Dec 18, 2024
5b75bd9
add typechecking (wip)
crusso Dec 18, 2024
bb965a5
Apply suggestions from code review
crusso Dec 18, 2024
7f5b963
cleanup
crusso Dec 18, 2024
bc23bcb
Merge branch 'claudio/migration' of github.com:dfinity/motoko into cl…
crusso Dec 18, 2024
406d244
ocamlformat
crusso Dec 18, 2024
7d4737e
eop changes (WIP)
crusso Dec 19, 2024
9964bb3
add rts_in_install prim; working
crusso Dec 19, 2024
9ca998c
extend signatures to record pre and post when required
crusso Dec 20, 2024
d28733b
fix printer
crusso Dec 20, 2024
c23fd70
fix printer
crusso Dec 20, 2024
8202cb0
refine versioning
crusso Jan 8, 2025
45b6c07
fix grammar
crusso Jan 8, 2025
858826e
remove fix me
crusso Jan 8, 2025
76b5faf
Claudio/migration eop sigs refactor (#4842)
crusso Jan 8, 2025
19487b1
simplify; delete trailing whitespace
crusso Jan 8, 2025
568d090
Update test/run-drun/upgrade-migration/Migration1.mo
crusso Jan 8, 2025
20be12c
check for hash collisions in induced pre signature
crusso Jan 8, 2025
1906f91
refine static checks on migration function:
crusso Jan 8, 2025
ebe108d
implement scoping properly
crusso Jan 9, 2025
86272d3
refactor to use syntactic exp_opt@
crusso Jan 10, 2025
91a73b5
update test output
crusso Jan 10, 2025
079700b
add test for lexical scoping
crusso Jan 10, 2025
ebe63ca
refactor typechecking code
crusso Jan 10, 2025
ea99627
tidy some todos
crusso Jan 10, 2025
55b56fd
loose ends
crusso Jan 10, 2025
d7b67c2
renamings@
crusso Jan 10, 2025
2b686f8
Update src/mo_types/type.ml
crusso Jan 10, 2025
c70ed43
adjust definedness (not too sure about this tbh)
crusso Jan 10, 2025
1a89789
Merge branch 'claudio/migration' of github.com:dfinity/motoko into cl…
crusso Jan 10, 2025
9077c9c
custom error codes
crusso Jan 10, 2025
edffd72
missing test
crusso Jan 10, 2025
b9c844b
implement interprete rts_in_install prim; check migration exxpression…
crusso Jan 13, 2025
6c918b2
simplify upgrade-migration.drun; add corresponding upgrade-class-migr…
crusso Jan 13, 2025
4383f81
add comments
crusso Jan 13, 2025
45ffad5
port to class tests
crusso Jan 13, 2025
a2f7ea4
fix tests
crusso Jan 13, 2025
f3994a4
update test output
crusso Jan 14, 2025
9bc4b78
positive tests (derived from drun/upgrade-migration.drun
crusso Jan 15, 2025
843043a
add more cmp test and correct calculation of pre-sig to remove migrat…
crusso Jan 15, 2025
85c46e9
fix typo in test
crusso Jan 15, 2025
cb1416d
Apply suggestions from code review
crusso Jan 15, 2025
e8f7b2c
remove negative test since eop doesn't allow field deletion
crusso Jan 15, 2025
21f1f23
remove debug spew
crusso Jan 15, 2025
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
2 changes: 1 addition & 1 deletion doc/md/examples/grammar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<obj_sort> ::=
'object'
'persistent'? 'actor'
'persistent'? 'actor' ('[' <exp> ']')?
'module'

<query> ::=
Expand Down
16 changes: 16 additions & 0 deletions rts/motoko-rts/src/persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,22 @@ pub unsafe fn register_stable_type<M: Memory>(
(*metadata).stable_type.assign(mem, &new_type);
}

/// Register the stable actor type on canister initialization and upgrade.
/// The type is stored in the persistent metadata memory for later retrieval on canister upgrades.
/// The `new_type` value points to a blob encoding the new stable actor type.
#[ic_mem_fn]
pub unsafe fn assign_stable_type<M: Memory>(
mem: &mut M,
new_candid_data: Value,
new_type_offsets: Value,
) {
assert_eq!(new_candid_data.tag(), TAG_BLOB_B);
assert_eq!(new_type_offsets.tag(), TAG_BLOB_B);
let new_type = TypeDescriptor::new(new_candid_data, new_type_offsets);
let metadata = PersistentMetadata::get();
(*metadata).stable_type.assign(mem, &new_type);
}

pub(crate) unsafe fn stable_type_descriptor() -> &'static mut TypeDescriptor {
let metadata = PersistentMetadata::get();
&mut (*metadata).stable_type
Expand Down
9 changes: 9 additions & 0 deletions src/codegen/compile_classical.ml
Original file line number Diff line number Diff line change
Expand Up @@ -11616,6 +11616,15 @@ and compile_prim_invocation (env : E.t) ae p es at =
SR.Vanilla,
StableMem.get_mem_size env ^^ BigNum.from_word64 env

| OtherPrim "rts_in_install", [] -> (* classical specific *)
assert (not !Flags.enhanced_orthogonal_persistence);
SR.Vanilla,
StableMem.stable64_size env ^^
G.i (Test (Wasm_exts.Values.I64 I64Op.Eqz)) ^^
G.if1 I32Type
(Bool.lit true)
(Bool.lit false)

(* Regions *)

| OtherPrim "regionNew", [] ->
Expand Down
30 changes: 24 additions & 6 deletions src/codegen/compile_enhanced.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,7 @@ module RTS = struct
E.add_func_import env "rts" "allocation_barrier" [I64Type] [I64Type];
E.add_func_import env "rts" "running_gc" [] [I32Type];
E.add_func_import env "rts" "register_stable_type" [I64Type; I64Type] [];
E.add_func_import env "rts" "assign_stable_type" [I64Type; I64Type] [];
E.add_func_import env "rts" "load_stable_actor" [] [I64Type];
E.add_func_import env "rts" "save_stable_actor" [I64Type] [];
E.add_func_import env "rts" "free_stable_actor" [] [];
Expand Down Expand Up @@ -8694,6 +8695,10 @@ module EnhancedOrthogonalPersistence = struct
create_type_descriptor env actor_type ^^
E.call_import env "rts" "register_stable_type"

let assign_stable_type env actor_type =
create_type_descriptor env actor_type ^^
E.call_import env "rts" "assign_stable_type"

let load_old_field env field get_old_actor =
if field.Type.typ = Type.(Opt Any) then
(* A stable variable may have been promoted to type `Any`: Therefore, drop its former content. *)
Expand Down Expand Up @@ -8733,6 +8738,7 @@ module EnhancedOrthogonalPersistence = struct
free_stable_actor env

let save env actor_type =
assign_stable_type env actor_type ^^
IC.get_actor_to_persist env ^^
save_stable_actor env ^^
NewStableMemory.backup env ^^
Expand All @@ -8751,6 +8757,7 @@ module EnhancedOrthogonalPersistence = struct

let initialize env actor_type =
register_stable_type env actor_type

end (* EnhancedOrthogonalPersistence *)

(* As fallback when doing persistent memory layout changes. *)
Expand Down Expand Up @@ -9981,12 +9988,12 @@ module IncrementalGraphStabilization = struct
let partial_destabilization_on_upgrade env actor_type =
(* TODO: Verify that the post_upgrade hook cannot be directly called by the IC *)
(* Garbage collection is disabled in `start_graph_destabilization` until destabilization has completed. *)
GraphCopyStabilization.start_graph_destabilization env actor_type ^^
GraphCopyStabilization.start_graph_destabilization env actor_type.Ir.pre ^^
get_destabilized_actor env ^^
compile_test I64Op.Eqz ^^
E.if0
begin
destabilization_increment env actor_type ^^
destabilization_increment env actor_type.Ir.pre ^^
get_destabilized_actor env ^^
(E.if0
G.nop
Expand Down Expand Up @@ -10018,22 +10025,22 @@ module IncrementalGraphStabilization = struct
})
| _ -> ()
end

let load env =
get_destabilized_actor env ^^
compile_test I64Op.Eqz ^^
E.then_trap_with env "Destabilization is not yet completed: Call __motoko_destabilize_after_upgrade" ^^
get_destabilized_actor env
(* Upgrade costs are already record in RTS for graph-copy-based (de-)stabilization. *)

let define_methods env actor_type =
let define_methods env (actor_type : Ir.stable_actor_typ) =
define_async_stabilization_reply_callback env;
define_async_stabilization_reject_callback env;
export_async_stabilization_method env;
export_stabilize_before_upgrade_method env actor_type;
export_stabilize_before_upgrade_method env actor_type.Ir.post;
define_async_destabilization_reply_callback env;
define_async_destabilization_reject_callback env;
export_async_destabilization_method env actor_type;
export_async_destabilization_method env actor_type.Ir.pre;
export_destabilize_after_upgrade_method env;

end (* IncrementalGraphStabilization *)
Expand Down Expand Up @@ -11678,6 +11685,15 @@ and compile_prim_invocation (env : E.t) ae p es at =
SR.Vanilla,
StableMem.get_mem_size env ^^ BigNum.from_word64 env

| OtherPrim "rts_in_install", [] -> (* EOP specific *)
assert (!Flags.enhanced_orthogonal_persistence);
SR.Vanilla,
EnhancedOrthogonalPersistence.load_stable_actor env ^^
compile_test I64Op.Eqz ^^
E.if1 I64Type
(Bool.lit true)
(Bool.lit false)

(* Regions *)

| OtherPrim "regionNew", [] ->
Expand Down Expand Up @@ -12252,9 +12268,11 @@ and compile_prim_invocation (env : E.t) ae p es at =

| ICStableRead ty, [] ->
SR.Vanilla,
(* IC.compile_static_print env ("ICStableRead" ^ Type.string_of_typ ty) ^^ *)
Persistence.load env ty
| ICStableWrite ty, [] ->
SR.unit,
(* IC.compile_static_print env ("ICStableWrite" ^ Type.string_of_typ ty) ^^ *)
Persistence.save env ty

(* Cycles *)
Expand Down
14 changes: 11 additions & 3 deletions src/docs/extract.ml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ struct
_;
} -> (
match rhs with
| Source.{ it = Syntax.ObjBlockE (sort, _, fields); _ } ->
| Source.{ it = Syntax.ObjBlockE (sort, _, _, fields); _ } ->
let mk_field_xref xref = mk_xref (Xref.XClass (name, xref)) in
Some
( mk_xref (Xref.XType name),
Expand All @@ -155,7 +155,7 @@ struct
)
| Source.{ it = Syntax.VarD ({ it = name; _ }, rhs); _ } -> (
match rhs with
| Source.{ it = Syntax.ObjBlockE (sort, _, fields); _ } ->
| Source.{ it = Syntax.ObjBlockE (sort, _, _, fields); _ } ->
let mk_field_xref xref = mk_xref (Xref.XClass (name, xref)) in
Some
( mk_xref (Xref.XType name),
Expand Down Expand Up @@ -184,7 +184,15 @@ struct
{
it =
Syntax.ClassD
(shared_pat, name, type_args, ctor, _, obj_sort, _, fields);
( shared_pat,
exp_opt,
name,
type_args,
ctor,
_,
obj_sort,
_,
fields );
_;
} ->
let mk_field_xref xref = mk_xref (Xref.XClass (name.it, xref)) in
Expand Down
4 changes: 2 additions & 2 deletions src/docs/namespace.ml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ let from_module =
| Syntax.ExpD _ -> acc
| Syntax.LetD
( { it = Syntax.VarP id; _ },
{ it = Syntax.ObjBlockE (_, _, decs); _ },
{ it = Syntax.ObjBlockE (_, _, _, decs); _ },
_ ) ->
let mk_nested x = mk_xref (Xref.XNested (id.it, x)) in
{
Expand Down Expand Up @@ -69,7 +69,7 @@ let from_module =
(mk_xref (Xref.XValue id.it), None)
acc.values;
}
| Syntax.ClassD (_, id, _, _, _, _, _, _) ->
| Syntax.ClassD (_, _, id, _, _, _, _, _, _) ->
{
acc with
types = StringMap.add id.it (mk_xref (Xref.XType id.it)) acc.types;
Expand Down
2 changes: 1 addition & 1 deletion src/gen-grammar/grammar.sed
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ s/<id>/ID/g
/^<parse_module_header> ::=/,+2d
/^<stab_field> ::=/,+2d
/^<typ_dec> ::=/,+2d
/^<parse_stab_sig> ::=/,+2d
/^<parse_stab_sig> ::=/,+5d
/.*PRIM.*/d
/^<bl> ::=/,+2d
/^<ob> ::=/,+2d
Expand Down
2 changes: 1 addition & 1 deletion src/ir_def/arrange_ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ and system { meta; preupgrade; postupgrade; heartbeat; timer; inspect; stable_re
"Timer" $$ [exp timer];
"Inspect" $$ [exp inspect];
"StableRecord" $$ [exp stable_record];
"StableType" $$ [typ stable_type]
"StableType" $$ [typ stable_type.pre; typ stable_type.post]
]

and lexp le = match le.it with
Expand Down
6 changes: 3 additions & 3 deletions src/ir_def/check_ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ let rec check_typ env typ : unit =
if not (Lib.List.is_strictly_ordered T.compare_field fields) then
error env no_region "variant type's fields are not distinct and sorted %s" (T.string_of_typ typ)
| T.Mut typ ->
error env no_region "unexpected T.Mut"
error env no_region "unexpected T.Mut %s" (T.string_of_typ typ)
| T.Typ c ->
error env no_region "unexpected T.Typ"

Expand Down Expand Up @@ -834,7 +834,7 @@ let rec check_exp env (exp:Ir.exp) : unit =
typ heartbeat <: T.unit;
typ timer <: T.unit;
typ inspect <: T.unit;
typ stable_record <: stable_type;
typ stable_record <: stable_type.post;
check (T.is_obj t0) "bad annotation (object type expected)";
let (s0, tfs0) = T.as_obj t0 in
let val_tfs0 = List.filter (fun tf -> not (T.is_typ tf.T.typ)) tfs0 in
Expand Down Expand Up @@ -1184,7 +1184,7 @@ let check_comp_unit env = function
typ heartbeat <: T.unit;
typ timer <: T.unit;
typ inspect <: T.unit;
typ stable_record <: stable_type;
typ stable_record <: stable_type.post;
check (T.is_obj t0) "bad annotation (object type expected)";
let (s0, tfs0) = T.as_obj t0 in
let val_tfs0 = List.filter (fun tf -> not (T.is_typ tf.T.typ)) tfs0 in
Expand Down
35 changes: 35 additions & 0 deletions src/ir_def/construct.ml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ let primE prim es =
| OtherPrim "rts_max_stack_size" -> T.nat
| OtherPrim "rts_callback_table_count" -> T.nat
| OtherPrim "rts_callback_table_size" -> T.nat
| OtherPrim "rts_in_install" -> T.bool
| _ -> assert false (* implement more as needed *)
in
let eff = map_max_effs eff es in
Expand Down Expand Up @@ -790,8 +791,42 @@ let objE sort typ_flds flds =
in
go [] [] [] flds


let recordE flds = objE T.Object [] flds

let objectE sort flds (tfs : T.field list) =
let rec go ds fields = function
| [] ->
blockE
(List.rev ds)
(newObjE sort fields
(T.Obj (sort, List.sort T.compare_field tfs)))
| (lab, exp)::flds ->
let v, typ, ds =
match T.lookup_val_field_opt lab tfs with
| None -> assert false
| Some typ ->
if T.is_mut typ
then
let v = fresh_var lab typ in
v, typ, varD v exp :: ds
else
match exp.it with
| VarE (Const, v) ->
var v typ, typ, ds
| _ ->
let v = fresh_var lab typ in
v, typ, letD v exp :: ds
in
let field = {
it = {name = lab; var = id_of_var v};
at = no_region;
note = typ
} in
go ds (field::fields) flds
in
go [] [] flds

let check_call_perform_status success mk_failure =
ifE
(callE
Expand Down
2 changes: 2 additions & 0 deletions src/ir_def/construct.mli
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ val (-*-) : exp -> exp -> exp (* application *)

val objE : obj_sort -> (lab * con) list -> (lab * exp) list -> exp

val objectE : obj_sort -> (lab * exp) list -> field list -> exp

(* Records *)

val recordE : (lab * exp) list -> exp
Expand Down
6 changes: 4 additions & 2 deletions src/ir_def/ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ and exp' =
| NewObjE of Type.obj_sort * field list * Type.typ (* make an object *)
| TryE of exp * case list * (id * Type.typ) option (* try/catch/cleanup *)

and stable_actor_typ = { pre: Type.typ; post: Type.typ }

and system = {
meta : meta;
(* TODO: use option expressions for (some or all of) these *)
Expand All @@ -86,7 +88,7 @@ and system = {
timer : exp; (* TODO: use an option type: (Default of exp | UserDefined of exp) option *)
inspect : exp;
stable_record: exp;
stable_type: Type.typ;
stable_type: stable_actor_typ;
}

and candid = {
Expand Down Expand Up @@ -242,7 +244,7 @@ type actor_type = {
transient_actor_type: Type.typ;
(* record of stable actor fields used for persistence,
the fields are without mutability distinctions *)
stable_actor_type: Type.typ
stable_actor_type: stable_actor_typ
}

(* Program *)
Expand Down
7 changes: 5 additions & 2 deletions src/ir_passes/async.ml
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ let transform prog =
timer = t_exp timer;
inspect = t_exp inspect;
stable_record = t_exp stable_record;
stable_type = t_typ stable_type;
stable_type = {pre = t_typ stable_type.pre; post = t_typ stable_type.post};
},
t_typ typ)
| NewObjE (sort, ids, t) ->
Expand Down Expand Up @@ -532,7 +532,10 @@ let transform prog =
timer = t_exp timer;
inspect = t_exp inspect;
stable_record = t_exp stable_record;
stable_type = t_typ stable_type;
stable_type = {
pre = t_typ stable_type.pre;
post = t_typ stable_type.post
}
},
t_typ t)

Expand Down
10 changes: 8 additions & 2 deletions src/ir_passes/erase_typ_field.ml
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ let transform prog =
timer = t_exp timer;
inspect = t_exp inspect;
stable_record = t_exp stable_record;
stable_type = t_typ stable_type;
stable_type = {
pre = t_typ stable_type.pre;
post = t_typ stable_type.post
}
},
t_typ typ)

Expand Down Expand Up @@ -220,7 +223,10 @@ let transform prog =
timer = t_exp timer;
inspect = t_exp inspect;
stable_record = t_exp stable_record;
stable_type = t_typ stable_type;
stable_type = {
pre = t_typ stable_type.pre;
post = t_typ stable_type.post
}
},
t_typ t)
and t_prog (cu, flavor) = (t_comp_unit cu, { flavor with has_typ_field = false } )
Expand Down
2 changes: 1 addition & 1 deletion src/languageServer/declaration_index.ml
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ let populate_definitions (project_root : string) (libs : Syntax.lib list)
let is_type_def dec_field =
match dec_field.it.Syntax.dec.it with
| Syntax.TypD (typ_id, _, _) -> Some typ_id
| Syntax.ClassD (_, typ_id, _, _, _, _, _, _) -> Some typ_id
| Syntax.ClassD (_, _, typ_id, _, _, _, _, _, _) -> Some typ_id
| _ -> None
in
let extract_binders env (pat : Syntax.pat) = gather_pat env pat in
Expand Down
Loading
Loading