From 307df370663f320ab149a35f1e286510ecc3e871 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 18 Feb 2022 22:49:23 +0000 Subject: [PATCH 001/128] start implemenation of rts candid subtyping check --- rts/motoko-rts/src/idl.rs | 233 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 37dfd7a584a..ee026c542ab 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -486,3 +486,236 @@ unsafe extern "C" fn skip_fields(tb: *mut Buf, buf: *mut Buf, typtbl: *mut *mut *n -= 1; } } + +unsafe fn unfold(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> i32 { + let mut tb = Buf { + ptr: *typtbl.add(t as usize), + end: (*buf).end, + }; + return sleb128_decode(&mut tb); +} + +// https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 + +#[no_mangle] +unsafe extern "C" fn sub(buf1: *mut Buf, + buf2: *mut Buf, + typtbl1: *mut *mut u8, + typtbl2: *mut *mut u8, + t1: i32, + t2: i32, + depth: i32) -> bool { + + if depth > 100 { + idl_trap_with("sub: subtyping too deep"); + } + + // re-declare as mut for any unfolding + let mut t1 = t1; + let mut t2 = t2; + + + /* primitives reflexive */ + if is_primitive_type(t1) && + is_primitive_type(t2) && + t1 == t2 { + return true; + } + + // unfold t1, if necessary + let mut tb1 = Buf { + ptr: *typtbl1.add(if t1 < 0 { 0 } else { t1 as usize }), // better dummy? + end: (*buf1).end, + }; + + if t1 >= 0 { + t1 = sleb128_decode(&mut tb1); + }; + + // unfold t2, if necessary + let mut tb2 = Buf { + ptr: *typtbl2.add(if t2 < 0 { 0 } else { t2 as usize }), // better dummy? + end: (*buf2).end, + }; + + if t2 >= 0 { + t2 = sleb128_decode(&mut tb2); + }; + + debug_assert!(t1 < 0 && t2 < 0); + + match (t1, t2) { + (_, IDL_PRIM_reserved) => true, + (IDL_PRIM_empty, _) => false, + (IDL_PRIM_null, IDL_CON_opt) => true, + (IDL_CON_opt, IDL_CON_opt) => { + let t11 = sleb128_decode(&mut tb1); + let t21 = sleb128_decode(&mut tb2); + return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); + }, + // todo: ugly opt cases + (IDL_CON_vec, IDL_CON_vec) => { + let t11 = sleb128_decode(&mut tb1); + let t21 = sleb128_decode(&mut tb2); + return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); + }, + // default + (IDL_CON_func, IDL_CON_func) => { + // contra in domain + let in1 = leb128_decode(&mut tb1); + let in2 = leb128_decode(&mut tb2); + if in1 > in2 { + return false; + } + for _ in 0..in1 { + let t11 = sleb128_decode(&mut tb1); + let t21 = sleb128_decode(&mut tb2); + if !sub(buf2, buf1, typtbl2, typtbl1, t21, t11, depth + 1) { + return false + } + }; + for _ in in1..in2 { + let _ = sleb128_decode(&mut tb2); + }; + // co in range + let out1 = leb128_decode(&mut tb1); + let out2 = leb128_decode(&mut tb2); + if out2 > out1 { + return false; + } + for _ in 0..out2 { + let t11 = sleb128_decode(&mut tb1); + let t21 = sleb128_decode(&mut tb2); + if !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + return false; + } + }; + for _ in out2..out1 { + let _ = sleb128_decode(&mut tb1); + }; + // TODO: annotations (as sets!) + // Annotations + /* + for _ in 0..leb128_decode(buf) { + let a = read_byte(buf); + if !(1 <= a && a <= 2) { + idl_trap_with("func annotation not within 1..2"); + } + } + */ + return true + }, + (_,_) => false, + + } +/* + buf.advance(2); + } + => { + buf.advance(4); + } + IDL_PRIM_nat64 | IDL_PRIM_int64 | IDL_PRIM_float64 => { + buf.advance(8); + } + IDL_PRIM_text => skip_text(buf), + IDL_PRIM_empty => { + idl_trap_with("skip_any: encountered empty"); + } + IDL_REF_principal => { + if read_byte_tag(buf) != 0 { + skip_blob(buf); + } + } + _ => { + idl_trap_with("skip_any: unknown prim"); + } + } + } else { + // t >= 0 + let mut tb = Buf { + ptr: *typtbl.add(t as usize), + end: (*buf).end, + }; + let tc = sleb128_decode(&mut tb); + match tc { + IDL_CON_opt => { + let it = sleb128_decode(&mut tb); + if read_byte_tag(buf) != 0 { + skip_any(buf, typtbl, it, 0); + } + } + IDL_CON_vec => { + let it = sleb128_decode(&mut tb); + let count = leb128_decode(buf); + skip_any_vec(buf, typtbl, it, count); + } + IDL_CON_record => { + for _ in 0..leb128_decode(&mut tb) { + skip_leb128(&mut tb); + let it = sleb128_decode(&mut tb); + // This is just a quick check; we should be keeping + // track of all enclosing records to detect larger loops + if it == t { + idl_trap_with("skip_any: recursive record"); + } + skip_any(buf, typtbl, it, depth + 1); + } + } + IDL_CON_variant => { + let n = leb128_decode(&mut tb); + let i = leb128_decode(buf); + if i >= n { + idl_trap_with("skip_any: variant tag too large"); + } + for _ in 0..i { + skip_leb128(&mut tb); + skip_leb128(&mut tb); + } + skip_leb128(&mut tb); + let it = sleb128_decode(&mut tb); + skip_any(buf, typtbl, it, 0); + } + IDL_CON_func => { + if read_byte_tag(buf) == 0 { + idl_trap_with("skip_any: skipping references"); + } else { + if read_byte_tag(buf) == 0 { + idl_trap_with("skip_any: skipping references"); + } else { + skip_blob(buf) + } + skip_text(buf) + } + } + IDL_CON_service => { + if read_byte_tag(buf) == 0 { + idl_trap_with("skip_any: skipping references"); + } else { + skip_blob(buf) + } + } + IDL_CON_alias => { + // See Note [mutable stable values] in codegen/compile.ml + let it = sleb128_decode(&mut tb); + let tag = read_byte_tag(buf); + if tag == 0 { + buf.advance(8); + // this is the contents (not a reference) + skip_any(buf, typtbl, it, 0); + } else { + buf.advance(4); + } + } + _ => { + // Future type + let n_data = leb128_decode(buf); + let n_ref = leb128_decode(buf); + buf.advance(n_data); + if n_ref > 0 { + idl_trap_with("skip_any: skipping references"); + } + } + } + } +*/ +} From 99a7a474cb93c7c3fbee2e234bdd33d805d97da3 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 18 Feb 2022 22:53:13 +0000 Subject: [PATCH 002/128] rustfmt --- rts/motoko-rts/src/idl.rs | 247 +++++++++++++++++++------------------- 1 file changed, 122 insertions(+), 125 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index ee026c542ab..3336869a715 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -498,14 +498,15 @@ unsafe fn unfold(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> i32 { // https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 #[no_mangle] -unsafe extern "C" fn sub(buf1: *mut Buf, - buf2: *mut Buf, - typtbl1: *mut *mut u8, - typtbl2: *mut *mut u8, - t1: i32, - t2: i32, - depth: i32) -> bool { - +unsafe extern "C" fn sub( + buf1: *mut Buf, + buf2: *mut Buf, + typtbl1: *mut *mut u8, + typtbl2: *mut *mut u8, + t1: i32, + t2: i32, + depth: i32, +) -> bool { if depth > 100 { idl_trap_with("sub: subtyping too deep"); } @@ -514,12 +515,9 @@ unsafe extern "C" fn sub(buf1: *mut Buf, let mut t1 = t1; let mut t2 = t2; - /* primitives reflexive */ - if is_primitive_type(t1) && - is_primitive_type(t2) && - t1 == t2 { - return true; + if is_primitive_type(t1) && is_primitive_type(t2) && t1 == t2 { + return true; } // unfold t1, if necessary @@ -552,13 +550,13 @@ unsafe extern "C" fn sub(buf1: *mut Buf, let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - }, + } // todo: ugly opt cases (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - }, + } // default (IDL_CON_func, IDL_CON_func) => { // contra in domain @@ -568,15 +566,15 @@ unsafe extern "C" fn sub(buf1: *mut Buf, return false; } for _ in 0..in1 { - let t11 = sleb128_decode(&mut tb1); - let t21 = sleb128_decode(&mut tb2); + let t11 = sleb128_decode(&mut tb1); + let t21 = sleb128_decode(&mut tb2); if !sub(buf2, buf1, typtbl2, typtbl1, t21, t11, depth + 1) { - return false + return false; } - }; + } for _ in in1..in2 { - let _ = sleb128_decode(&mut tb2); - }; + let _ = sleb128_decode(&mut tb2); + } // co in range let out1 = leb128_decode(&mut tb1); let out2 = leb128_decode(&mut tb2); @@ -584,17 +582,17 @@ unsafe extern "C" fn sub(buf1: *mut Buf, return false; } for _ in 0..out2 { - let t11 = sleb128_decode(&mut tb1); - let t21 = sleb128_decode(&mut tb2); - if !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { - return false; - } - }; + let t11 = sleb128_decode(&mut tb1); + let t21 = sleb128_decode(&mut tb2); + if !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + return false; + } + } for _ in out2..out1 { - let _ = sleb128_decode(&mut tb1); - }; + let _ = sleb128_decode(&mut tb1); + } // TODO: annotations (as sets!) - // Annotations + // Annotations /* for _ in 0..leb128_decode(buf) { let a = read_byte(buf); @@ -603,119 +601,118 @@ unsafe extern "C" fn sub(buf1: *mut Buf, } } */ - return true - }, - (_,_) => false, - + return true; + } + (_, _) => false, } -/* - buf.advance(2); - } - => { - buf.advance(4); - } - IDL_PRIM_nat64 | IDL_PRIM_int64 | IDL_PRIM_float64 => { - buf.advance(8); - } - IDL_PRIM_text => skip_text(buf), - IDL_PRIM_empty => { - idl_trap_with("skip_any: encountered empty"); - } - IDL_REF_principal => { - if read_byte_tag(buf) != 0 { - skip_blob(buf); + /* + buf.advance(2); } - } - _ => { - idl_trap_with("skip_any: unknown prim"); - } - } - } else { - // t >= 0 - let mut tb = Buf { - ptr: *typtbl.add(t as usize), - end: (*buf).end, - }; - let tc = sleb128_decode(&mut tb); - match tc { - IDL_CON_opt => { - let it = sleb128_decode(&mut tb); - if read_byte_tag(buf) != 0 { - skip_any(buf, typtbl, it, 0); + => { + buf.advance(4); + } + IDL_PRIM_nat64 | IDL_PRIM_int64 | IDL_PRIM_float64 => { + buf.advance(8); + } + IDL_PRIM_text => skip_text(buf), + IDL_PRIM_empty => { + idl_trap_with("skip_any: encountered empty"); + } + IDL_REF_principal => { + if read_byte_tag(buf) != 0 { + skip_blob(buf); + } + } + _ => { + idl_trap_with("skip_any: unknown prim"); } } - IDL_CON_vec => { - let it = sleb128_decode(&mut tb); - let count = leb128_decode(buf); - skip_any_vec(buf, typtbl, it, count); - } - IDL_CON_record => { - for _ in 0..leb128_decode(&mut tb) { - skip_leb128(&mut tb); + } else { + // t >= 0 + let mut tb = Buf { + ptr: *typtbl.add(t as usize), + end: (*buf).end, + }; + let tc = sleb128_decode(&mut tb); + match tc { + IDL_CON_opt => { let it = sleb128_decode(&mut tb); - // This is just a quick check; we should be keeping - // track of all enclosing records to detect larger loops - if it == t { - idl_trap_with("skip_any: recursive record"); + if read_byte_tag(buf) != 0 { + skip_any(buf, typtbl, it, 0); } - skip_any(buf, typtbl, it, depth + 1); } - } - IDL_CON_variant => { - let n = leb128_decode(&mut tb); - let i = leb128_decode(buf); - if i >= n { - idl_trap_with("skip_any: variant tag too large"); + IDL_CON_vec => { + let it = sleb128_decode(&mut tb); + let count = leb128_decode(buf); + skip_any_vec(buf, typtbl, it, count); } - for _ in 0..i { - skip_leb128(&mut tb); + IDL_CON_record => { + for _ in 0..leb128_decode(&mut tb) { + skip_leb128(&mut tb); + let it = sleb128_decode(&mut tb); + // This is just a quick check; we should be keeping + // track of all enclosing records to detect larger loops + if it == t { + idl_trap_with("skip_any: recursive record"); + } + skip_any(buf, typtbl, it, depth + 1); + } + } + IDL_CON_variant => { + let n = leb128_decode(&mut tb); + let i = leb128_decode(buf); + if i >= n { + idl_trap_with("skip_any: variant tag too large"); + } + for _ in 0..i { + skip_leb128(&mut tb); + skip_leb128(&mut tb); + } skip_leb128(&mut tb); + let it = sleb128_decode(&mut tb); + skip_any(buf, typtbl, it, 0); } - skip_leb128(&mut tb); - let it = sleb128_decode(&mut tb); - skip_any(buf, typtbl, it, 0); - } - IDL_CON_func => { - if read_byte_tag(buf) == 0 { - idl_trap_with("skip_any: skipping references"); - } else { + IDL_CON_func => { if read_byte_tag(buf) == 0 { idl_trap_with("skip_any: skipping references"); } else { - skip_blob(buf) + if read_byte_tag(buf) == 0 { + idl_trap_with("skip_any: skipping references"); + } else { + skip_blob(buf) + } + skip_text(buf) } - skip_text(buf) } - } - IDL_CON_service => { - if read_byte_tag(buf) == 0 { - idl_trap_with("skip_any: skipping references"); - } else { - skip_blob(buf) + IDL_CON_service => { + if read_byte_tag(buf) == 0 { + idl_trap_with("skip_any: skipping references"); + } else { + skip_blob(buf) + } } - } - IDL_CON_alias => { - // See Note [mutable stable values] in codegen/compile.ml - let it = sleb128_decode(&mut tb); - let tag = read_byte_tag(buf); - if tag == 0 { - buf.advance(8); - // this is the contents (not a reference) - skip_any(buf, typtbl, it, 0); - } else { - buf.advance(4); + IDL_CON_alias => { + // See Note [mutable stable values] in codegen/compile.ml + let it = sleb128_decode(&mut tb); + let tag = read_byte_tag(buf); + if tag == 0 { + buf.advance(8); + // this is the contents (not a reference) + skip_any(buf, typtbl, it, 0); + } else { + buf.advance(4); + } } - } - _ => { - // Future type - let n_data = leb128_decode(buf); - let n_ref = leb128_decode(buf); - buf.advance(n_data); - if n_ref > 0 { - idl_trap_with("skip_any: skipping references"); + _ => { + // Future type + let n_data = leb128_decode(buf); + let n_ref = leb128_decode(buf); + buf.advance(n_data); + if n_ref > 0 { + idl_trap_with("skip_any: skipping references"); + } } } } - } -*/ + */ } From 0a19a81c8d7d91b41fbb84b2c2c0a95aee6eb245 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Sat, 19 Feb 2022 19:17:29 +0000 Subject: [PATCH 003/128] handle annotations; add TODO --- rts/motoko-rts/src/idl.rs | 41 +++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 3336869a715..fb67e4f084d 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -167,6 +167,11 @@ unsafe fn parse_idl_header( if !(1 <= a && a <= 2) { idl_trap_with("func annotation not within 1..2"); } + // TODO: shouldn't we also check + // * 1 (query) or 2 (oneway), but not both + // * 2 -> |Ret types| == 0 + // c.f. https://github.com/dfinity/candid/issues/318 + // NB: if this code changes, change sub type check below accordingly } } else if ty == IDL_CON_service { let mut last_len: u32 = 0 as u32; @@ -591,17 +596,33 @@ unsafe extern "C" fn sub( for _ in out2..out1 { let _ = sleb128_decode(&mut tb1); } - // TODO: annotations (as sets!) - // Annotations - /* - for _ in 0..leb128_decode(buf) { - let a = read_byte(buf); - if !(1 <= a && a <= 2) { - idl_trap_with("func annotation not within 1..2"); - } + // check annotations (that we care about) + // TODO: more generally, we would check equality of 256-bit bit-vectors, + // but validity ensures each entry is 1 or 2 (for now) + // c.f. https://github.com/dfinity/candid/issues/318 + let mut a11 = false; + let mut a12 = false; + for _ in 0..leb128_decode(buf1) { + let a = read_byte(buf1); + if a == 1 { + a11 = true; + }; + if a == 2 { + a12 = true; + }; + } + let mut a21 = false; + let mut a22 = false; + for _ in 0..leb128_decode(buf2) { + let a = read_byte(buf2); + if a == 1 { + a21 = true; + }; + if a == 2 { + a22 = true; + }; } - */ - return true; + return (a11 == a21) && (a12 == a22); } (_, _) => false, } From fe1a39915033eb5c89a5876b30701e51dda21837 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Sat, 19 Feb 2022 20:30:46 +0000 Subject: [PATCH 004/128] subtyping on variants --- rts/motoko-rts/src/idl.rs | 132 ++++++++------------------------------ 1 file changed, 25 insertions(+), 107 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index fb67e4f084d..d1bc5cf3a47 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -624,116 +624,34 @@ unsafe extern "C" fn sub( } return (a11 == a21) && (a12 == a22); } - (_, _) => false, - } - /* - buf.advance(2); - } - => { - buf.advance(4); - } - IDL_PRIM_nat64 | IDL_PRIM_int64 | IDL_PRIM_float64 => { - buf.advance(8); - } - IDL_PRIM_text => skip_text(buf), - IDL_PRIM_empty => { - idl_trap_with("skip_any: encountered empty"); - } - IDL_REF_principal => { - if read_byte_tag(buf) != 0 { - skip_blob(buf); - } - } - _ => { - idl_trap_with("skip_any: unknown prim"); - } - } - } else { - // t >= 0 - let mut tb = Buf { - ptr: *typtbl.add(t as usize), - end: (*buf).end, - }; - let tc = sleb128_decode(&mut tb); - match tc { - IDL_CON_opt => { - let it = sleb128_decode(&mut tb); - if read_byte_tag(buf) != 0 { - skip_any(buf, typtbl, it, 0); - } - } - IDL_CON_vec => { - let it = sleb128_decode(&mut tb); - let count = leb128_decode(buf); - skip_any_vec(buf, typtbl, it, count); - } - IDL_CON_record => { - for _ in 0..leb128_decode(&mut tb) { - skip_leb128(&mut tb); - let it = sleb128_decode(&mut tb); - // This is just a quick check; we should be keeping - // track of all enclosing records to detect larger loops - if it == t { - idl_trap_with("skip_any: recursive record"); - } - skip_any(buf, typtbl, it, depth + 1); - } - } - IDL_CON_variant => { - let n = leb128_decode(&mut tb); - let i = leb128_decode(buf); - if i >= n { - idl_trap_with("skip_any: variant tag too large"); - } - for _ in 0..i { - skip_leb128(&mut tb); - skip_leb128(&mut tb); - } - skip_leb128(&mut tb); - let it = sleb128_decode(&mut tb); - skip_any(buf, typtbl, it, 0); - } - IDL_CON_func => { - if read_byte_tag(buf) == 0 { - idl_trap_with("skip_any: skipping references"); - } else { - if read_byte_tag(buf) == 0 { - idl_trap_with("skip_any: skipping references"); - } else { - skip_blob(buf) - } - skip_text(buf) - } - } - IDL_CON_service => { - if read_byte_tag(buf) == 0 { - idl_trap_with("skip_any: skipping references"); - } else { - skip_blob(buf) - } - } - IDL_CON_alias => { - // See Note [mutable stable values] in codegen/compile.ml - let it = sleb128_decode(&mut tb); - let tag = read_byte_tag(buf); - if tag == 0 { - buf.advance(8); - // this is the contents (not a reference) - skip_any(buf, typtbl, it, 0); - } else { - buf.advance(4); + (IDL_CON_variant, IDL_CON_variant) => { + let n1 = leb128_decode(buf1); + let mut n2 = leb128_decode(buf2); + for _ in 0..n1 { + if n2 == 0 { + return false; + }; + let tag1 = leb128_decode(buf1); + let t11 = sleb128_decode(buf1); + let mut tag2 = 0; + let mut t21 = 0; + loop { + tag2 = leb128_decode(buf2); + t21 = sleb128_decode(buf2); + n2 -= 1; + if !(tag2 < tag1 && n2 > 0) { + break; } } - _ => { - // Future type - let n_data = leb128_decode(buf); - let n_ref = leb128_decode(buf); - buf.advance(n_data); - if n_ref > 0 { - idl_trap_with("skip_any: skipping references"); - } + if tag1 != tag2 { + return false; + }; + if !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + return false; } } + return true; } - */ + (_, _) => false, + } } From 65ce5874dfa7e085e3166ac4d8ab1e11b916ba27 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 21 Feb 2022 17:29:40 +0000 Subject: [PATCH 005/128] records; first stab --- rts/motoko-rts/src/idl.rs | 61 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index d1bc5cf3a47..7bdc19dbe0f 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -500,8 +500,31 @@ unsafe fn unfold(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> i32 { return sleb128_decode(&mut tb); } -// https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 +unsafe fn opt_empty_sub( + buf: *mut Buf, + typtbl: *mut *mut u8, + t: i32, +) -> bool { + + if is_primitive_type(t) { + return t == IDL_PRIM_reserved; + } + + // unfold t + let mut t = t; + + let mut tb = Buf { + ptr: *typtbl.add(t as usize), + end: (*buf).end, + }; + + t = sleb128_decode(&mut tb); + + return t == IDL_CON_opt; +} + +// https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 #[no_mangle] unsafe extern "C" fn sub( buf1: *mut Buf, @@ -624,6 +647,42 @@ unsafe extern "C" fn sub( } return (a11 == a21) && (a12 == a22); } + (IDL_CON_record, IDL_CON_record) => { + let mut n1 = leb128_decode(buf1); + let n2 = leb128_decode(buf2); + for _ in 0..n2 { + let tag2 = leb128_decode(buf2); + let t21 = sleb128_decode(buf2); + if n1 == 0 { + return opt_empty_sub(buf2, typtbl2, t21); + }; + let mut tag1 = 0; + let mut t11 = 0; + let mut save_ptr : *mut u8 = (*buf1).ptr; + loop { + save_ptr = (*buf1).ptr; + tag1 = leb128_decode(buf1); + t11 = sleb128_decode(buf1); + n1 -= 1; + if !(tag1 < tag2 && n1 > 0) { + break; + } + } + if tag1 > tag2 { + if opt_empty_sub(buf2, typtbl2, t21) { + // reconsider this field + (*buf1).ptr = save_ptr; + n1 += 1; + continue; + } + else { return false; } + }; + if !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + return false; + } + } + return true; + }, (IDL_CON_variant, IDL_CON_variant) => { let n1 = leb128_decode(buf1); let mut n2 = leb128_decode(buf2); From 8061aaf540ce1e77c2a075790ac9f7d6020787c2 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 21 Feb 2022 17:40:52 +0000 Subject: [PATCH 006/128] fix bug --- rts/motoko-rts/src/idl.rs | 53 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 7bdc19dbe0f..c7118fc69c1 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -500,14 +500,8 @@ unsafe fn unfold(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> i32 { return sleb128_decode(&mut tb); } - -unsafe fn opt_empty_sub( - buf: *mut Buf, - typtbl: *mut *mut u8, - t: i32, -) -> bool { - - if is_primitive_type(t) { +unsafe fn opt_empty_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { + if is_primitive_type(t) { return t == IDL_PRIM_reserved; } @@ -650,39 +644,44 @@ unsafe extern "C" fn sub( (IDL_CON_record, IDL_CON_record) => { let mut n1 = leb128_decode(buf1); let n2 = leb128_decode(buf2); + let mut tag1 = 0; + let mut t11 = 0; + let mut advance = true; for _ in 0..n2 { let tag2 = leb128_decode(buf2); let t21 = sleb128_decode(buf2); if n1 == 0 { - return opt_empty_sub(buf2, typtbl2, t21); + // check all remaining fields optional + if !opt_empty_sub(buf2, typtbl2, t21) { + return false; + } + continue; }; - let mut tag1 = 0; - let mut t11 = 0; - let mut save_ptr : *mut u8 = (*buf1).ptr; - loop { - save_ptr = (*buf1).ptr; - tag1 = leb128_decode(buf1); - t11 = sleb128_decode(buf1); - n1 -= 1; - if !(tag1 < tag2 && n1 > 0) { - break; + if advance { + loop { + tag1 = leb128_decode(buf1); + t11 = sleb128_decode(buf1); + n1 -= 1; + if !(tag1 < tag2 && n1 > 0) { + break; + } } - } + }; if tag1 > tag2 { - if opt_empty_sub(buf2, typtbl2, t21) { - // reconsider this field - (*buf1).ptr = save_ptr; - n1 += 1; - continue; + if !opt_empty_sub(buf2, typtbl2, t21) { + // missing, non_opt field + return false; } - else { return false; } + advance = false; // reconsider this field in next round + continue; }; if !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { return false; } + advance = true; } return true; - }, + } (IDL_CON_variant, IDL_CON_variant) => { let n1 = leb128_decode(buf1); let mut n2 = leb128_decode(buf2); From c3adb822efe1c07b22f5c1b766924d132784391b Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 28 Feb 2022 14:03:06 +0000 Subject: [PATCH 007/128] opt cases --- rts/motoko-rts/src/idl.rs | 44 ++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index c7118fc69c1..0b4f9630443 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -518,7 +518,27 @@ unsafe fn opt_empty_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { return t == IDL_CON_opt; } +unsafe fn null_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { + if is_primitive_type(t) { + return t == IDL_PRIM_empty || t == IDL_PRIM_null; + } + + // unfold t + let mut t = t; + + let mut tb = Buf { + ptr: *typtbl.add(t as usize), + end: (*buf).end, + }; + + t = sleb128_decode(&mut tb); + + return t == IDL_CON_opt; +} + + // https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 +// https://github.com/dfinity/candid/blob/20b84d1c1515e2c1db353ebe02b738486f835466/spec/Candid.md #[no_mangle] unsafe extern "C" fn sub( buf1: *mut Buf, @@ -567,19 +587,32 @@ unsafe extern "C" fn sub( match (t1, t2) { (_, IDL_PRIM_reserved) => true, (IDL_PRIM_empty, _) => false, +/* (IDL_PRIM_null, IDL_CON_opt) => true, (IDL_CON_opt, IDL_CON_opt) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - } - // todo: ugly opt cases + }, + (_, IDL_CON_opt) => { + let t21 = sleb128_decode(&mut tb2); + return + !null_sub(buf1, typetbl1, t1) && + !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); + }, + (_, IDL_CON_opt) => { + let t21 = sleb128_decode(&mut tb2); + return + !null_sub(buf1, typetbl1, t1) && + !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); + }, +*/ + (_, IDL_CON_opt) => true, // apparently, this is admissable (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - } - // default + }, (IDL_CON_func, IDL_CON_func) => { // contra in domain let in1 = leb128_decode(&mut tb1); @@ -709,7 +742,8 @@ unsafe extern "C" fn sub( } } return true; - } + }, + // default (_, _) => false, } } From da679f13e0ce3360856d14a81a1482f116913449 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 3 Mar 2022 14:01:51 +0000 Subject: [PATCH 008/128] basic bitset --- rts/motoko-rts/src/bitset.rs | 33 +++++++++++++++++++++++++++++++++ rts/motoko-rts/src/idl.rs | 2 +- rts/motoko-rts/src/lib.rs | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 rts/motoko-rts/src/bitset.rs diff --git a/rts/motoko-rts/src/bitset.rs b/rts/motoko-rts/src/bitset.rs new file mode 100644 index 00000000000..ccd05d0722f --- /dev/null +++ b/rts/motoko-rts/src/bitset.rs @@ -0,0 +1,33 @@ +//! This module implements a simple bit set to be used by the compiler (in generated code) + +use crate::idl_trap_with; + +#[repr(packed)] +pub struct BitSet { + /// Pointer into the bit set + pub ptr: *mut u8, + /// Pointer to the end of the bit set + pub end: *mut u8, +} + +impl BitSet { + #[cfg(feature = "ic")] + pub(crate) unsafe fn set(self: *mut Self, n: u32) { + let byte = (n / 8) as usize; + let bit = (n % 8) as u8; + let dst = (*self).ptr.add(byte); + if dst > (*self).end { idl_trap_with("BitSet.set out of bounds"); }; + *dst = *dst | (1 << bit); + } + + pub(crate) unsafe fn get(self: *mut Self, n: u32) -> bool { + let byte = (n / 8) as usize; + let bit = (n % 8) as u8; + let src = (*self).ptr.add(byte); + if src > (*self).end { idl_trap_with("BitSet.get out of bounds"); }; + let mask = 1 << bit; + return *src & mask == mask; + } +} + + diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 0b4f9630443..d933af7f028 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -1,5 +1,5 @@ #![allow(non_upper_case_globals)] - +use crate::bitset::{BitSet}; use crate::buf::{read_byte, read_word, skip_leb128, Buf}; use crate::idl_trap_with; use crate::leb128::{leb128_decode, sleb128_decode}; diff --git a/rts/motoko-rts/src/lib.rs b/rts/motoko-rts/src/lib.rs index ece3c07a95b..a54be5e5ecc 100644 --- a/rts/motoko-rts/src/lib.rs +++ b/rts/motoko-rts/src/lib.rs @@ -12,6 +12,7 @@ pub mod debug; pub mod bigint; #[cfg(feature = "ic")] mod blob_iter; +mod bitset; pub mod buf; mod char; pub mod constants; From 23ce44275a8a3e8277d41e9a2c9935d7fce769e1 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 3 Mar 2022 14:03:14 +0000 Subject: [PATCH 009/128] formatting --- rts/motoko-rts/src/bitset.rs | 10 +++++--- rts/motoko-rts/src/idl.rs | 47 ++++++++++++++++++------------------ rts/motoko-rts/src/lib.rs | 2 +- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/rts/motoko-rts/src/bitset.rs b/rts/motoko-rts/src/bitset.rs index ccd05d0722f..e6dc8d53c4d 100644 --- a/rts/motoko-rts/src/bitset.rs +++ b/rts/motoko-rts/src/bitset.rs @@ -16,7 +16,9 @@ impl BitSet { let byte = (n / 8) as usize; let bit = (n % 8) as u8; let dst = (*self).ptr.add(byte); - if dst > (*self).end { idl_trap_with("BitSet.set out of bounds"); }; + if dst > (*self).end { + idl_trap_with("BitSet.set out of bounds"); + }; *dst = *dst | (1 << bit); } @@ -24,10 +26,10 @@ impl BitSet { let byte = (n / 8) as usize; let bit = (n % 8) as u8; let src = (*self).ptr.add(byte); - if src > (*self).end { idl_trap_with("BitSet.get out of bounds"); }; + if src > (*self).end { + idl_trap_with("BitSet.get out of bounds"); + }; let mask = 1 << bit; return *src & mask == mask; } } - - diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index d933af7f028..24dd6a450db 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -1,5 +1,5 @@ #![allow(non_upper_case_globals)] -use crate::bitset::{BitSet}; +use crate::bitset::BitSet; use crate::buf::{read_byte, read_word, skip_leb128, Buf}; use crate::idl_trap_with; use crate::leb128::{leb128_decode, sleb128_decode}; @@ -536,7 +536,6 @@ unsafe fn null_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { return t == IDL_CON_opt; } - // https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 // https://github.com/dfinity/candid/blob/20b84d1c1515e2c1db353ebe02b738486f835466/spec/Candid.md #[no_mangle] @@ -587,32 +586,32 @@ unsafe extern "C" fn sub( match (t1, t2) { (_, IDL_PRIM_reserved) => true, (IDL_PRIM_empty, _) => false, -/* - (IDL_PRIM_null, IDL_CON_opt) => true, - (IDL_CON_opt, IDL_CON_opt) => { - let t11 = sleb128_decode(&mut tb1); - let t21 = sleb128_decode(&mut tb2); - return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - }, - (_, IDL_CON_opt) => { - let t21 = sleb128_decode(&mut tb2); - return - !null_sub(buf1, typetbl1, t1) && - !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - }, - (_, IDL_CON_opt) => { - let t21 = sleb128_decode(&mut tb2); - return - !null_sub(buf1, typetbl1, t1) && - !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - }, -*/ + /* + (IDL_PRIM_null, IDL_CON_opt) => true, + (IDL_CON_opt, IDL_CON_opt) => { + let t11 = sleb128_decode(&mut tb1); + let t21 = sleb128_decode(&mut tb2); + return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); + }, + (_, IDL_CON_opt) => { + let t21 = sleb128_decode(&mut tb2); + return + !null_sub(buf1, typetbl1, t1) && + !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); + }, + (_, IDL_CON_opt) => { + let t21 = sleb128_decode(&mut tb2); + return + !null_sub(buf1, typetbl1, t1) && + !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); + }, + */ (_, IDL_CON_opt) => true, // apparently, this is admissable (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - }, + } (IDL_CON_func, IDL_CON_func) => { // contra in domain let in1 = leb128_decode(&mut tb1); @@ -742,7 +741,7 @@ unsafe extern "C" fn sub( } } return true; - }, + } // default (_, _) => false, } diff --git a/rts/motoko-rts/src/lib.rs b/rts/motoko-rts/src/lib.rs index a54be5e5ecc..4213c69f1d5 100644 --- a/rts/motoko-rts/src/lib.rs +++ b/rts/motoko-rts/src/lib.rs @@ -10,9 +10,9 @@ mod print; pub mod debug; pub mod bigint; +mod bitset; #[cfg(feature = "ic")] mod blob_iter; -mod bitset; pub mod buf; mod char; pub mod constants; From 130955886738f436a6e891cfdd49d934c7918bcb Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 3 Mar 2022 15:20:02 +0000 Subject: [PATCH 010/128] implement BitRel --- rts/motoko-rts/src/bitset.rs | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/rts/motoko-rts/src/bitset.rs b/rts/motoko-rts/src/bitset.rs index e6dc8d53c4d..fe1aab961ac 100644 --- a/rts/motoko-rts/src/bitset.rs +++ b/rts/motoko-rts/src/bitset.rs @@ -33,3 +33,64 @@ impl BitSet { return *src & mask == mask; } } + +#[repr(packed)] +pub struct BitRel { + /// Pointer into the bit set + pub ptr: *mut u8, + /// Pointer to the end of the bit set + pub end: *mut u8, + pub n: u32, + pub m: u32, +} + +impl BitRel { + pub(crate) unsafe fn clear(self: *mut Self) { + let mut ptr = (*self).ptr; + while ptr < (*self).end { + *ptr = 0; + ptr = ptr.add(1); + } + } + + pub(crate) unsafe fn set(self: *mut Self, p: bool, i_j: u32, j_i: u32) { + let n = (*self).n; + let m = (*self).m; + let (i, j, base) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; + if i >= n { + idl_trap_with("BitRel.set i out of bounds"); + }; + if j >= m { + idl_trap_with("BitRel.set j out of bounds"); + }; + let k = base + i * m + j; + let byte = (k / 8) as usize; + let bit = (k % 8) as u8; + let dst = (*self).ptr.add(byte); + if dst > (*self).end { + idl_trap_with("BitRel.set out of bounds"); + }; + *dst = *dst | (1 << bit); + } + + pub(crate) unsafe fn get(self: *mut Self, p: bool, i_j: u32, j_i: u32) -> bool { + let n = (*self).n; + let m = (*self).m; + let (i, j, base) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; + if i >= n { + idl_trap_with("BitRel.set i out of bounds"); + }; + if j >= m { + idl_trap_with("BitRel.set j out of bounds"); + }; + let k = base + i * m + j; + let byte = (k / 8) as usize; + let bit = (k % 8) as u8; + let src = (*self).ptr.add(byte); + if src > (*self).end { + idl_trap_with("BitRel.get out of bounds"); + }; + let mask = 1 << bit; + return *src & mask == mask; + } +} From 3f676b41af502267f2f3351497d7a426a4e32132 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 3 Mar 2022 15:22:47 +0000 Subject: [PATCH 011/128] edit --- rts/motoko-rts/src/bitset.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rts/motoko-rts/src/bitset.rs b/rts/motoko-rts/src/bitset.rs index fe1aab961ac..0da879846b5 100644 --- a/rts/motoko-rts/src/bitset.rs +++ b/rts/motoko-rts/src/bitset.rs @@ -11,7 +11,6 @@ pub struct BitSet { } impl BitSet { - #[cfg(feature = "ic")] pub(crate) unsafe fn set(self: *mut Self, n: u32) { let byte = (n / 8) as usize; let bit = (n % 8) as u8; From de6f75b40dda0501a23f775837fff510606dd2e0 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 3 Mar 2022 17:22:39 +0000 Subject: [PATCH 012/128] add the cache --- rts/motoko-rts/src/bitset.rs | 8 +++- rts/motoko-rts/src/idl.rs | 79 ++++++++++++++++++++++++++++++++---- 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/rts/motoko-rts/src/bitset.rs b/rts/motoko-rts/src/bitset.rs index 0da879846b5..1f2ea9b84f9 100644 --- a/rts/motoko-rts/src/bitset.rs +++ b/rts/motoko-rts/src/bitset.rs @@ -44,7 +44,12 @@ pub struct BitRel { } impl BitRel { - pub(crate) unsafe fn clear(self: *mut Self) { + + pub(crate) unsafe fn init(self: &mut Self) { + let bytes = (((*self).end as usize) - ((*self).ptr as usize)) as u32; + if (self.n * self.m * 2) > bytes * 8 { + idl_trap_with("BitRel not enough bytes"); + }; let mut ptr = (*self).ptr; while ptr < (*self).end { *ptr = 0; @@ -93,3 +98,4 @@ impl BitRel { return *src & mask == mask; } } + diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 24dd6a450db..1ce916b1a94 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -1,5 +1,5 @@ #![allow(non_upper_case_globals)] -use crate::bitset::BitSet; +use crate::bitset::{BitRel}; use crate::buf::{read_byte, read_word, skip_leb128, Buf}; use crate::idl_trap_with; use crate::leb128::{leb128_decode, sleb128_decode}; @@ -538,8 +538,9 @@ unsafe fn null_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { // https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 // https://github.com/dfinity/candid/blob/20b84d1c1515e2c1db353ebe02b738486f835466/spec/Candid.md -#[no_mangle] -unsafe extern "C" fn sub( +unsafe fn sub( + rel : *mut BitRel, + p : bool, buf1: *mut Buf, buf2: *mut Buf, typtbl1: *mut *mut u8, @@ -581,6 +582,17 @@ unsafe extern "C" fn sub( t2 = sleb128_decode(&mut tb2); }; + if t1 >= 0 && t2 >= 0 { + let t1 = t1 as u32; + let t2 = t2 as u32; + if rel.get(p, t1, t2) { + // cached: succeed! + return true + }; + // cache and continue + rel.set(p, t1, t2); + }; + debug_assert!(t1 < 0 && t2 < 0); match (t1, t2) { @@ -610,7 +622,7 @@ unsafe extern "C" fn sub( (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); - return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); + return sub(rel, p, buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); } (IDL_CON_func, IDL_CON_func) => { // contra in domain @@ -622,7 +634,8 @@ unsafe extern "C" fn sub( for _ in 0..in1 { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); - if !sub(buf2, buf1, typtbl2, typtbl1, t21, t11, depth + 1) { + // NB: invert p and args! + if !sub(rel, !p, buf2, buf1, typtbl2, typtbl1, t21, t11, depth + 1) { return false; } } @@ -638,7 +651,7 @@ unsafe extern "C" fn sub( for _ in 0..out2 { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); - if !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { return false; } } @@ -707,7 +720,7 @@ unsafe extern "C" fn sub( advance = false; // reconsider this field in next round continue; }; - if !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { return false; } advance = true; @@ -736,7 +749,7 @@ unsafe extern "C" fn sub( if tag1 != tag2 { return false; }; - if !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { return false; } } @@ -746,3 +759,53 @@ unsafe extern "C" fn sub( (_, _) => false, } } + +unsafe fn table_size( + buf: *mut Buf +) -> u32 { + + let mut buf = Buf { + ptr: (*buf).ptr, + end: (*buf).end, + }; + + if buf.ptr == buf.end { + idl_trap_with( + "empty input. Expected Candid-encoded argument, but received a zero-length argument", + ); + } + + // Magic bytes (DIDL) + if read_word(&mut buf) != 0x4C444944 { + idl_trap_with("missing magic bytes"); + } + + return leb128_decode(&mut buf); +} + +#[no_mangle] +unsafe extern "C" fn sub_type( + rel_buf : *mut Buf, // a buffer with at least 2 * n * m bits + buf1: *mut Buf, + buf2: *mut Buf, + typtbl1: *mut *mut u8, + typtbl2: *mut *mut u8, + t1: i32, + t2: i32, +) -> bool { + + let n = table_size(buf1); + let m = table_size(buf2); + + let mut rel = BitRel { + ptr: (*rel_buf).ptr, + end: (*rel_buf).end, + n: n, + m: m, + }; + + rel.init(); + + return sub(&mut rel, true, buf1, buf2, typtbl1, typtbl2, t1, t2, 0); + +} From fd4a6b07a637a06f97a909ddf1ec6cf03c9d036c Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 3 Mar 2022 17:32:00 +0000 Subject: [PATCH 013/128] simplify types --- rts/motoko-rts/src/bitset.rs | 22 +++++++++++----------- rts/motoko-rts/src/idl.rs | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/rts/motoko-rts/src/bitset.rs b/rts/motoko-rts/src/bitset.rs index 1f2ea9b84f9..35446438f7e 100644 --- a/rts/motoko-rts/src/bitset.rs +++ b/rts/motoko-rts/src/bitset.rs @@ -45,7 +45,7 @@ pub struct BitRel { impl BitRel { - pub(crate) unsafe fn init(self: &mut Self) { + pub(crate) unsafe fn init(self: & Self) { let bytes = (((*self).end as usize) - ((*self).ptr as usize)) as u32; if (self.n * self.m * 2) > bytes * 8 { idl_trap_with("BitRel not enough bytes"); @@ -57,9 +57,9 @@ impl BitRel { } } - pub(crate) unsafe fn set(self: *mut Self, p: bool, i_j: u32, j_i: u32) { - let n = (*self).n; - let m = (*self).m; + pub(crate) unsafe fn set(self: & Self, p: bool, i_j: u32, j_i: u32) { + let n = self.n; + let m = self.m; let (i, j, base) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; if i >= n { idl_trap_with("BitRel.set i out of bounds"); @@ -70,16 +70,16 @@ impl BitRel { let k = base + i * m + j; let byte = (k / 8) as usize; let bit = (k % 8) as u8; - let dst = (*self).ptr.add(byte); - if dst > (*self).end { + let dst = self.ptr.add(byte); + if dst > self.end { idl_trap_with("BitRel.set out of bounds"); }; *dst = *dst | (1 << bit); } - pub(crate) unsafe fn get(self: *mut Self, p: bool, i_j: u32, j_i: u32) -> bool { - let n = (*self).n; - let m = (*self).m; + pub(crate) unsafe fn get(self: & Self, p: bool, i_j: u32, j_i: u32) -> bool { + let n = self.n; + let m = self.m; let (i, j, base) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; if i >= n { idl_trap_with("BitRel.set i out of bounds"); @@ -90,8 +90,8 @@ impl BitRel { let k = base + i * m + j; let byte = (k / 8) as usize; let bit = (k % 8) as u8; - let src = (*self).ptr.add(byte); - if src > (*self).end { + let src = self.ptr.add(byte); + if src > self.end { idl_trap_with("BitRel.get out of bounds"); }; let mask = 1 << bit; diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 1ce916b1a94..c35af625b18 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -539,7 +539,7 @@ unsafe fn null_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { // https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 // https://github.com/dfinity/candid/blob/20b84d1c1515e2c1db353ebe02b738486f835466/spec/Candid.md unsafe fn sub( - rel : *mut BitRel, + rel : & BitRel, p : bool, buf1: *mut Buf, buf2: *mut Buf, @@ -797,7 +797,7 @@ unsafe extern "C" fn sub_type( let n = table_size(buf1); let m = table_size(buf2); - let mut rel = BitRel { + let rel = BitRel { ptr: (*rel_buf).ptr, end: (*rel_buf).end, n: n, @@ -806,6 +806,6 @@ unsafe extern "C" fn sub_type( rel.init(); - return sub(&mut rel, true, buf1, buf2, typtbl1, typtbl2, t1, t2, 0); + return sub(& rel, true, buf1, buf2, typtbl1, typtbl2, t1, t2, 0); } From c8f9416f6b5bbe9aaef44f7c19a1a82c698681c3 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 3 Mar 2022 17:43:35 +0000 Subject: [PATCH 014/128] clean up --- rts/motoko-rts/src/{bitset.rs => bitrel.rs} | 0 rts/motoko-rts/src/idl.rs | 8 +++++--- rts/motoko-rts/src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) rename rts/motoko-rts/src/{bitset.rs => bitrel.rs} (100%) diff --git a/rts/motoko-rts/src/bitset.rs b/rts/motoko-rts/src/bitrel.rs similarity index 100% rename from rts/motoko-rts/src/bitset.rs rename to rts/motoko-rts/src/bitrel.rs diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index c35af625b18..0f24c677ba0 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -1,5 +1,5 @@ #![allow(non_upper_case_globals)] -use crate::bitset::{BitRel}; +use crate::bitrel::{BitRel}; use crate::buf::{read_byte, read_word, skip_leb128, Buf}; use crate::idl_trap_with; use crate::leb128::{leb128_decode, sleb128_decode}; @@ -788,8 +788,8 @@ unsafe extern "C" fn sub_type( rel_buf : *mut Buf, // a buffer with at least 2 * n * m bits buf1: *mut Buf, buf2: *mut Buf, - typtbl1: *mut *mut u8, - typtbl2: *mut *mut u8, + typtbl1: *mut *mut u8, // size n + typtbl2: *mut *mut u8, // size m t1: i32, t2: i32, ) -> bool { @@ -804,6 +804,8 @@ unsafe extern "C" fn sub_type( m: m, }; + debug_assert!(t1 < (n as i32) && t2 < (m as i32)); + rel.init(); return sub(& rel, true, buf1, buf2, typtbl1, typtbl2, t1, t2, 0); diff --git a/rts/motoko-rts/src/lib.rs b/rts/motoko-rts/src/lib.rs index 4213c69f1d5..d659a695449 100644 --- a/rts/motoko-rts/src/lib.rs +++ b/rts/motoko-rts/src/lib.rs @@ -10,7 +10,7 @@ mod print; pub mod debug; pub mod bigint; -mod bitset; +mod bitrel; #[cfg(feature = "ic")] mod blob_iter; pub mod buf; From 813d2efb2c3fef19de27c1a4843f1505874dbd35 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 3 Mar 2022 17:48:56 +0000 Subject: [PATCH 015/128] formatting --- rts/motoko-rts/src/bitrel.rs | 13 +++++++------ rts/motoko-rts/src/idl.rs | 25 ++++++++++--------------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 35446438f7e..2fdc4137d40 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -1,7 +1,8 @@ -//! This module implements a simple bit set to be used by the compiler (in generated code) +//! This module implements a simple subtype cache used by the compiler (in generated code) use crate::idl_trap_with; +/* TODO: delete me #[repr(packed)] pub struct BitSet { /// Pointer into the bit set @@ -32,20 +33,21 @@ impl BitSet { return *src & mask == mask; } } +*/ #[repr(packed)] pub struct BitRel { /// Pointer into the bit set pub ptr: *mut u8, /// Pointer to the end of the bit set + /// must allow at least 2 * n * m bits pub end: *mut u8, pub n: u32, pub m: u32, } impl BitRel { - - pub(crate) unsafe fn init(self: & Self) { + pub(crate) unsafe fn init(self: &Self) { let bytes = (((*self).end as usize) - ((*self).ptr as usize)) as u32; if (self.n * self.m * 2) > bytes * 8 { idl_trap_with("BitRel not enough bytes"); @@ -57,7 +59,7 @@ impl BitRel { } } - pub(crate) unsafe fn set(self: & Self, p: bool, i_j: u32, j_i: u32) { + pub(crate) unsafe fn set(self: &Self, p: bool, i_j: u32, j_i: u32) { let n = self.n; let m = self.m; let (i, j, base) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; @@ -77,7 +79,7 @@ impl BitRel { *dst = *dst | (1 << bit); } - pub(crate) unsafe fn get(self: & Self, p: bool, i_j: u32, j_i: u32) -> bool { + pub(crate) unsafe fn get(self: &Self, p: bool, i_j: u32, j_i: u32) -> bool { let n = self.n; let m = self.m; let (i, j, base) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; @@ -98,4 +100,3 @@ impl BitRel { return *src & mask == mask; } } - diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 0f24c677ba0..b1ae3ee490a 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -1,5 +1,5 @@ #![allow(non_upper_case_globals)] -use crate::bitrel::{BitRel}; +use crate::bitrel::BitRel; use crate::buf::{read_byte, read_word, skip_leb128, Buf}; use crate::idl_trap_with; use crate::leb128::{leb128_decode, sleb128_decode}; @@ -296,7 +296,7 @@ unsafe fn skip_any_vec(buf: *mut Buf, typtbl: *mut *mut u8, t: i32, count: u32) // Assumes all type references in the typtbl are already checked // // This is currently implemented recursively, but we could -// do this in a loop (by maintaing a stack of the t arguments) +// do this in a loop (by maintaining a stack of the t arguments) #[no_mangle] unsafe extern "C" fn skip_any(buf: *mut Buf, typtbl: *mut *mut u8, t: i32, depth: i32) { if depth > 100 { @@ -539,8 +539,8 @@ unsafe fn null_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { // https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 // https://github.com/dfinity/candid/blob/20b84d1c1515e2c1db353ebe02b738486f835466/spec/Candid.md unsafe fn sub( - rel : & BitRel, - p : bool, + rel: &BitRel, + p: bool, buf1: *mut Buf, buf2: *mut Buf, typtbl1: *mut *mut u8, @@ -587,7 +587,7 @@ unsafe fn sub( let t2 = t2 as u32; if rel.get(p, t1, t2) { // cached: succeed! - return true + return true; }; // cache and continue rel.set(p, t1, t2); @@ -635,7 +635,7 @@ unsafe fn sub( let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); // NB: invert p and args! - if !sub(rel, !p, buf2, buf1, typtbl2, typtbl1, t21, t11, depth + 1) { + if !sub(rel, !p, buf2, buf1, typtbl2, typtbl1, t21, t11, depth + 1) { return false; } } @@ -760,10 +760,7 @@ unsafe fn sub( } } -unsafe fn table_size( - buf: *mut Buf -) -> u32 { - +unsafe fn table_size(buf: *mut Buf) -> u32 { let mut buf = Buf { ptr: (*buf).ptr, end: (*buf).end, @@ -785,7 +782,7 @@ unsafe fn table_size( #[no_mangle] unsafe extern "C" fn sub_type( - rel_buf : *mut Buf, // a buffer with at least 2 * n * m bits + rel_buf: *mut Buf, // a buffer with at least 2 * n * m bits buf1: *mut Buf, buf2: *mut Buf, typtbl1: *mut *mut u8, // size n @@ -793,7 +790,6 @@ unsafe extern "C" fn sub_type( t1: i32, t2: i32, ) -> bool { - let n = table_size(buf1); let m = table_size(buf2); @@ -804,10 +800,9 @@ unsafe extern "C" fn sub_type( m: m, }; - debug_assert!(t1 < (n as i32) && t2 < (m as i32)); + debug_assert!(t1 < (n as i32) && t2 < (m as i32)); rel.init(); - return sub(& rel, true, buf1, buf2, typtbl1, typtbl2, t1, t2, 0); - + return sub(&rel, true, buf1, buf2, typtbl1, typtbl2, t1, t2, 0); } From a7d56417b49891b222619922af2386351b734fe0 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 3 Mar 2022 17:53:26 +0000 Subject: [PATCH 016/128] cleanup --- rts/motoko-rts/src/bitrel.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 2fdc4137d40..5f4032cbdc6 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -48,12 +48,13 @@ pub struct BitRel { impl BitRel { pub(crate) unsafe fn init(self: &Self) { - let bytes = (((*self).end as usize) - ((*self).ptr as usize)) as u32; + let bytes = ((self.end as usize) - (self.ptr as usize)) as u32; if (self.n * self.m * 2) > bytes * 8 { idl_trap_with("BitRel not enough bytes"); }; - let mut ptr = (*self).ptr; - while ptr < (*self).end { + //TODO: use memset + let mut ptr = self.ptr; + while ptr < self.end { *ptr = 0; ptr = ptr.add(1); } From 18ee14e01336f940539811b61c1414f99f164211 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Sat, 5 Mar 2022 15:37:06 +0000 Subject: [PATCH 017/128] wip --- rts/motoko-rts/src/idl.rs | 15 +++++++-- src/codegen/compile.ml | 71 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index b1ae3ee490a..446209bf0e7 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -760,7 +760,10 @@ unsafe fn sub( } } -unsafe fn table_size(buf: *mut Buf) -> u32 { + +// TODO: make non-extern? +#[no_mangle] +unsafe extern "C" fn table_size(buf: *mut Buf) -> u32 { let mut buf = Buf { ptr: (*buf).ptr, end: (*buf).end, @@ -781,7 +784,15 @@ unsafe fn table_size(buf: *mut Buf) -> u32 { } #[no_mangle] -unsafe extern "C" fn sub_type( +unsafe extern "C" fn idl_sub_buf_size(buf1: *mut Buf, buf2: *mut Buf) -> u32 { + let n = table_size(buf1); + let m = table_size(buf2); + return ((2 * n * m) + 31) / 32; +} + + +#[no_mangle] +unsafe extern "C" fn idl_sub( rel_buf: *mut Buf, // a buffer with at least 2 * n * m bits buf1: *mut Buf, buf2: *mut Buf, diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index dd9335e05ab..6e94d726e76 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -765,6 +765,15 @@ module Func = struct (G.i (LocalGet (nr 2l))) (G.i (LocalGet (nr 3l))) ) + let share_code6 env name (p1, p2, p3, p4, p5, p6) retty mk_body = + share_code env name [p1; p2; p3; p4; p5; p6] retty (fun env -> mk_body env + (G.i (LocalGet (nr 0l))) + (G.i (LocalGet (nr 1l))) + (G.i (LocalGet (nr 2l))) + (G.i (LocalGet (nr 3l))) + (G.i (LocalGet (nr 4l))) + (G.i (LocalGet (nr 5l))) + ) let share_code7 env name (p1, p2, p3, p4, p5, p6, p7) retty mk_body = share_code env name [p1; p2; p3; p4; p5; p6; p7] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) @@ -785,6 +794,8 @@ module RTS = struct E.add_func_import env "rts" "memcmp" [I32Type; I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "version" [] [I32Type]; E.add_func_import env "rts" "parse_idl_header" [I32Type; I32Type; I32Type; I32Type; I32Type] []; + E.add_func_import env "rts" "idl_sub_buf_size" [I32Type; I32Type] [I32Type]; + E.add_func_import env "rts" "idl_sub" [I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "leb128_decode" [I32Type] [I32Type]; E.add_func_import env "rts" "sleb128_decode" [I32Type] [I32Type]; E.add_func_import env "rts" "bigint_of_word32" [I32Type] [I32Type]; @@ -1010,6 +1021,7 @@ module Stack = struct let set_stack_ptr env = G.i (GlobalSet (nr (E.get_global env "__stack_pointer"))) + (* TODO: check for overflow *) let alloc_words env n = get_stack_ptr env ^^ compile_unboxed_const (Int32.mul n Heap.word_size) ^^ @@ -1023,12 +1035,39 @@ module Stack = struct G.i (Binary (Wasm.Values.I32 I32Op.Add)) ^^ set_stack_ptr env + (* TODO: why not just remember and reset the stack pointer, instead of calling free_words? Also below *) let with_words env name n f = let (set_x, get_x) = new_local env name in alloc_words env n ^^ set_x ^^ f get_x ^^ free_words env n + (* TODO: check for overflow *) + let dynamic_alloc_words env get_n = + get_stack_ptr env ^^ + get_n ^^ + compile_mul_const Heap.word_size ^^ + G.i (Binary (Wasm.Values.I32 I32Op.Sub)) ^^ + set_stack_ptr env ^^ + get_stack_ptr env + + let dynamic_free_words env get_n = + get_stack_ptr env ^^ + get_n ^^ + compile_mul_const Heap.word_size ^^ + G.i (Binary (Wasm.Values.I32 I32Op.Add)) ^^ + set_stack_ptr env + + (* TODO: why not just remember and reset the stack pointer, instead of calling free_words? Also above*) + let dynamic_with_words env name f = + let (set_n, get_n) = new_local env "n" in + let (set_x, get_x) = new_local env name in + set_n ^^ + dynamic_alloc_words env get_n ^^ set_x ^^ + f get_x ^^ + dynamic_free_words env get_n + + end (* Stack *) @@ -4726,7 +4765,7 @@ module Serialization = struct ] (* The main deserialization function, generated once per type hash. - Is parameters are: + Its parameters are: * data_buffer: The current position of the input data buffer * ref_buffer: The current position of the input references buffer * typtbl: The type table, as returned by parse_idl_header @@ -4738,6 +4777,29 @@ module Serialization = struct It returns the value of type t (vanilla representation) or coercion_error_value, It advances the data_buffer past the decoded value (even if it returns coercion_error_value!) *) + + let idl_sub env = + Func.share_code6 env "idl_sub" + (("get_buf1", I32Type), + ("get_buf2", I32Type), + ("typtbl1", I32Type), + ("typtbl2", I32Type), + ("idltyp1", I32Type), + ("idltyp2", I32Type)) + [I32Type] + (fun env get_buf1 get_buf2 get_typtbl1 get_typtbl2 get_idltyp1 get_idltyp2 -> + get_buf1 ^^ get_buf2 ^^ + E.call_import env "rts" "idl_sub_buf_size" ^^ + Stack.dynamic_with_words env "rel_buf" (fun get_rel_buf_ptr -> + get_rel_buf_ptr ^^ + get_buf1 ^^ + get_buf2 ^^ + get_typtbl1 ^^ + get_typtbl2 ^^ + get_idltyp1 ^^ + get_idltyp2 ^^ + E.call_import env "rts" "idl_sub")) + let rec deserialize_go env t = let open Type in let t = Type.normalize t in @@ -5310,6 +5372,9 @@ module Serialization = struct ( coercion_failed "IDL error: unexpected variant tag" ) ) | Func _ -> + get_data_buf ^^ get_data_buf ^^ get_typtbl ^^ get_typtbl ^^ get_idltyp ^^ get_idltyp ^^ + idl_sub env ^^ + E.else_trap_with env "idl_sub_irreflexive:func" ^^ with_composite_typ idl_func (fun _get_typ_buf -> read_byte_tagged [ E.trap_with env "IDL error: unexpected function reference" @@ -5319,6 +5384,9 @@ module Serialization = struct ] ); | Obj (Actor, _) -> + get_data_buf ^^ get_data_buf ^^ get_typtbl ^^ get_typtbl ^^ get_idltyp ^^ get_idltyp ^^ + idl_sub env ^^ + E.else_trap_with env "idl_sub_irreflexive:actor" ^^ with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data ()) | Mut t -> read_alias env (Mut t) (fun get_arg_typ on_alloc -> @@ -5397,6 +5465,7 @@ module Serialization = struct get_data_size ) + let deserialize_from_blob extended env ts = let ts_name = typ_seq_hash ts in let name = From d79c6bfdb28d9950a900c92f6c6c8f92d0dd5ced Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Sat, 5 Mar 2022 17:28:39 +0000 Subject: [PATCH 018/128] basic plumbing with reflexivity checks; fixed empty < _ case; added missing now always true service < service case --- rts/motoko-rts/src/idl.rs | 94 ++++++++++++++++++++------------------- src/codegen/compile.ml | 48 ++++++++++++++------ 2 files changed, 84 insertions(+), 58 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 446209bf0e7..f9c0015b0ce 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -492,6 +492,7 @@ unsafe extern "C" fn skip_fields(tb: *mut Buf, buf: *mut Buf, typtbl: *mut *mut } } +// TODO: delete me unsafe fn unfold(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> i32 { let mut tb = Buf { ptr: *typtbl.add(t as usize), @@ -500,7 +501,7 @@ unsafe fn unfold(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> i32 { return sleb128_decode(&mut tb); } -unsafe fn opt_empty_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { +unsafe fn opt_empty_sub(end: *mut u8, typtbl: *mut *mut u8, t: i32) -> bool { if is_primitive_type(t) { return t == IDL_PRIM_reserved; } @@ -510,7 +511,7 @@ unsafe fn opt_empty_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { let mut tb = Buf { ptr: *typtbl.add(t as usize), - end: (*buf).end, + end: end, }; t = sleb128_decode(&mut tb); @@ -518,6 +519,7 @@ unsafe fn opt_empty_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { return t == IDL_CON_opt; } +// TODO: delete me unsafe fn null_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { if is_primitive_type(t) { return t == IDL_PRIM_empty || t == IDL_PRIM_null; @@ -541,8 +543,8 @@ unsafe fn null_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { unsafe fn sub( rel: &BitRel, p: bool, - buf1: *mut Buf, - buf2: *mut Buf, + end1: *mut u8, + end2: *mut u8, typtbl1: *mut *mut u8, typtbl2: *mut *mut u8, t1: i32, @@ -565,7 +567,7 @@ unsafe fn sub( // unfold t1, if necessary let mut tb1 = Buf { ptr: *typtbl1.add(if t1 < 0 { 0 } else { t1 as usize }), // better dummy? - end: (*buf1).end, + end: end1, }; if t1 >= 0 { @@ -575,7 +577,7 @@ unsafe fn sub( // unfold t2, if necessary let mut tb2 = Buf { ptr: *typtbl2.add(if t2 < 0 { 0 } else { t2 as usize }), // better dummy? - end: (*buf2).end, + end: end2, }; if t2 >= 0 { @@ -597,7 +599,7 @@ unsafe fn sub( match (t1, t2) { (_, IDL_PRIM_reserved) => true, - (IDL_PRIM_empty, _) => false, + (IDL_PRIM_empty, _) => true, /* (IDL_PRIM_null, IDL_CON_opt) => true, (IDL_CON_opt, IDL_CON_opt) => { @@ -622,7 +624,7 @@ unsafe fn sub( (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); - return sub(rel, p, buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); + return sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1); } (IDL_CON_func, IDL_CON_func) => { // contra in domain @@ -635,7 +637,7 @@ unsafe fn sub( let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); // NB: invert p and args! - if !sub(rel, !p, buf2, buf1, typtbl2, typtbl1, t21, t11, depth + 1) { + if !sub(rel, !p, end2, end1, typtbl2, typtbl1, t21, t11, depth + 1) { return false; } } @@ -651,7 +653,7 @@ unsafe fn sub( for _ in 0..out2 { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); - if !sub(rel, p, buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { return false; } } @@ -664,8 +666,8 @@ unsafe fn sub( // c.f. https://github.com/dfinity/candid/issues/318 let mut a11 = false; let mut a12 = false; - for _ in 0..leb128_decode(buf1) { - let a = read_byte(buf1); + for _ in 0..leb128_decode(&mut tb1) { + let a = read_byte(&mut tb1); if a == 1 { a11 = true; }; @@ -675,8 +677,8 @@ unsafe fn sub( } let mut a21 = false; let mut a22 = false; - for _ in 0..leb128_decode(buf2) { - let a = read_byte(buf2); + for _ in 0..leb128_decode(&mut tb2) { + let a = read_byte(&mut tb2); if a == 1 { a21 = true; }; @@ -687,25 +689,25 @@ unsafe fn sub( return (a11 == a21) && (a12 == a22); } (IDL_CON_record, IDL_CON_record) => { - let mut n1 = leb128_decode(buf1); - let n2 = leb128_decode(buf2); + let mut n1 = leb128_decode(&mut tb1); + let n2 = leb128_decode(&mut tb2); let mut tag1 = 0; let mut t11 = 0; let mut advance = true; for _ in 0..n2 { - let tag2 = leb128_decode(buf2); - let t21 = sleb128_decode(buf2); + let tag2 = leb128_decode(&mut tb2); + let t21 = sleb128_decode(&mut tb2); if n1 == 0 { // check all remaining fields optional - if !opt_empty_sub(buf2, typtbl2, t21) { + if !opt_empty_sub(end2, typtbl2, t21) { return false; } continue; }; if advance { loop { - tag1 = leb128_decode(buf1); - t11 = sleb128_decode(buf1); + tag1 = leb128_decode(&mut tb1); + t11 = sleb128_decode(&mut tb1); n1 -= 1; if !(tag1 < tag2 && n1 > 0) { break; @@ -713,14 +715,14 @@ unsafe fn sub( } }; if tag1 > tag2 { - if !opt_empty_sub(buf2, typtbl2, t21) { + if !opt_empty_sub(end2, typtbl2, t21) { // missing, non_opt field return false; } advance = false; // reconsider this field in next round continue; }; - if !sub(rel, p, buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { return false; } advance = true; @@ -728,19 +730,19 @@ unsafe fn sub( return true; } (IDL_CON_variant, IDL_CON_variant) => { - let n1 = leb128_decode(buf1); - let mut n2 = leb128_decode(buf2); + let n1 = leb128_decode(&mut tb1); + let mut n2 = leb128_decode(&mut tb2); for _ in 0..n1 { if n2 == 0 { return false; }; - let tag1 = leb128_decode(buf1); - let t11 = sleb128_decode(buf1); + let tag1 = leb128_decode(&mut tb1); + let t11 = sleb128_decode(&mut tb1); let mut tag2 = 0; let mut t21 = 0; loop { - tag2 = leb128_decode(buf2); - t21 = sleb128_decode(buf2); + tag2 = leb128_decode(&mut tb2); + t21 = sleb128_decode(&mut tb2); n2 -= 1; if !(tag2 < tag1 && n2 > 0) { break; @@ -749,19 +751,23 @@ unsafe fn sub( if tag1 != tag2 { return false; }; - if !sub(rel, p, buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { return false; } } return true; } + (IDL_CON_service, IDL_CON_service) => { + // TODO: complete me + return true; + }, // default (_, _) => false, } } -// TODO: make non-extern? +// TODO: DELETE #[no_mangle] unsafe extern "C" fn table_size(buf: *mut Buf) -> u32 { let mut buf = Buf { @@ -784,36 +790,34 @@ unsafe extern "C" fn table_size(buf: *mut Buf) -> u32 { } #[no_mangle] -unsafe extern "C" fn idl_sub_buf_size(buf1: *mut Buf, buf2: *mut Buf) -> u32 { - let n = table_size(buf1); - let m = table_size(buf2); - return ((2 * n * m) + 31) / 32; +unsafe extern "C" fn idl_sub_buf_size(n_types1: u32, n_types2: u32) -> u32 { + return ((2 * n_types1 * n_types2) + 31) / 32; } #[no_mangle] unsafe extern "C" fn idl_sub( rel_buf: *mut Buf, // a buffer with at least 2 * n * m bits - buf1: *mut Buf, - buf2: *mut Buf, - typtbl1: *mut *mut u8, // size n - typtbl2: *mut *mut u8, // size m + end1: *mut u8, + end2: *mut u8, + n_types1: u32, + n_types2: u32, + typtbl1: *mut *mut u8, // of len n_types1 + typtbl2: *mut *mut u8, // of len n_types2 t1: i32, t2: i32, ) -> bool { - let n = table_size(buf1); - let m = table_size(buf2); let rel = BitRel { ptr: (*rel_buf).ptr, end: (*rel_buf).end, - n: n, - m: m, + n: n_types1, + m: n_types2, }; - debug_assert!(t1 < (n as i32) && t2 < (m as i32)); + debug_assert!(t1 < (n_types1 as i32) && t2 < (n_types2 as i32)); rel.init(); - return sub(&rel, true, buf1, buf2, typtbl1, typtbl2, t1, t2, 0); + return sub(&rel, true, end1, end2, typtbl1, typtbl2, t1, t2, 0); } diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 6e94d726e76..fd759757338 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -765,7 +765,7 @@ module Func = struct (G.i (LocalGet (nr 2l))) (G.i (LocalGet (nr 3l))) ) - let share_code6 env name (p1, p2, p3, p4, p5, p6) retty mk_body = + let _share_code6 env name (p1, p2, p3, p4, p5, p6) retty mk_body = share_code env name [p1; p2; p3; p4; p5; p6] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) (G.i (LocalGet (nr 1l))) @@ -784,6 +784,17 @@ module Func = struct (G.i (LocalGet (nr 5l))) (G.i (LocalGet (nr 6l))) ) + let share_code8 env name (p1, p2, p3, p4, p5, p6, p7, p8) retty mk_body = + share_code env name [p1; p2; p3; p4; p5; p6; p7; p8] retty (fun env -> mk_body env + (G.i (LocalGet (nr 0l))) + (G.i (LocalGet (nr 1l))) + (G.i (LocalGet (nr 2l))) + (G.i (LocalGet (nr 3l))) + (G.i (LocalGet (nr 4l))) + (G.i (LocalGet (nr 5l))) + (G.i (LocalGet (nr 6l))) + (G.i (LocalGet (nr 7l))) + ) end (* Func *) @@ -795,7 +806,8 @@ module RTS = struct E.add_func_import env "rts" "version" [] [I32Type]; E.add_func_import env "rts" "parse_idl_header" [I32Type; I32Type; I32Type; I32Type; I32Type] []; E.add_func_import env "rts" "idl_sub_buf_size" [I32Type; I32Type] [I32Type]; - E.add_func_import env "rts" "idl_sub" [I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type] [I32Type]; + E.add_func_import env "rts" "idl_sub" + [I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "leb128_decode" [I32Type] [I32Type]; E.add_func_import env "rts" "sleb128_decode" [I32Type] [I32Type]; E.add_func_import env "rts" "bigint_of_word32" [I32Type] [I32Type]; @@ -4779,21 +4791,25 @@ module Serialization = struct *) let idl_sub env = - Func.share_code6 env "idl_sub" - (("get_buf1", I32Type), - ("get_buf2", I32Type), + Func.share_code8 env "idl_sub" + (("get_end1", I32Type), + ("get_end2", I32Type), + ("n_types1", I32Type), + ("n_types2", I32Type), ("typtbl1", I32Type), ("typtbl2", I32Type), ("idltyp1", I32Type), ("idltyp2", I32Type)) [I32Type] - (fun env get_buf1 get_buf2 get_typtbl1 get_typtbl2 get_idltyp1 get_idltyp2 -> - get_buf1 ^^ get_buf2 ^^ + (fun env get_end1 get_end2 get_n_types1 get_n_types2 get_typtbl1 get_typtbl2 get_idltyp1 get_idltyp2 -> + get_n_types1 ^^ get_n_types2 ^^ E.call_import env "rts" "idl_sub_buf_size" ^^ Stack.dynamic_with_words env "rel_buf" (fun get_rel_buf_ptr -> get_rel_buf_ptr ^^ - get_buf1 ^^ - get_buf2 ^^ + get_end1 ^^ + get_end2 ^^ + get_n_types1 ^^ + get_n_types2 ^^ get_typtbl1 ^^ get_typtbl2 ^^ get_idltyp1 ^^ @@ -5372,8 +5388,11 @@ module Serialization = struct ( coercion_failed "IDL error: unexpected variant tag" ) ) | Func _ -> - get_data_buf ^^ get_data_buf ^^ get_typtbl ^^ get_typtbl ^^ get_idltyp ^^ get_idltyp ^^ - idl_sub env ^^ + compile_unboxed_const 0xFFFF_FFFFl ^^ compile_unboxed_const 0xFFFF_FFFFl ^^ (* FIX ME *) + get_typtbl_size ^^ get_typtbl_size ^^ + get_typtbl ^^ get_typtbl ^^ + get_idltyp ^^ get_idltyp ^^ + idl_sub env ^^ E.else_trap_with env "idl_sub_irreflexive:func" ^^ with_composite_typ idl_func (fun _get_typ_buf -> read_byte_tagged @@ -5384,8 +5403,11 @@ module Serialization = struct ] ); | Obj (Actor, _) -> - get_data_buf ^^ get_data_buf ^^ get_typtbl ^^ get_typtbl ^^ get_idltyp ^^ get_idltyp ^^ - idl_sub env ^^ + compile_unboxed_const 0xFFFF_FFFFl ^^ compile_unboxed_const 0xFFFF_FFFFl ^^ (* FIX ME *) + get_typtbl_size ^^ get_typtbl_size ^^ + get_typtbl ^^ get_typtbl ^^ + get_idltyp ^^ get_idltyp ^^ + idl_sub env ^^ E.else_trap_with env "idl_sub_irreflexive:actor" ^^ with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data ()) | Mut t -> From 6cd8d9ff577a0a778c16518f4c2bad6a41a342bb Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Sun, 6 Mar 2022 00:25:11 +0000 Subject: [PATCH 019/128] fix 'base' bug in bitrel.rs; implement service subtyping; still broken --- rts/motoko-rts/src/bitrel.rs | 4 ++-- rts/motoko-rts/src/idl.rs | 38 +++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 5f4032cbdc6..7ee58b62ce4 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -63,7 +63,7 @@ impl BitRel { pub(crate) unsafe fn set(self: &Self, p: bool, i_j: u32, j_i: u32) { let n = self.n; let m = self.m; - let (i, j, base) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; + let (base, i, j) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; if i >= n { idl_trap_with("BitRel.set i out of bounds"); }; @@ -83,7 +83,7 @@ impl BitRel { pub(crate) unsafe fn get(self: &Self, p: bool, i_j: u32, j_i: u32) -> bool { let n = self.n; let m = self.m; - let (i, j, base) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; + let (base, i, j) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; if i >= n { idl_trap_with("BitRel.set i out of bounds"); }; diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index f9c0015b0ce..bf4aa0a670e 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -758,7 +758,43 @@ unsafe fn sub( return true; } (IDL_CON_service, IDL_CON_service) => { - // TODO: complete me +// return true; // TODO: Delete ME + let mut n1 = leb128_decode(&mut tb1); + let n2 = leb128_decode(&mut tb2); + for _ in 0..n2 { + if n1 == 0 { + return false; + }; + let len2 = leb128_decode(&mut tb2); + let p2 = tb2.ptr; + Buf::advance(&mut tb2, len2); + let t21 = sleb128_decode(&mut tb2); + let mut len1 = 0; + let mut p1 = core::ptr::null_mut(); + let mut t11 = 0; + let mut cmp : i32 = 0; + loop { + len1 = leb128_decode(&mut tb1); + p1 = tb1.ptr; + Buf::advance(&mut tb1, len1); + t11 = sleb128_decode(&mut tb1); + n1 -= 1; + cmp = libc::memcmp( + p1 as *mut libc::c_void, + p2 as *mut libc::c_void, + min(len1, len2) as usize + ); + if !(cmp < 0 && n1 > 0) { + break; + } + } + if !(cmp == 0 && len1 == len2) { + return false; + }; + if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { + return false; + } + } return true; }, // default From 392fa80c690c869dc6dc6bfb42a9f93f45b72454 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 9 Mar 2022 15:07:16 +0000 Subject: [PATCH 020/128] test idl_sub --- test/run-drun/idl-sub.mo | 156 +++++++++++++++++++++++++ test/run-drun/ok/idl-sub.drun-run.ok | 17 +++ test/run-drun/ok/idl-sub.ic-ref-run.ok | 20 ++++ 3 files changed, 193 insertions(+) create mode 100644 test/run-drun/idl-sub.mo create mode 100644 test/run-drun/ok/idl-sub.drun-run.ok create mode 100644 test/run-drun/ok/idl-sub.ic-ref-run.ok diff --git a/test/run-drun/idl-sub.mo b/test/run-drun/idl-sub.mo new file mode 100644 index 00000000000..d3d70dbe45d --- /dev/null +++ b/test/run-drun/idl-sub.mo @@ -0,0 +1,156 @@ +import Prim "mo:⛔"; + +actor this { + + public func f0() : async () {}; + + public func send_f0( + f : shared () -> async () + ) : async () { + Prim.debugPrint("ok 0"); + }; + + public func f1(n:Nat) : async () {}; + + public func send_f1( + f1 : shared (n:Nat) -> async () + ) : async () { + Prim.debugPrint("ok 1"); + }; + + public func f2(n:Nat) : async Nat { 0 }; + + public func send_f2( + f2 : shared (n:Nat) -> async Nat + ) : async () { + Prim.debugPrint("ok 2"); + }; + + + // variants + public func f3(n:{#f:Nat}) : async {#f:Nat} { (#f 0) }; + + public func send_f3( + f3 : shared (n:{#f:Nat}) -> async {#f:Nat} + ) : async () { + Prim.debugPrint("ok 3"); + }; + + + // records + public func f4(n:{f:Nat}) : async {f:Nat} { { f = 0 } }; + + public func send_f4( + f4 : shared (n: {f : Nat}) -> async {f : Nat} + ) : async () { + Prim.debugPrint("ok 4"); + }; + + + // option + public func f5(n : ?Nat) : async ?Nat { null }; + + public func send_f5( + f5 : shared (n : ?Nat) -> async ?Nat + ) : async () { + Prim.debugPrint("ok 5"); + }; + + // actor + public func f6(n : actor {}) : async (actor {}) { n }; + + public func send_f6( + f6 : shared (n : actor {}) -> async (actor {}) + ) : async () { + Prim.debugPrint("ok 6"); + }; + + public func f7(n : Nat, b : Bool) : async (Nat,Bool) {(n,b)}; + + public func send_f7( + f7 : shared (Nat, Bool) -> async (Nat, Bool) + ) : async () { + Prim.debugPrint("ok 7"); + }; + + + // record with 2 fields + public func f8({n : Nat; b : Bool}) : async {n : Nat; b : Bool} {{ n; b}}; + + public func send_f8( + f8 : shared {n : Nat; b : Bool} -> async {n : Nat; b : Bool} + ) : async () { + Prim.debugPrint("ok 8"); + }; + + // arrays + public func f9(n:[Nat]) : async [Nat] { n }; + + public func send_f9( + f9 : shared (n:[Nat]) -> async [Nat] + ) : async () { + Prim.debugPrint("ok 9"); + }; + + // blob + public func f10(n:Blob) : async Blob { n }; + + public func send_f10( + f10 : shared (n:Blob) -> async Blob + ) : async () { + Prim.debugPrint("ok 10"); + }; + + + // record with opt field + public func f11({n : Nat; o : ?Bool}) : async {n : Nat; o : ?Bool} {{ n; o}}; + + public func send_f11( + f11 : shared {n : Nat; o : ?Bool} -> async {n : Nat; o : ?Bool} + ) : async () { + Prim.debugPrint("ok 11"); + }; + + // record with opt field record + public func f12({n : Nat; o : ?{b:Bool}}) : async {n : Nat; o : ?{b:Bool}} {{ n; o}}; + + public func send_f12( + f12 : shared {n : Nat; o : ?{b:Bool}} -> async {n : Nat; o : ?{b:Bool}} + ) : async () { + Prim.debugPrint("ok 12"); + }; + + // Principals + public func f13(n:Principal) : async Principal { n }; + + public func send_f13( + f13 : shared (n:Principal) -> async Principal + ) : async () { + Prim.debugPrint("ok 13"); + }; + + + + public func go() : async () { + await this.send_f0(f0); + await this.send_f1(f1); + await this.send_f2(f2); + await this.send_f3(f3); + await this.send_f4(f4); + await this.send_f5(f5); + await this.send_f6(f6); + await this.send_f7(f7); + await this.send_f8(f8); + await this.send_f9(f9); + await this.send_f10(f10); + await this.send_f11(f11); + await this.send_f12(f12); + await this.send_f13(f13); + }; + + +} +//SKIP run +//SKIP run-ir +//SKIP run-low +//CALL ingress go "DIDL\x00\x00" \ No newline at end of file diff --git a/test/run-drun/ok/idl-sub.drun-run.ok b/test/run-drun/ok/idl-sub.drun-run.ok new file mode 100644 index 00000000000..c86d0398cb4 --- /dev/null +++ b/test/run-drun/ok/idl-sub.drun-run.ok @@ -0,0 +1,17 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: ok 0 +debug.print: ok 1 +debug.print: ok 2 +debug.print: ok 3 +debug.print: ok 4 +debug.print: ok 5 +debug.print: ok 6 +debug.print: ok 7 +debug.print: ok 8 +debug.print: ok 9 +debug.print: ok 10 +debug.print: ok 11 +debug.print: ok 12 +debug.print: ok 13 +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub.ic-ref-run.ok b/test/run-drun/ok/idl-sub.ic-ref-run.ok new file mode 100644 index 00000000000..a6a76dd981c --- /dev/null +++ b/test/run-drun/ok/idl-sub.ic-ref-run.ok @@ -0,0 +1,20 @@ +→ update create_canister(record {settings = null}) +← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… +← replied: () +→ update go() +debug.print: ok 0 +debug.print: ok 1 +debug.print: ok 2 +debug.print: ok 3 +debug.print: ok 4 +debug.print: ok 5 +debug.print: ok 6 +debug.print: ok 7 +debug.print: ok 8 +debug.print: ok 9 +debug.print: ok 10 +debug.print: ok 11 +debug.print: ok 12 +debug.print: ok 13 +← replied: () From 7e22e8d44ca08c6f745c71dc055ddde3d225d32f Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 10 Mar 2022 22:53:14 +0000 Subject: [PATCH 021/128] fixed subtle stack corruption in rel_buf setup; first reasonable tests --- rts/motoko-rts/src/idl.rs | 52 ++++++++++++++++---------- src/codegen/compile.ml | 14 +++---- test/run-drun/idl-sub.mo | 27 +++++++++++++ test/run-drun/ok/idl-sub.drun-run.ok | 2 + test/run-drun/ok/idl-sub.ic-ref-run.ok | 2 + 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index bf4aa0a670e..3cb8dda5ab4 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -50,6 +50,27 @@ unsafe fn is_primitive_type(ty: i32) -> bool { ty < 0 && (ty >= IDL_PRIM_lowest || ty == IDL_REF_principal) } +// TBR; based on Text.text_compare +unsafe fn utf8_cmp(len1: u32, p1: *mut u8, len2: u32, p2: *mut u8) -> i32 { + let len = min(len1, len2); + let cmp = libc::memcmp( + p1 as *mut libc::c_void, + p2 as *mut libc::c_void, + len as usize, + ); + if cmp == -1 { + return -1; + } else if cmp == 1 { + return 1; + } else if len1 > len { + return 1; + } else if len2 > len { + return -1; + } else { + return 0; + } +} + unsafe fn check_typearg(ty: i32, n_types: u32) { // Arguments to type constructors can be primitive types or type indices if !(is_primitive_type(ty) || (ty >= 0 && (ty as u32) < n_types)) { @@ -758,7 +779,6 @@ unsafe fn sub( return true; } (IDL_CON_service, IDL_CON_service) => { -// return true; // TODO: Delete ME let mut n1 = leb128_decode(&mut tb1); let n2 = leb128_decode(&mut tb2); for _ in 0..n2 { @@ -772,23 +792,20 @@ unsafe fn sub( let mut len1 = 0; let mut p1 = core::ptr::null_mut(); let mut t11 = 0; - let mut cmp : i32 = 0; + let mut cmp: i32 = 0; loop { len1 = leb128_decode(&mut tb1); p1 = tb1.ptr; Buf::advance(&mut tb1, len1); t11 = sleb128_decode(&mut tb1); n1 -= 1; - cmp = libc::memcmp( - p1 as *mut libc::c_void, - p2 as *mut libc::c_void, - min(len1, len2) as usize - ); - if !(cmp < 0 && n1 > 0) { - break; - } + cmp = utf8_cmp(len1, p1, len2, p2); + if cmp < 0 && n1 > 0 { + continue; + }; + break; } - if !(cmp == 0 && len1 == len2) { + if !(cmp == 0) { return false; }; if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { @@ -796,13 +813,12 @@ unsafe fn sub( } } return true; - }, + } // default (_, _) => false, } } - // TODO: DELETE #[no_mangle] unsafe extern "C" fn table_size(buf: *mut Buf) -> u32 { @@ -826,14 +842,13 @@ unsafe extern "C" fn table_size(buf: *mut Buf) -> u32 { } #[no_mangle] -unsafe extern "C" fn idl_sub_buf_size(n_types1: u32, n_types2: u32) -> u32 { +unsafe extern "C" fn idl_sub_buf_words(n_types1: u32, n_types2: u32) -> u32 { return ((2 * n_types1 * n_types2) + 31) / 32; } - #[no_mangle] unsafe extern "C" fn idl_sub( - rel_buf: *mut Buf, // a buffer with at least 2 * n * m bits + rel_buf: *mut u8, // a buffer with at least 2 * n * m bits end1: *mut u8, end2: *mut u8, n_types1: u32, @@ -843,10 +858,9 @@ unsafe extern "C" fn idl_sub( t1: i32, t2: i32, ) -> bool { - let rel = BitRel { - ptr: (*rel_buf).ptr, - end: (*rel_buf).end, + ptr: rel_buf, + end: rel_buf.add((idl_sub_buf_words(n_types1, n_types2) * 4) as usize), n: n_types1, m: n_types2, }; diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index fd759757338..c9c3c046d24 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -805,7 +805,7 @@ module RTS = struct E.add_func_import env "rts" "memcmp" [I32Type; I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "version" [] [I32Type]; E.add_func_import env "rts" "parse_idl_header" [I32Type; I32Type; I32Type; I32Type; I32Type] []; - E.add_func_import env "rts" "idl_sub_buf_size" [I32Type; I32Type] [I32Type]; + E.add_func_import env "rts" "idl_sub_buf_words" [I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "idl_sub" [I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "leb128_decode" [I32Type] [I32Type]; @@ -4803,7 +4803,7 @@ module Serialization = struct [I32Type] (fun env get_end1 get_end2 get_n_types1 get_n_types2 get_typtbl1 get_typtbl2 get_idltyp1 get_idltyp2 -> get_n_types1 ^^ get_n_types2 ^^ - E.call_import env "rts" "idl_sub_buf_size" ^^ + E.call_import env "rts" "idl_sub_buf_words" ^^ Stack.dynamic_with_words env "rel_buf" (fun get_rel_buf_ptr -> get_rel_buf_ptr ^^ get_end1 ^^ @@ -4968,9 +4968,9 @@ module Serialization = struct get_ptr ^^ get_len ^^ Text.of_ptr_size env in - let read_actor_data () = + let read_actor_data t = read_byte_tagged - [ E.trap_with env "IDL error: unexpected actor reference" + [ E.trap_with env ("IDL error: unexpected actor reference" ^ Type.string_of_typ t) ; read_principal () ] in @@ -5396,8 +5396,8 @@ module Serialization = struct E.else_trap_with env "idl_sub_irreflexive:func" ^^ with_composite_typ idl_func (fun _get_typ_buf -> read_byte_tagged - [ E.trap_with env "IDL error: unexpected function reference" - ; read_actor_data () ^^ + [ E.trap_with env ("IDL error: unexpected function reference" ^ Type.string_of_typ t) + ; read_actor_data t ^^ read_text () ^^ Tuple.from_stack env 2 ] @@ -5409,7 +5409,7 @@ module Serialization = struct get_idltyp ^^ get_idltyp ^^ idl_sub env ^^ E.else_trap_with env "idl_sub_irreflexive:actor" ^^ - with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data ()) + with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data t) | Mut t -> read_alias env (Mut t) (fun get_arg_typ on_alloc -> let (set_result, get_result) = new_local env "result" in diff --git a/test/run-drun/idl-sub.mo b/test/run-drun/idl-sub.mo index d3d70dbe45d..7b3e5b26551 100644 --- a/test/run-drun/idl-sub.mo +++ b/test/run-drun/idl-sub.mo @@ -129,6 +129,30 @@ actor this { Prim.debugPrint("ok 13"); }; + type Actor = actor { + f : () -> async (); + p : () -> (); + q : shared query () -> async (); + // r : shared () -> async (); + }; + + // non-triv actor + public func f14(n : Actor) : async Actor { n }; + + public func send_f14( + f14 : shared (n : Actor) -> async Actor + ) : async () { + Prim.debugPrint("ok 14"); + }; + + // non-triv actor + public query func f15() : async () { }; + + public func send_f15( + f15 : query () -> async () + ) : async () { + Prim.debugPrint("ok 15"); + }; public func go() : async () { @@ -146,6 +170,9 @@ actor this { await this.send_f11(f11); await this.send_f12(f12); await this.send_f13(f13); + await this.send_f14(f14); + await this.send_f15(f15); + }; diff --git a/test/run-drun/ok/idl-sub.drun-run.ok b/test/run-drun/ok/idl-sub.drun-run.ok index c86d0398cb4..c5094c146e0 100644 --- a/test/run-drun/ok/idl-sub.drun-run.ok +++ b/test/run-drun/ok/idl-sub.drun-run.ok @@ -14,4 +14,6 @@ debug.print: ok 10 debug.print: ok 11 debug.print: ok 12 debug.print: ok 13 +debug.print: ok 14 +debug.print: ok 15 ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub.ic-ref-run.ok b/test/run-drun/ok/idl-sub.ic-ref-run.ok index a6a76dd981c..c903959dc6c 100644 --- a/test/run-drun/ok/idl-sub.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub.ic-ref-run.ok @@ -17,4 +17,6 @@ debug.print: ok 10 debug.print: ok 11 debug.print: ok 12 debug.print: ok 13 +debug.print: ok 14 +debug.print: ok 15 ← replied: () From bcd5a02314d624ea734ded52591a48ee3d063174 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 10 Mar 2022 23:45:18 +0000 Subject: [PATCH 022/128] check cache on entry --- rts/motoko-rts/src/idl.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 3cb8dda5ab4..35eb3cb6ddd 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -572,10 +572,21 @@ unsafe fn sub( t2: i32, depth: i32, ) -> bool { - if depth > 100 { + if depth > 1023 { idl_trap_with("sub: subtyping too deep"); } + if t1 >= 0 && t2 >= 0 { + let t1 = t1 as u32; + let t2 = t2 as u32; + if rel.get(p, t1, t2) { + // cached: succeed! + return true; + }; + // cache and continue + rel.set(p, t1, t2); + }; + // re-declare as mut for any unfolding let mut t1 = t1; let mut t2 = t2; @@ -605,17 +616,6 @@ unsafe fn sub( t2 = sleb128_decode(&mut tb2); }; - if t1 >= 0 && t2 >= 0 { - let t1 = t1 as u32; - let t2 = t2 as u32; - if rel.get(p, t1, t2) { - // cached: succeed! - return true; - }; - // cache and continue - rel.set(p, t1, t2); - }; - debug_assert!(t1 < 0 && t2 < 0); match (t1, t2) { From 8e3de33c95b26abeec9f31c76a4b49fefaeed023 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 11 Mar 2022 14:56:22 +0000 Subject: [PATCH 023/128] clean up annotation subtyping --- rts/motoko-rts/src/idl.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 35eb3cb6ddd..ad7d2ba0a48 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -688,24 +688,20 @@ unsafe fn sub( let mut a11 = false; let mut a12 = false; for _ in 0..leb128_decode(&mut tb1) { - let a = read_byte(&mut tb1); - if a == 1 { - a11 = true; - }; - if a == 2 { - a12 = true; - }; + match read_byte(&mut tb1) { + 1 => { a11 = true }, + 2 => { a12 = true }, + _ => { }, + } } let mut a21 = false; let mut a22 = false; for _ in 0..leb128_decode(&mut tb2) { - let a = read_byte(&mut tb2); - if a == 1 { - a21 = true; - }; - if a == 2 { - a22 = true; - }; + match read_byte(&mut tb2) { + 1 => { a21 = true }, + 2 => { a22 = true }, + _ => { }, + } } return (a11 == a21) && (a12 == a22); } From e42e25a2e601548251756f84b5c31b67d06a464e Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 11 Mar 2022 15:46:28 +0000 Subject: [PATCH 024/128] make BitRel word, not byte based; cleanup --- rts/motoko-rts/src/bitrel.rs | 30 ++++++++++++++++-------------- rts/motoko-rts/src/idl.rs | 18 +++++++++--------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 7ee58b62ce4..1447f914db1 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -1,6 +1,9 @@ //! This module implements a simple subtype cache used by the compiler (in generated code) +use crate::constants::WORD_SIZE; use crate::idl_trap_with; +use crate::mem_utils::memzero; +use crate::types::Words; /* TODO: delete me #[repr(packed)] @@ -38,26 +41,25 @@ impl BitSet { #[repr(packed)] pub struct BitRel { /// Pointer into the bit set - pub ptr: *mut u8, + pub ptr: *mut u32, /// Pointer to the end of the bit set /// must allow at least 2 * n * m bits - pub end: *mut u8, + pub end: *mut u32, pub n: u32, pub m: u32, } impl BitRel { + pub(crate) unsafe fn words(n_types1: u32, n_types2: u32) -> u32 { + return ((2 * n_types1 * n_types2) + (usize::BITS - 1)) / usize::BITS; + } + pub(crate) unsafe fn init(self: &Self) { let bytes = ((self.end as usize) - (self.ptr as usize)) as u32; if (self.n * self.m * 2) > bytes * 8 { idl_trap_with("BitRel not enough bytes"); }; - //TODO: use memset - let mut ptr = self.ptr; - while ptr < self.end { - *ptr = 0; - ptr = ptr.add(1); - } + memzero(self.ptr as usize, Words(bytes / WORD_SIZE)); } pub(crate) unsafe fn set(self: &Self, p: bool, i_j: u32, j_i: u32) { @@ -71,9 +73,9 @@ impl BitRel { idl_trap_with("BitRel.set j out of bounds"); }; let k = base + i * m + j; - let byte = (k / 8) as usize; - let bit = (k % 8) as u8; - let dst = self.ptr.add(byte); + let word = (k / usize::BITS) as usize; + let bit = (k % usize::BITS) as u32; + let dst = self.ptr.add(word); if dst > self.end { idl_trap_with("BitRel.set out of bounds"); }; @@ -91,9 +93,9 @@ impl BitRel { idl_trap_with("BitRel.set j out of bounds"); }; let k = base + i * m + j; - let byte = (k / 8) as usize; - let bit = (k % 8) as u8; - let src = self.ptr.add(byte); + let word = (k / usize::BITS) as usize; + let bit = (k % usize::BITS) as u32; + let src = self.ptr.add(word); if src > self.end { idl_trap_with("BitRel.get out of bounds"); }; diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index ad7d2ba0a48..8d15064c0f4 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -689,18 +689,18 @@ unsafe fn sub( let mut a12 = false; for _ in 0..leb128_decode(&mut tb1) { match read_byte(&mut tb1) { - 1 => { a11 = true }, - 2 => { a12 = true }, - _ => { }, + 1 => a11 = true, + 2 => a12 = true, + _ => {} } } let mut a21 = false; let mut a22 = false; for _ in 0..leb128_decode(&mut tb2) { match read_byte(&mut tb2) { - 1 => { a21 = true }, - 2 => { a22 = true }, - _ => { }, + 1 => a21 = true, + 2 => a22 = true, + _ => {} } } return (a11 == a21) && (a12 == a22); @@ -839,12 +839,12 @@ unsafe extern "C" fn table_size(buf: *mut Buf) -> u32 { #[no_mangle] unsafe extern "C" fn idl_sub_buf_words(n_types1: u32, n_types2: u32) -> u32 { - return ((2 * n_types1 * n_types2) + 31) / 32; + return BitRel::words(n_types1, n_types2); } #[no_mangle] unsafe extern "C" fn idl_sub( - rel_buf: *mut u8, // a buffer with at least 2 * n * m bits + rel_buf: *mut u32, // a buffer with at least 2 * n * m bits end1: *mut u8, end2: *mut u8, n_types1: u32, @@ -856,7 +856,7 @@ unsafe extern "C" fn idl_sub( ) -> bool { let rel = BitRel { ptr: rel_buf, - end: rel_buf.add((idl_sub_buf_words(n_types1, n_types2) * 4) as usize), + end: rel_buf.add(idl_sub_buf_words(n_types1, n_types2) as usize), n: n_types1, m: n_types2, }; From 7f3f67e3516d2cd73e9699132c187a6029a06464 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 11 Mar 2022 22:55:49 +0000 Subject: [PATCH 025/128] generate static type table for t and use to check idl_sub _ t --- src/codegen/compile.ml | 93 ++++++++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 25 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index c9c3c046d24..eaf0d2c635f 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -758,7 +758,7 @@ module Func = struct (G.i (LocalGet (nr 1l))) (G.i (LocalGet (nr 2l))) ) - let _share_code4 env name (p1, p2, p3, p4) retty mk_body = + let share_code4 env name (p1, p2, p3, p4) retty mk_body = share_code env name [p1; p2; p3; p4] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) (G.i (LocalGet (nr 1l))) @@ -784,7 +784,7 @@ module Func = struct (G.i (LocalGet (nr 5l))) (G.i (LocalGet (nr 6l))) ) - let share_code8 env name (p1, p2, p3, p4, p5, p6, p7, p8) retty mk_body = + let _share_code8 env name (p1, p2, p3, p4, p5, p6, p7, p8) retty mk_body = share_code env name [p1; p2; p3; p4; p5; p6; p7; p8] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) (G.i (LocalGet (nr 1l))) @@ -4286,8 +4286,10 @@ module Serialization = struct let idl_service = -23l let idl_alias = 1l (* see Note [mutable stable values] *) - - let type_desc env ts : string = + (* TODO: use record *) + let type_desc env ts : + string * int list * int32 list (* type_desc, (relative offsets), indices of ts *) + = let open Type in (* Type traversal *) @@ -4360,6 +4362,12 @@ module Serialization = struct | Some i -> add_sleb128 (Int32.neg i) | None -> add_sleb128 (TM.find (normalize t) idx) in + let idx t = + let t = Type.normalize t in + match to_idl_prim t with + | Some i -> Int32.neg i + | None -> TM.find (normalize t) idx in + let rec add_typ t = match t with | Non -> assert false @@ -4423,10 +4431,17 @@ module Serialization = struct Buffer.add_string buf "DIDL"; add_leb128 (List.length typs); - List.iter add_typ typs; + let offsets = List.map (fun typ -> + let offset = Buffer.length buf in + add_typ typ; + offset) + typs + in add_leb128 (List.length ts); List.iter add_idx ts; - Buffer.contents buf + (Buffer.contents buf, + offsets, + List.map idx ts) (* Returns data (in bytes) and reference buffer size (in entries) needed *) let rec buffer_size env t = @@ -4790,18 +4805,46 @@ module Serialization = struct It advances the data_buffer past the decoded value (even if it returns coercion_error_value!) *) - let idl_sub env = - Func.share_code8 env "idl_sub" + let idl_sub env t2 = + Func.share_code4 env ("idl_sub<" ^ typ_hash t2 ^ ">") (("get_end1", I32Type), - ("get_end2", I32Type), + (* ("get_end2", I32Type), *) ("n_types1", I32Type), - ("n_types2", I32Type), + (* ("n_types2", I32Type), *) ("typtbl1", I32Type), - ("typtbl2", I32Type), - ("idltyp1", I32Type), - ("idltyp2", I32Type)) + (* ("typtbl2", I32Type), *) + ("idltyp1", I32Type) + (*, ("idltyp2", I32Type) *) + ) [I32Type] - (fun env get_end1 get_end2 get_n_types1 get_n_types2 get_typtbl1 get_typtbl2 get_idltyp1 get_idltyp2 -> + (fun env get_end1 (* get_end2 *) get_n_types1 (* get_n_types2 *) get_typtbl1 (*get_typtbl2*) get_idltyp1 (*get_idltyp2*) -> + let typdesc, offsets, idltyps2 = type_desc env [t2] in + let idltyp2 = List.hd idltyps2 in + let (set_end2, get_end2) = new_local env "end2" in + let (set_n_types2, get_n_types2) = new_local env "n_types2" in + let (set_typtbl2, get_typtbl2) = new_local env "typetbl2" in + let (set_idltyp2, get_idltyp2) = new_local env "idltyp2" in + let static_typedesc = + Int32.(add (Blob.vanilla_lit env typdesc) Blob.unskewed_payload_offset) + in + let tbl2 = + let buf = Buffer.create (List.length offsets * 4) in + begin + List.iter (fun offset -> + Buffer.add_int32_le buf + Int32.(add static_typedesc (of_int(offset)))) + offsets; + Buffer.contents buf + end + in + let static_typtbl2 = + Int32.add (Blob.vanilla_lit env tbl2) Blob.unskewed_payload_offset + in + compile_unboxed_const Int32.(add static_typedesc (of_int (String.length typdesc))) + ^^ set_end2 ^^ + compile_unboxed_const (Int32.of_int (List.length offsets)) ^^ set_n_types2 ^^ + compile_unboxed_const static_typtbl2 ^^ set_typtbl2 ^^ + compile_unboxed_const idltyp2 ^^ set_idltyp2 ^^ get_n_types1 ^^ get_n_types2 ^^ E.call_import env "rts" "idl_sub_buf_words" ^^ Stack.dynamic_with_words env "rel_buf" (fun get_rel_buf_ptr -> @@ -5388,11 +5431,11 @@ module Serialization = struct ( coercion_failed "IDL error: unexpected variant tag" ) ) | Func _ -> - compile_unboxed_const 0xFFFF_FFFFl ^^ compile_unboxed_const 0xFFFF_FFFFl ^^ (* FIX ME *) - get_typtbl_size ^^ get_typtbl_size ^^ - get_typtbl ^^ get_typtbl ^^ - get_idltyp ^^ get_idltyp ^^ - idl_sub env ^^ + compile_unboxed_const 0xFFFF_FFFFl (* ^^ compile_unboxed_const 0xFFFF_FFFFl *) ^^ (* FIX ME *) + get_typtbl_size ^^ (* get_typtbl_size ^^ *) + get_typtbl ^^ (* get_typtbl ^^ *) + get_idltyp ^^ (* get_idltyp ^^ *) + idl_sub env t ^^ E.else_trap_with env "idl_sub_irreflexive:func" ^^ with_composite_typ idl_func (fun _get_typ_buf -> read_byte_tagged @@ -5403,11 +5446,11 @@ module Serialization = struct ] ); | Obj (Actor, _) -> - compile_unboxed_const 0xFFFF_FFFFl ^^ compile_unboxed_const 0xFFFF_FFFFl ^^ (* FIX ME *) - get_typtbl_size ^^ get_typtbl_size ^^ - get_typtbl ^^ get_typtbl ^^ - get_idltyp ^^ get_idltyp ^^ - idl_sub env ^^ + compile_unboxed_const 0xFFFF_FFFFl ^^ (* compile_unboxed_const 0xFFFF_FFFFl ^^ (* FIX ME *) *) + get_typtbl_size ^^ (* get_typtbl_size ^^ *) + get_typtbl ^^ (* get_typtbl ^^ *) + get_idltyp ^^ (* get_idltyp ^^ *) + idl_sub env t ^^ E.else_trap_with env "idl_sub_irreflexive:actor" ^^ with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data t) | Mut t -> @@ -5435,7 +5478,7 @@ module Serialization = struct let (set_data_size, get_data_size) = new_local env "data_size" in let (set_refs_size, get_refs_size) = new_local env "refs_size" in - let tydesc = type_desc env ts in + let (tydesc, _offsets, _idltyps) = type_desc env ts in let tydesc_len = Int32.of_int (String.length tydesc) in (* Get object sizes *) From 3fce6574ca08de774d53912c63b704a5de67b7ff Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 14 Mar 2022 13:23:41 +0000 Subject: [PATCH 026/128] fix broken argument typing of fun3 (missing async return) leading to test failure --- test/run-drun/idl-large-principal.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/run-drun/idl-large-principal.mo b/test/run-drun/idl-large-principal.mo index ffaa09e14dd..9f85cd19d75 100644 --- a/test/run-drun/idl-large-principal.mo +++ b/test/run-drun/idl-large-principal.mo @@ -1,7 +1,7 @@ actor { public query func fun1(_: Principal) : async () {}; public query func fun2(_: actor {}) : async () {}; - public query func fun3(_: shared () -> ()) : async () {}; + public query func fun3(_: shared () -> async ()) : async () {}; } From e5a18b9b1da86f6bc6ec527789d58b795f54df6b Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 15 Mar 2022 12:02:52 +0000 Subject: [PATCH 027/128] fail, don't trap --- src/codegen/compile.ml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index eaf0d2c635f..fbbbe1ab6f4 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5436,23 +5436,25 @@ module Serialization = struct get_typtbl ^^ (* get_typtbl ^^ *) get_idltyp ^^ (* get_idltyp ^^ *) idl_sub env t ^^ - E.else_trap_with env "idl_sub_irreflexive:func" ^^ - with_composite_typ idl_func (fun _get_typ_buf -> - read_byte_tagged - [ E.trap_with env ("IDL error: unexpected function reference" ^ Type.string_of_typ t) - ; read_actor_data t ^^ - read_text () ^^ - Tuple.from_stack env 2 - ] - ); + G.if1 I32Type + (with_composite_typ idl_func (fun _get_typ_buf -> + read_byte_tagged + [ E.trap_with env ("IDL error: unexpected function reference" ^ Type.string_of_typ t) + ; read_actor_data t ^^ + read_text () ^^ + Tuple.from_stack env 2 + ])) + (coercion_failed "IDL error: incompatible function type") | Obj (Actor, _) -> compile_unboxed_const 0xFFFF_FFFFl ^^ (* compile_unboxed_const 0xFFFF_FFFFl ^^ (* FIX ME *) *) get_typtbl_size ^^ (* get_typtbl_size ^^ *) get_typtbl ^^ (* get_typtbl ^^ *) get_idltyp ^^ (* get_idltyp ^^ *) idl_sub env t ^^ - E.else_trap_with env "idl_sub_irreflexive:actor" ^^ - with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data t) + G.if1 I32Type + (with_composite_typ idl_service + (fun _get_typ_buf -> read_actor_data t)) + (coercion_failed "IDL error: incompatible actor type") | Mut t -> read_alias env (Mut t) (fun get_arg_typ on_alloc -> let (set_result, get_result) = new_local env "result" in From 60534e8f9e6e4ae83582e49277d7b8f9a628cee2 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 15 Mar 2022 13:46:06 +0000 Subject: [PATCH 028/128] plumb proper end1; killl comments --- src/codegen/compile.ml | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index fbbbe1ab6f4..6420fb128b1 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -774,7 +774,7 @@ module Func = struct (G.i (LocalGet (nr 4l))) (G.i (LocalGet (nr 5l))) ) - let share_code7 env name (p1, p2, p3, p4, p5, p6, p7) retty mk_body = + let _share_code7 env name (p1, p2, p3, p4, p5, p6, p7) retty mk_body = share_code env name [p1; p2; p3; p4; p5; p6; p7] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) (G.i (LocalGet (nr 1l))) @@ -784,7 +784,7 @@ module Func = struct (G.i (LocalGet (nr 5l))) (G.i (LocalGet (nr 6l))) ) - let _share_code8 env name (p1, p2, p3, p4, p5, p6, p7, p8) retty mk_body = + let share_code8 env name (p1, p2, p3, p4, p5, p6, p7, p8) retty mk_body = share_code env name [p1; p2; p3; p4; p5; p6; p7; p8] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) (G.i (LocalGet (nr 1l))) @@ -4808,16 +4808,12 @@ module Serialization = struct let idl_sub env t2 = Func.share_code4 env ("idl_sub<" ^ typ_hash t2 ^ ">") (("get_end1", I32Type), - (* ("get_end2", I32Type), *) ("n_types1", I32Type), - (* ("n_types2", I32Type), *) ("typtbl1", I32Type), - (* ("typtbl2", I32Type), *) ("idltyp1", I32Type) - (*, ("idltyp2", I32Type) *) ) [I32Type] - (fun env get_end1 (* get_end2 *) get_n_types1 (* get_n_types2 *) get_typtbl1 (*get_typtbl2*) get_idltyp1 (*get_idltyp2*) -> + (fun env get_end1 get_n_types1 get_typtbl1 get_idltyp1 -> let typdesc, offsets, idltyps2 = type_desc env [t2] in let idltyp2 = List.hd idltyps2 in let (set_end2, get_end2) = new_local env "end2" in @@ -4863,16 +4859,17 @@ module Serialization = struct let open Type in let t = Type.normalize t in let name = "@deserialize_go<" ^ typ_hash t ^ ">" in - Func.share_code7 env name + Func.share_code8 env name (("data_buffer", I32Type), ("ref_buffer", I32Type), + ("typtbl_end", I32Type), ("typtbl", I32Type), ("idltyp", I32Type), ("typtbl_size", I32Type), ("depth", I32Type), ("can_recover", I32Type) ) [I32Type] - (fun env get_data_buf get_ref_buf get_typtbl get_idltyp get_typtbl_size get_depth get_can_recover -> + (fun env get_data_buf get_ref_buf get_typtbl_end get_typtbl get_idltyp get_typtbl_size get_depth get_can_recover -> (* Check recursion depth (protects against empty record etc.) *) (* Factor 2 because at each step, the expected type could go through one @@ -4892,6 +4889,7 @@ module Serialization = struct set_idlty ^^ get_data_buf ^^ get_ref_buf ^^ + get_typtbl_end ^^ get_typtbl ^^ get_idlty ^^ get_typtbl_size ^^ @@ -5431,10 +5429,10 @@ module Serialization = struct ( coercion_failed "IDL error: unexpected variant tag" ) ) | Func _ -> - compile_unboxed_const 0xFFFF_FFFFl (* ^^ compile_unboxed_const 0xFFFF_FFFFl *) ^^ (* FIX ME *) - get_typtbl_size ^^ (* get_typtbl_size ^^ *) - get_typtbl ^^ (* get_typtbl ^^ *) - get_idltyp ^^ (* get_idltyp ^^ *) + get_typtbl_end ^^ + get_typtbl_size ^^ + get_typtbl ^^ + get_idltyp ^^ idl_sub env t ^^ G.if1 I32Type (with_composite_typ idl_func (fun _get_typ_buf -> @@ -5446,10 +5444,10 @@ module Serialization = struct ])) (coercion_failed "IDL error: incompatible function type") | Obj (Actor, _) -> - compile_unboxed_const 0xFFFF_FFFFl ^^ (* compile_unboxed_const 0xFFFF_FFFFl ^^ (* FIX ME *) *) - get_typtbl_size ^^ (* get_typtbl_size ^^ *) - get_typtbl ^^ (* get_typtbl ^^ *) - get_idltyp ^^ (* get_idltyp ^^ *) + get_typtbl_end ^^ + get_typtbl_size ^^ + get_typtbl ^^ + get_idltyp ^^ idl_sub env t ^^ G.if1 I32Type (with_composite_typ idl_service @@ -5582,6 +5580,7 @@ module Serialization = struct G.concat_map (fun t -> get_data_buf ^^ get_ref_buf ^^ + get_maintyps_ptr ^^ load_unskewed_ptr ^^ (* typtbl_end *) get_typtbl_ptr ^^ load_unskewed_ptr ^^ ReadBuf.read_sleb128 env get_main_typs_buf ^^ get_typtbl_size_ptr ^^ load_unskewed_ptr ^^ From d2427e2f7f30cc1c26cc67faef2931fc47922fa9 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 15 Mar 2022 14:39:36 +0000 Subject: [PATCH 029/128] cleanup debug code --- src/codegen/compile.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 6420fb128b1..d4026ca0ff7 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5009,9 +5009,9 @@ module Serialization = struct get_ptr ^^ get_len ^^ Text.of_ptr_size env in - let read_actor_data t = + let read_actor_data () = read_byte_tagged - [ E.trap_with env ("IDL error: unexpected actor reference" ^ Type.string_of_typ t) + [ E.trap_with env ("IDL error: unexpected actor reference") ; read_principal () ] in @@ -5437,8 +5437,8 @@ module Serialization = struct G.if1 I32Type (with_composite_typ idl_func (fun _get_typ_buf -> read_byte_tagged - [ E.trap_with env ("IDL error: unexpected function reference" ^ Type.string_of_typ t) - ; read_actor_data t ^^ + [ E.trap_with env ("IDL error: unexpected function reference") + ; read_actor_data () ^^ read_text () ^^ Tuple.from_stack env 2 ])) @@ -5451,7 +5451,7 @@ module Serialization = struct idl_sub env t ^^ G.if1 I32Type (with_composite_typ idl_service - (fun _get_typ_buf -> read_actor_data t)) + (fun _get_typ_buf -> read_actor_data ())) (coercion_failed "IDL error: incompatible actor type") | Mut t -> read_alias env (Mut t) (fun get_arg_typ on_alloc -> From e174af54afd56e2c40c6e24710266c1660ac3b91 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 15 Mar 2022 19:28:07 +0000 Subject: [PATCH 030/128] omit check for extended types --- src/codegen/compile.ml | 44 ++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index d4026ca0ff7..fe7a42ef74d 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -784,8 +784,8 @@ module Func = struct (G.i (LocalGet (nr 5l))) (G.i (LocalGet (nr 6l))) ) - let share_code8 env name (p1, p2, p3, p4, p5, p6, p7, p8) retty mk_body = - share_code env name [p1; p2; p3; p4; p5; p6; p7; p8] retty (fun env -> mk_body env + let share_code9 env name (p1, p2, p3, p4, p5, p6, p7, p8, p9) retty mk_body = + share_code env name [p1; p2; p3; p4; p5; p6; p7; p8; p9] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) (G.i (LocalGet (nr 1l))) (G.i (LocalGet (nr 2l))) @@ -794,6 +794,7 @@ module Func = struct (G.i (LocalGet (nr 5l))) (G.i (LocalGet (nr 6l))) (G.i (LocalGet (nr 7l))) + (G.i (LocalGet (nr 8l))) ) end (* Func *) @@ -4859,8 +4860,9 @@ module Serialization = struct let open Type in let t = Type.normalize t in let name = "@deserialize_go<" ^ typ_hash t ^ ">" in - Func.share_code8 env name - (("data_buffer", I32Type), + Func.share_code9 env name + (("extended", I32Type), + ("data_buffer", I32Type), ("ref_buffer", I32Type), ("typtbl_end", I32Type), ("typtbl", I32Type), @@ -4869,7 +4871,7 @@ module Serialization = struct ("depth", I32Type), ("can_recover", I32Type) ) [I32Type] - (fun env get_data_buf get_ref_buf get_typtbl_end get_typtbl get_idltyp get_typtbl_size get_depth get_can_recover -> + (fun env get_extended get_data_buf get_ref_buf get_typtbl_end get_typtbl get_idltyp get_typtbl_size get_depth get_can_recover -> (* Check recursion depth (protects against empty record etc.) *) (* Factor 2 because at each step, the expected type could go through one @@ -4887,6 +4889,7 @@ module Serialization = struct let go' can_recover env t = let (set_idlty, get_idlty) = new_local env "idl_ty" in set_idlty ^^ + get_extended ^^ get_data_buf ^^ get_ref_buf ^^ get_typtbl_end ^^ @@ -5429,11 +5432,16 @@ module Serialization = struct ( coercion_failed "IDL error: unexpected variant tag" ) ) | Func _ -> - get_typtbl_end ^^ - get_typtbl_size ^^ - get_typtbl ^^ - get_idltyp ^^ - idl_sub env t ^^ + get_extended ^^ + G.if1 I32Type + (compile_unboxed_const 1l) + (begin + get_typtbl_end ^^ + get_typtbl_size ^^ + get_typtbl ^^ + get_idltyp ^^ + idl_sub env t + end) ^^ G.if1 I32Type (with_composite_typ idl_func (fun _get_typ_buf -> read_byte_tagged @@ -5444,11 +5452,16 @@ module Serialization = struct ])) (coercion_failed "IDL error: incompatible function type") | Obj (Actor, _) -> - get_typtbl_end ^^ - get_typtbl_size ^^ - get_typtbl ^^ - get_idltyp ^^ - idl_sub env t ^^ + get_extended ^^ + G.if1 I32Type + (compile_unboxed_const 1l) + (begin + get_typtbl_end ^^ + get_typtbl_size ^^ + get_typtbl ^^ + get_idltyp ^^ + idl_sub env t + end) ^^ G.if1 I32Type (with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data ())) @@ -5579,6 +5592,7 @@ module Serialization = struct E.else_trap_with env ("IDL error: too few arguments " ^ ts_name) ^^ G.concat_map (fun t -> + if extended then compile_unboxed_const 1l else compile_unboxed_const 0l ^^ get_data_buf ^^ get_ref_buf ^^ get_maintyps_ptr ^^ load_unskewed_ptr ^^ (* typtbl_end *) get_typtbl_ptr ^^ load_unskewed_ptr ^^ From 4a3d14b99290c2f1bd43c0838cdf8b88268e69c8 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 16 Mar 2022 15:48:37 +0000 Subject: [PATCH 031/128] fix --- src/codegen/compile.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index fe7a42ef74d..a9095d01d5f 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5592,7 +5592,7 @@ module Serialization = struct E.else_trap_with env ("IDL error: too few arguments " ^ ts_name) ^^ G.concat_map (fun t -> - if extended then compile_unboxed_const 1l else compile_unboxed_const 0l ^^ + compile_unboxed_const (if extended then 1l else 0l) ^^ get_data_buf ^^ get_ref_buf ^^ get_maintyps_ptr ^^ load_unskewed_ptr ^^ (* typtbl_end *) get_typtbl_ptr ^^ load_unskewed_ptr ^^ From 759b40f485cd3b5725b314d07b481edcdc7a6eef Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 17 Mar 2022 17:52:44 +0000 Subject: [PATCH 032/128] broken attempt at top-level option typing --- src/codegen/compile.ml | 44 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index a9095d01d5f..b77fa3d8dde 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5586,12 +5586,23 @@ module Serialization = struct ReadBuf.set_ptr get_main_typs_buf (get_maintyps_ptr ^^ load_unskewed_ptr) ^^ ReadBuf.set_end get_main_typs_buf (ReadBuf.get_end get_data_buf) ^^ ReadBuf.read_leb128 env get_main_typs_buf ^^ set_arg_count ^^ - + (* Remember data buffer position, to detect progress *) + let (set_old_pos, get_old_pos) = new_local env "old_pos" in + let (set_old_main_pos, get_old_main_pos) = new_local env "old_main_pos" in +(* get_arg_count ^^ compile_rel_const I32Op.GeU (Int32.of_int (List.length ts)) ^^ E.else_trap_with env ("IDL error: too few arguments " ^ ts_name) ^^ - + *) G.concat_map (fun t -> + ReadBuf.get_ptr get_data_buf ^^ set_old_pos ^^ + ReadBuf.get_ptr get_main_typs_buf ^^ set_old_main_pos ^^ + ReadBuf.is_empty env get_main_typs_buf ^^ + (G.if0 + (begin + (compile_unboxed_const (coercion_error_value env)) ^^ set_val + end) + (begin compile_unboxed_const (if extended then 1l else 0l) ^^ get_data_buf ^^ get_ref_buf ^^ get_maintyps_ptr ^^ load_unskewed_ptr ^^ (* typtbl_end *) @@ -5599,13 +5610,22 @@ module Serialization = struct ReadBuf.read_sleb128 env get_main_typs_buf ^^ get_typtbl_size_ptr ^^ load_unskewed_ptr ^^ compile_unboxed_const 0l ^^ (* initial depth *) - compile_unboxed_const 0l ^^ (* initially, cannot recover *) - deserialize_go env t ^^ set_val ^^ + compile_unboxed_const 0l ^^ (* initially, can recover *) + deserialize_go env t ^^ set_val + end)) + ^^ get_val ^^ compile_eq_const (coercion_error_value env) ^^ - E.then_trap_with env ("IDL error: coercion failure encountered") ^^ - get_val + Type.(G.if1 I32Type + (match normalize t with + | Opt _ | Any -> + ReadBuf.set_ptr get_main_typs_buf get_old_main_pos ^^ + ReadBuf.set_ptr get_data_buf get_old_pos ^^ + Opt.null_lit env + | _ -> E.trap_with env ("IDL error: coercion failure encountered")) + (get_val)) ) ts ^^ +(* (* Skip any extra arguments *) get_arg_count ^^ compile_sub_const (Int32.of_int (List.length ts)) ^^ from_0_to_n env (fun _ -> @@ -5615,12 +5635,24 @@ module Serialization = struct compile_unboxed_const 0l ^^ E.call_import env "rts" "skip_any" ) ^^ + *) + + compile_while env + ((ReadBuf.is_empty env get_main_typs_buf) ^^ Bool.neg) + (begin + get_data_buf ^^ + get_typtbl_ptr ^^ load_unskewed_ptr ^^ + ReadBuf.read_sleb128 env get_main_typs_buf ^^ + compile_unboxed_const 0l ^^ + E.call_import env "rts" "skip_any" + end) ^^ ReadBuf.is_empty env get_data_buf ^^ E.else_trap_with env ("IDL error: left-over bytes " ^ ts_name) ^^ ReadBuf.is_empty env get_ref_buf ^^ E.else_trap_with env ("IDL error: left-over references " ^ ts_name) )))))) + ) let deserialize env ts = From d163ade970c39de2a9ba84589d6b3458de1cd6cf Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 17 Mar 2022 23:01:37 +0000 Subject: [PATCH 033/128] fixed broken code --- src/codegen/compile.ml | 80 ++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index b77fa3d8dde..787f1813eed 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5586,65 +5586,47 @@ module Serialization = struct ReadBuf.set_ptr get_main_typs_buf (get_maintyps_ptr ^^ load_unskewed_ptr) ^^ ReadBuf.set_end get_main_typs_buf (ReadBuf.get_end get_data_buf) ^^ ReadBuf.read_leb128 env get_main_typs_buf ^^ set_arg_count ^^ - (* Remember data buffer position, to detect progress *) - let (set_old_pos, get_old_pos) = new_local env "old_pos" in - let (set_old_main_pos, get_old_main_pos) = new_local env "old_main_pos" in -(* - get_arg_count ^^ - compile_rel_const I32Op.GeU (Int32.of_int (List.length ts)) ^^ - E.else_trap_with env ("IDL error: too few arguments " ^ ts_name) ^^ - *) + G.concat_map (fun t -> - ReadBuf.get_ptr get_data_buf ^^ set_old_pos ^^ - ReadBuf.get_ptr get_main_typs_buf ^^ set_old_main_pos ^^ - ReadBuf.is_empty env get_main_typs_buf ^^ - (G.if0 + let default_or_trap = + Type.( + match normalize t with + | Prim Null | Opt _ | Any -> + Opt.null_lit env + | _ -> E.trap_with env "IDL error: coercion failure encountered") + in + get_arg_count ^^ + compile_rel_const I32Op.Eq 0l ^^ + G.if1 I32Type + default_or_trap (begin - (compile_unboxed_const (coercion_error_value env)) ^^ set_val - end) - (begin - compile_unboxed_const (if extended then 1l else 0l) ^^ - get_data_buf ^^ get_ref_buf ^^ - get_maintyps_ptr ^^ load_unskewed_ptr ^^ (* typtbl_end *) - get_typtbl_ptr ^^ load_unskewed_ptr ^^ - ReadBuf.read_sleb128 env get_main_typs_buf ^^ - get_typtbl_size_ptr ^^ load_unskewed_ptr ^^ - compile_unboxed_const 0l ^^ (* initial depth *) - compile_unboxed_const 0l ^^ (* initially, can recover *) - deserialize_go env t ^^ set_val - end)) - ^^ - get_val ^^ compile_eq_const (coercion_error_value env) ^^ - Type.(G.if1 I32Type - (match normalize t with - | Opt _ | Any -> - ReadBuf.set_ptr get_main_typs_buf get_old_main_pos ^^ - ReadBuf.set_ptr get_data_buf get_old_pos ^^ - Opt.null_lit env - | _ -> E.trap_with env ("IDL error: coercion failure encountered")) - (get_val)) + compile_unboxed_const (if extended then 1l else 0l) ^^ + get_data_buf ^^ get_ref_buf ^^ + get_maintyps_ptr ^^ load_unskewed_ptr ^^ (* typtbl_end *) + get_typtbl_ptr ^^ load_unskewed_ptr ^^ + ReadBuf.read_sleb128 env get_main_typs_buf ^^ + get_typtbl_size_ptr ^^ load_unskewed_ptr ^^ + compile_unboxed_const 0l ^^ (* initial depth *) + compile_unboxed_const 1l ^^ (* initially, can recover *) + deserialize_go env t ^^ set_val ^^ + get_val ^^ compile_eq_const (coercion_error_value env) ^^ + get_arg_count ^^ compile_sub_const 1l ^^ set_arg_count ^^ + (G.if1 I32Type + default_or_trap + get_val) + end) ) ts ^^ -(* (* Skip any extra arguments *) - get_arg_count ^^ compile_sub_const (Int32.of_int (List.length ts)) ^^ - from_0_to_n env (fun _ -> - get_data_buf ^^ - get_typtbl_ptr ^^ load_unskewed_ptr ^^ - ReadBuf.read_sleb128 env get_main_typs_buf ^^ - compile_unboxed_const 0l ^^ - E.call_import env "rts" "skip_any" - ) ^^ - *) - compile_while env - ((ReadBuf.is_empty env get_main_typs_buf) ^^ Bool.neg) - (begin + (get_arg_count ^^ compile_rel_const I32Op.GtU 0l) + (begin get_data_buf ^^ get_typtbl_ptr ^^ load_unskewed_ptr ^^ ReadBuf.read_sleb128 env get_main_typs_buf ^^ compile_unboxed_const 0l ^^ - E.call_import env "rts" "skip_any" + E.call_import env "rts" "skip_any" ^^ + get_arg_count ^^ compile_sub_const 1l ^^ set_arg_count end) ^^ ReadBuf.is_empty env get_data_buf ^^ From ae93162e4fba0fd60d636f2d18e7abe4673c8532 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 17 Mar 2022 23:11:15 +0000 Subject: [PATCH 034/128] bump candid --- nix/sources.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nix/sources.json b/nix/sources.json index 100718fb9fe..8bc14bc6b7c 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -6,10 +6,10 @@ "homepage": "", "owner": "dfinity", "repo": "candid", - "rev": "a555d77704d691bb8f34e21a049d44ba0acee3f8", - "sha256": "0vn171lcadpznrl5nq2mws2zjjqj9jxyvndb2is3dixbjqyvjssx", + "rev": "0c8e620444ad6e2a4105ddc87b0e6292063b26cc", + "sha256": "014v0hn8yb80b4p4hy8qfqr6k90z9dcxhgbn1vrd7f5pa1dw39bg", "type": "tarball", - "url": "https://github.com/dfinity/candid/archive/a555d77704d691bb8f34e21a049d44ba0acee3f8.tar.gz", + "url": "https://github.com/dfinity/candid/archive/0c8e620444ad6e2a4105ddc87b0e6292063b26cc.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "esm": { From e8febab4a369db3ced63e6eb76a4b4effc7d520a Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 18 Mar 2022 14:31:49 +0000 Subject: [PATCH 035/128] update candid to PR branch --- nix/sources.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nix/sources.json b/nix/sources.json index 8bc14bc6b7c..a73a5d6a315 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -1,15 +1,15 @@ { "candid": { - "branch": "master", + "branch": "claudio/candid-subtype-check", "builtin": false, "description": "Candid Library for the Internet Computer", "homepage": "", "owner": "dfinity", "repo": "candid", - "rev": "0c8e620444ad6e2a4105ddc87b0e6292063b26cc", - "sha256": "014v0hn8yb80b4p4hy8qfqr6k90z9dcxhgbn1vrd7f5pa1dw39bg", + "rev": "9b0e92e8729e660bfdcf02a3169b9a4b829762a4", + "sha256": "0rh3n0wqkbj8ry2n2pgni18bfwn8x80cpk741kis3d7l61n808jk", "type": "tarball", - "url": "https://github.com/dfinity/candid/archive/0c8e620444ad6e2a4105ddc87b0e6292063b26cc.tar.gz", + "url": "https://github.com/dfinity/candid/archive/9b0e92e8729e660bfdcf02a3169b9a4b829762a4.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "esm": { From 597cb2e4fd223cd9a109e20174fdde5a952f9a82 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 18 Mar 2022 14:43:47 +0000 Subject: [PATCH 036/128] improve error message --- src/codegen/compile.ml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 787f1813eed..bac59d87725 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5588,12 +5588,12 @@ module Serialization = struct ReadBuf.read_leb128 env get_main_typs_buf ^^ set_arg_count ^^ G.concat_map (fun t -> - let default_or_trap = - Type.( - match normalize t with - | Prim Null | Opt _ | Any -> - Opt.null_lit env - | _ -> E.trap_with env "IDL error: coercion failure encountered") + let can_recover, default_or_trap = Type.( + match normalize t with + | Prim Null | Opt _ | Any -> + (compile_unboxed_one, Opt.null_lit env) + | _ -> + (compile_unboxed_zero, E.trap_with env "IDL error: coercion failure encountered")) in get_arg_count ^^ compile_rel_const I32Op.Eq 0l ^^ @@ -5607,7 +5607,7 @@ module Serialization = struct ReadBuf.read_sleb128 env get_main_typs_buf ^^ get_typtbl_size_ptr ^^ load_unskewed_ptr ^^ compile_unboxed_const 0l ^^ (* initial depth *) - compile_unboxed_const 1l ^^ (* initially, can recover *) + can_recover ^^ deserialize_go env t ^^ set_val ^^ get_val ^^ compile_eq_const (coercion_error_value env) ^^ get_arg_count ^^ compile_sub_const 1l ^^ set_arg_count ^^ From dd95ececf2a76afeff6ab80dae0810b8b9f022ef Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 18 Mar 2022 15:45:08 +0000 Subject: [PATCH 037/128] match previous behaviour --- src/codegen/compile.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index bac59d87725..4f21f73823f 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5591,14 +5591,14 @@ module Serialization = struct let can_recover, default_or_trap = Type.( match normalize t with | Prim Null | Opt _ | Any -> - (compile_unboxed_one, Opt.null_lit env) + (compile_unboxed_one, fun msg -> Opt.null_lit env) | _ -> - (compile_unboxed_zero, E.trap_with env "IDL error: coercion failure encountered")) + (compile_unboxed_zero, fun msg -> E.trap_with env msg)) in get_arg_count ^^ compile_rel_const I32Op.Eq 0l ^^ G.if1 I32Type - default_or_trap + (default_or_trap ("IDL error: too few arguments " ^ ts_name)) (begin compile_unboxed_const (if extended then 1l else 0l) ^^ get_data_buf ^^ get_ref_buf ^^ @@ -5612,7 +5612,7 @@ module Serialization = struct get_val ^^ compile_eq_const (coercion_error_value env) ^^ get_arg_count ^^ compile_sub_const 1l ^^ set_arg_count ^^ (G.if1 I32Type - default_or_trap + (default_or_trap "IDL error: coercion failure encountered") get_val) end) ) ts ^^ From c59ccc27abe9213f82332c1de8ad79bfbe69f768 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 21 Mar 2022 13:40:49 +0000 Subject: [PATCH 038/128] cleanup and assert on IDL_con_alias --- rts/motoko-rts/src/idl.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 8d15064c0f4..8311d7ec02c 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -598,7 +598,11 @@ unsafe fn sub( // unfold t1, if necessary let mut tb1 = Buf { - ptr: *typtbl1.add(if t1 < 0 { 0 } else { t1 as usize }), // better dummy? + ptr: if t1 < 0 { + end1 + } else { + *typtbl1.add(t1 as usize) + }, end: end1, }; @@ -608,7 +612,11 @@ unsafe fn sub( // unfold t2, if necessary let mut tb2 = Buf { - ptr: *typtbl2.add(if t2 < 0 { 0 } else { t2 as usize }), // better dummy? + ptr: if t2 < 0 { + end2 + } else { + *typtbl2.add(t2 as usize) + }, end: end2, }; @@ -616,9 +624,8 @@ unsafe fn sub( t2 = sleb128_decode(&mut tb2); }; - debug_assert!(t1 < 0 && t2 < 0); - match (t1, t2) { + (_, IDL_CON_alias) | (IDL_CON_alias, _) => idl_trap_with("sub: unexpected alias"), (_, IDL_PRIM_reserved) => true, (IDL_PRIM_empty, _) => true, /* @@ -648,6 +655,7 @@ unsafe fn sub( return sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1); } (IDL_CON_func, IDL_CON_func) => { + // TODO: extend with opt subtyping // contra in domain let in1 = leb128_decode(&mut tb1); let in2 = leb128_decode(&mut tb2); From b4ea0e64a7da76bedd5827ce71f6276b5ea4b211 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 21 Mar 2022 15:06:05 +0000 Subject: [PATCH 039/128] implement nat <: int --- rts/motoko-rts/src/idl.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 8311d7ec02c..96a0dcf10b7 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -628,6 +628,7 @@ unsafe fn sub( (_, IDL_CON_alias) | (IDL_CON_alias, _) => idl_trap_with("sub: unexpected alias"), (_, IDL_PRIM_reserved) => true, (IDL_PRIM_empty, _) => true, + (IDL_PRIM_nat, IDL_PRIM_int) => true, /* (IDL_PRIM_null, IDL_CON_opt) => true, (IDL_CON_opt, IDL_CON_opt) => { From 23862d5756f38b53dd8f3f43d89d7412123b2c12 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 21 Mar 2022 15:48:21 +0000 Subject: [PATCH 040/128] add (failing) test for opt defaulting in function types (prior to implemenation) --- test/run-drun/idl-sub-default.mo | 93 +++++++++++++++++++ test/run-drun/ok/idl-sub-default.drun-run.ok | 8 ++ .../run-drun/ok/idl-sub-default.ic-ref-run.ok | 11 +++ 3 files changed, 112 insertions(+) create mode 100644 test/run-drun/idl-sub-default.mo create mode 100644 test/run-drun/ok/idl-sub-default.drun-run.ok create mode 100644 test/run-drun/ok/idl-sub-default.ic-ref-run.ok diff --git a/test/run-drun/idl-sub-default.mo b/test/run-drun/idl-sub-default.mo new file mode 100644 index 00000000000..eade603c07c --- /dev/null +++ b/test/run-drun/idl-sub-default.mo @@ -0,0 +1,93 @@ +import Prim "mo:⛔"; + +actor this { + + + public func send_f0( + f : shared (Nat) -> async Int + ) : async () { + Prim.debugPrint("ok"); + }; + + public func f0(n : Nat) : async Int { 0 }; + + public func f0_1(n : Int) : async Nat { 0 }; + + public func f0_2() : async (Nat, Bool) { (0,true) }; + + public func f0_3(i : Nat, on : ?Nat) : async (Int, ?Nat) { (0, null); }; + + public func f0_4(ob : ?Bool) : async Int { 0 }; + + public func f0_5(n : Nat) : async ?Bool { null }; + + public func go() : async () { + let t = debug_show (Prim.principalOfActor(this)); + + // vanilla subtyping on in/out args + do { + let this = actor (t) : actor { + send_f0 : (shared (n:Int) -> async Nat) -> async (); + }; + try { + await this.send_f0(f0_1); + } + catch e { Prim.debugPrint "wrong_0_1"; } + }; + + // vanilla subtyping on in/out arg sequences + do { + let this = actor (t) : actor { + send_f0 : (shared () -> async (Nat,Bool)) -> async (); + }; + try { + await this.send_f0(f0_2); + } + catch e { Prim.debugPrint "wrong_0_2"; } + }; + + // opt subtyping in arg and return + do { + let this = actor (t) : actor { + send_f0 : (shared (Nat, ?Nat) -> async (Int, ?Nat)) -> async (); + }; + try { + await this.send_f0(f0_3); + } + catch e { Prim.debugPrint "wrong_0_3"; } + }; + + // opt override in arg + do { + let this = actor (t) : actor { + send_f0 : (shared (?Bool) -> async Int) -> async (); + }; + try { + await this.send_f0(f0_4); + } + catch e { Prim.debugPrint "wrong_0_4"; } + }; + + + // opt override in return + do { + let this = actor (t) : actor { + send_f0 : (shared (Nat) -> async ?Bool) -> async (); + }; + try { + await this.send_f0(f0_5); + } + catch e { Prim.debugPrint "wrong_0_5"; } + }; + + + + + }; + + +} +//SKIP run +//SKIP run-ir +//SKIP run-low +//CALL ingress go "DIDL\x00\x00" \ No newline at end of file diff --git a/test/run-drun/ok/idl-sub-default.drun-run.ok b/test/run-drun/ok/idl-sub-default.drun-run.ok new file mode 100644 index 00000000000..46420dc7368 --- /dev/null +++ b/test/run-drun/ok/idl-sub-default.drun-run.ok @@ -0,0 +1,8 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: ok +debug.print: ok +debug.print: wrong_0_3 +debug.print: ok +debug.print: wrong_0_5 +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-default.ic-ref-run.ok b/test/run-drun/ok/idl-sub-default.ic-ref-run.ok new file mode 100644 index 00000000000..e24f0656de7 --- /dev/null +++ b/test/run-drun/ok/idl-sub-default.ic-ref-run.ok @@ -0,0 +1,11 @@ +→ update create_canister(record {settings = null}) +← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… +← replied: () +→ update go() +debug.print: ok +debug.print: ok +debug.print: wrong_0_3 +debug.print: ok +debug.print: wrong_0_5 +← replied: () From 241def77fd71330ad6a12fe86648117a0474ddf4 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 21 Mar 2022 17:08:44 +0000 Subject: [PATCH 041/128] implement fancy function subtyping modulo defaulting; basic sanity tests --- rts/motoko-rts/src/idl.rs | 44 ++++++++++++------- test/run-drun/idl-sub-default.mo | 23 ++++++---- test/run-drun/ok/idl-sub-default.drun-run.ok | 4 +- .../run-drun/ok/idl-sub-default.ic-ref-run.ok | 4 +- 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 96a0dcf10b7..2001245917c 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -659,36 +659,46 @@ unsafe fn sub( // TODO: extend with opt subtyping // contra in domain let in1 = leb128_decode(&mut tb1); - let in2 = leb128_decode(&mut tb2); - if in1 > in2 { - return false; - } + let mut in2 = leb128_decode(&mut tb2); for _ in 0..in1 { let t11 = sleb128_decode(&mut tb1); - let t21 = sleb128_decode(&mut tb2); - // NB: invert p and args! - if !sub(rel, !p, end2, end1, typtbl2, typtbl1, t21, t11, depth + 1) { - return false; + if in2 == 0 { + if !opt_empty_sub(end1, typtbl1, t11) { + return false; + } + } else { + let t21 = sleb128_decode(&mut tb2); + in2 -= 1; + // NB: invert p and args! + if !sub(rel, !p, end2, end1, typtbl2, typtbl1, t21, t11, depth + 1) { + return false; + } } } - for _ in in1..in2 { + while in2 > 0 { let _ = sleb128_decode(&mut tb2); + in2 -= 1; } // co in range - let out1 = leb128_decode(&mut tb1); + let mut out1 = leb128_decode(&mut tb1); let out2 = leb128_decode(&mut tb2); - if out2 > out1 { - return false; - } for _ in 0..out2 { - let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); - if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { - return false; + if out1 == 0 { + if !opt_empty_sub(end2, typtbl2, t21) { + return false; + } + } else { + let t11 = sleb128_decode(&mut tb1); + out1 -= 1; + if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { + return false; + } } } - for _ in out2..out1 { + while out1 > 0 { let _ = sleb128_decode(&mut tb1); + out1 -= 1; } // check annotations (that we care about) // TODO: more generally, we would check equality of 256-bit bit-vectors, diff --git a/test/run-drun/idl-sub-default.mo b/test/run-drun/idl-sub-default.mo index eade603c07c..b9f93368174 100644 --- a/test/run-drun/idl-sub-default.mo +++ b/test/run-drun/idl-sub-default.mo @@ -9,6 +9,13 @@ actor this { Prim.debugPrint("ok"); }; + public func send_f1( + f : shared (?Nat) -> async ?Int + ) : async () { + Prim.debugPrint("ok"); + }; + + public func f0(n : Nat) : async Int { 0 }; public func f0_1(n : Int) : async Nat { 0 }; @@ -19,7 +26,7 @@ actor this { public func f0_4(ob : ?Bool) : async Int { 0 }; - public func f0_5(n : Nat) : async ?Bool { null }; + public func f1_0(n : ?Nat) : async Bool { true }; public func go() : async () { let t = debug_show (Prim.principalOfActor(this)); @@ -27,7 +34,7 @@ actor this { // vanilla subtyping on in/out args do { let this = actor (t) : actor { - send_f0 : (shared (n:Int) -> async Nat) -> async (); + send_f0 : (shared (n:Int) -> async Nat) -> async (); }; try { await this.send_f0(f0_1); @@ -38,7 +45,7 @@ actor this { // vanilla subtyping on in/out arg sequences do { let this = actor (t) : actor { - send_f0 : (shared () -> async (Nat,Bool)) -> async (); + send_f0 : (shared () -> async (Nat,Bool)) -> async (); }; try { await this.send_f0(f0_2); @@ -49,7 +56,7 @@ actor this { // opt subtyping in arg and return do { let this = actor (t) : actor { - send_f0 : (shared (Nat, ?Nat) -> async (Int, ?Nat)) -> async (); + send_f0 : (shared (Nat, ?Nat) -> async (Int, ?Nat)) -> async (); }; try { await this.send_f0(f0_3); @@ -60,7 +67,7 @@ actor this { // opt override in arg do { let this = actor (t) : actor { - send_f0 : (shared (?Bool) -> async Int) -> async (); + send_f0 : (shared (?Bool) -> async Int) -> async (); }; try { await this.send_f0(f0_4); @@ -72,12 +79,12 @@ actor this { // opt override in return do { let this = actor (t) : actor { - send_f0 : (shared (Nat) -> async ?Bool) -> async (); + send_f1 : (shared (?Nat) -> async Bool) -> async (); }; try { - await this.send_f0(f0_5); + await this.send_f1(f1_0); } - catch e { Prim.debugPrint "wrong_0_5"; } + catch e { Prim.debugPrint "wrong_1_0"; } }; diff --git a/test/run-drun/ok/idl-sub-default.drun-run.ok b/test/run-drun/ok/idl-sub-default.drun-run.ok index 46420dc7368..faf6786498f 100644 --- a/test/run-drun/ok/idl-sub-default.drun-run.ok +++ b/test/run-drun/ok/idl-sub-default.drun-run.ok @@ -2,7 +2,7 @@ ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a000000000000000001 ingress Completed: Reply: 0x4449444c0000 debug.print: ok debug.print: ok -debug.print: wrong_0_3 debug.print: ok -debug.print: wrong_0_5 +debug.print: ok +debug.print: ok ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-default.ic-ref-run.ok b/test/run-drun/ok/idl-sub-default.ic-ref-run.ok index e24f0656de7..820ad5af661 100644 --- a/test/run-drun/ok/idl-sub-default.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-default.ic-ref-run.ok @@ -5,7 +5,7 @@ → update go() debug.print: ok debug.print: ok -debug.print: wrong_0_3 debug.print: ok -debug.print: wrong_0_5 +debug.print: ok +debug.print: ok ← replied: () From 80d3a131f5a0ac1a996f8e7a6c620c8cd40dbf81 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 21 Mar 2022 17:39:49 +0000 Subject: [PATCH 042/128] rename opt_empty_sub and extend to null type --- rts/motoko-rts/src/idl.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 2001245917c..98855ac4d39 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -522,9 +522,9 @@ unsafe fn unfold(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> i32 { return sleb128_decode(&mut tb); } -unsafe fn opt_empty_sub(end: *mut u8, typtbl: *mut *mut u8, t: i32) -> bool { +unsafe fn is_null_opt_reserved(end: *mut u8, typtbl: *mut *mut u8, t: i32) -> bool { if is_primitive_type(t) { - return t == IDL_PRIM_reserved; + return t == IDL_PRIM_null || t == IDL_PRIM_reserved; } // unfold t @@ -656,14 +656,13 @@ unsafe fn sub( return sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1); } (IDL_CON_func, IDL_CON_func) => { - // TODO: extend with opt subtyping // contra in domain let in1 = leb128_decode(&mut tb1); let mut in2 = leb128_decode(&mut tb2); for _ in 0..in1 { let t11 = sleb128_decode(&mut tb1); if in2 == 0 { - if !opt_empty_sub(end1, typtbl1, t11) { + if !is_null_opt_reserved(end1, typtbl1, t11) { return false; } } else { @@ -685,7 +684,7 @@ unsafe fn sub( for _ in 0..out2 { let t21 = sleb128_decode(&mut tb2); if out1 == 0 { - if !opt_empty_sub(end2, typtbl2, t21) { + if !is_null_opt_reserved(end2, typtbl2, t21) { return false; } } else { @@ -735,7 +734,7 @@ unsafe fn sub( let t21 = sleb128_decode(&mut tb2); if n1 == 0 { // check all remaining fields optional - if !opt_empty_sub(end2, typtbl2, t21) { + if !is_null_opt_reserved(end2, typtbl2, t21) { return false; } continue; @@ -751,7 +750,7 @@ unsafe fn sub( } }; if tag1 > tag2 { - if !opt_empty_sub(end2, typtbl2, t21) { + if !is_null_opt_reserved(end2, typtbl2, t21) { // missing, non_opt field return false; } From 3ac4ac87c43d18c57a6c55f27a1f50d0f77c9f51 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 21 Mar 2022 22:37:10 +0000 Subject: [PATCH 043/128] test with multiple args --- test/run-drun/idl-sub-default.mo | 57 +++++++++++++++++++ test/run-drun/ok/idl-sub-default.drun-run.ok | 3 + .../run-drun/ok/idl-sub-default.ic-ref-run.ok | 3 + 3 files changed, 63 insertions(+) diff --git a/test/run-drun/idl-sub-default.mo b/test/run-drun/idl-sub-default.mo index b9f93368174..0a15ce4cc90 100644 --- a/test/run-drun/idl-sub-default.mo +++ b/test/run-drun/idl-sub-default.mo @@ -15,6 +15,14 @@ actor this { Prim.debugPrint("ok"); }; + public func send_f2( + f : shared (Nat, [Nat], {f:Nat;g:Nat}, {#l:Nat; #m:Nat}) -> + async(Int, [Int], {f:Int;g:Int}, {#l:Int; #m:Int}) + ) : async () { + Prim.debugPrint("ok"); + }; + + public func f0(n : Nat) : async Int { 0 }; @@ -28,6 +36,16 @@ actor this { public func f1_0(n : ?Nat) : async Bool { true }; + public func f2_0(n : Nat, a : [Nat], r : {f : Nat; g : Nat}, v : {#l : Nat; #m : Nat}) : + async (Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Int}) { + (1, [1], {f=1;g=1}, (#l 0)) + }; + + public func f2_1(n : Int, a : [Int], r : {f : Int}, v : {#l : Int; #m : Int; #o : Int}) : + async (Nat, [Nat], {f : Nat; g : Nat; h : Nat}, { #l : Nat}) { + (1, [1], {f = 1; g = 2; h = 3}, (#l 0)) + }; + public func go() : async () { let t = debug_show (Prim.principalOfActor(this)); @@ -88,6 +106,45 @@ actor this { }; + // opt override in return + do { + let this = actor (t) : actor { + send_f1 : (shared (?Nat) -> async Bool) -> async (); + }; + try { + await this.send_f1(f1_0); + } + catch e { Prim.debugPrint "wrong_1_0"; } + }; + + + do { + let this = actor (t) : actor { + send_f2 : + (shared (Nat, [Nat], {f : Nat; g : Nat}, {#l : Nat; #m : Nat}) -> + async(Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Int})) -> + async () + }; + try { + await this.send_f2(f2_0); + } + catch e { Prim.debugPrint "wrong_2_0"; } + }; + + + do { + let this = actor (t) : actor { + send_f2 : + (shared (Int, [Int], {f : Int}, {#l : Int; #m : Int; #o : Int}) -> + async(Nat, [Nat], {f : Nat; g : Nat; h : Nat}, {#l : Nat})) -> + async () + }; + try { + await this.send_f2(f2_1); + } + catch e { Prim.debugPrint "wrong_2_1"; } + }; + }; diff --git a/test/run-drun/ok/idl-sub-default.drun-run.ok b/test/run-drun/ok/idl-sub-default.drun-run.ok index faf6786498f..ebc474269a7 100644 --- a/test/run-drun/ok/idl-sub-default.drun-run.ok +++ b/test/run-drun/ok/idl-sub-default.drun-run.ok @@ -5,4 +5,7 @@ debug.print: ok debug.print: ok debug.print: ok debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-default.ic-ref-run.ok b/test/run-drun/ok/idl-sub-default.ic-ref-run.ok index 820ad5af661..b1013e56fb9 100644 --- a/test/run-drun/ok/idl-sub-default.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-default.ic-ref-run.ok @@ -8,4 +8,7 @@ debug.print: ok debug.print: ok debug.print: ok debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok ← replied: () From 83303b95739114444a1f944e990529978dbb5420 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 21 Mar 2022 22:50:13 +0000 Subject: [PATCH 044/128] test trailing defaults --- test/run-drun/idl-sub-default.mo | 37 +++++++++++++++---- test/run-drun/ok/idl-sub-default.drun-run.ok | 1 + .../run-drun/ok/idl-sub-default.ic-ref-run.ok | 1 + 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/test/run-drun/idl-sub-default.mo b/test/run-drun/idl-sub-default.mo index 0a15ce4cc90..beb979bde3a 100644 --- a/test/run-drun/idl-sub-default.mo +++ b/test/run-drun/idl-sub-default.mo @@ -1,8 +1,8 @@ import Prim "mo:⛔"; +// test candid subtype test with higher-order arguments actor this { - public func send_f0( f : shared (Nat) -> async Int ) : async () { @@ -22,7 +22,12 @@ actor this { Prim.debugPrint("ok"); }; - + public func send_f3( + f : shared () -> + async (Null, Any, ?None) + ) : async () { + Prim.debugPrint("ok"); + }; public func f0(n : Nat) : async Int { 0 }; @@ -46,6 +51,11 @@ actor this { (1, [1], {f = 1; g = 2; h = 3}, (#l 0)) }; + public func f3_0() : + async (n : Null, a : ?None, r : Any) { + (null, null, null) + }; + public func go() : async () { let t = debug_show (Prim.principalOfActor(this)); @@ -118,12 +128,13 @@ actor this { }; + // several args do { let this = actor (t) : actor { send_f2 : (shared (Nat, [Nat], {f : Nat; g : Nat}, {#l : Nat; #m : Nat}) -> - async(Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Int})) -> - async () + async (Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Int})) -> + async () }; try { await this.send_f2(f2_0); @@ -131,12 +142,12 @@ actor this { catch e { Prim.debugPrint "wrong_2_0"; } }; - + // several args, contra-co subtyping do { let this = actor (t) : actor { send_f2 : (shared (Int, [Int], {f : Int}, {#l : Int; #m : Int; #o : Int}) -> - async(Nat, [Nat], {f : Nat; g : Nat; h : Nat}, {#l : Nat})) -> + async (Nat, [Nat], {f : Nat; g : Nat; h : Nat}, {#l : Nat})) -> async () }; try { @@ -146,10 +157,22 @@ actor this { }; + // null, opt and any trailing args, defaulting + do { + let this = actor (t) : actor { + send_f3 : + (shared () -> + async (Null, ?None, Any)) -> + async () + }; + try { + await this.send_f3(f3_0); + } + catch e { Prim.debugPrint "wrong_3_0"; } + }; }; - } //SKIP run //SKIP run-ir diff --git a/test/run-drun/ok/idl-sub-default.drun-run.ok b/test/run-drun/ok/idl-sub-default.drun-run.ok index ebc474269a7..a10eda26a67 100644 --- a/test/run-drun/ok/idl-sub-default.drun-run.ok +++ b/test/run-drun/ok/idl-sub-default.drun-run.ok @@ -8,4 +8,5 @@ debug.print: ok debug.print: ok debug.print: ok debug.print: ok +debug.print: ok ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-default.ic-ref-run.ok b/test/run-drun/ok/idl-sub-default.ic-ref-run.ok index b1013e56fb9..85e03181f69 100644 --- a/test/run-drun/ok/idl-sub-default.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-default.ic-ref-run.ok @@ -11,4 +11,5 @@ debug.print: ok debug.print: ok debug.print: ok debug.print: ok +debug.print: ok ← replied: () From 2b8d1b09cdf4ad350dd1e3aa626cccf79c844ee6 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 22 Mar 2022 10:48:02 +0000 Subject: [PATCH 045/128] remove depth argument --- rts/motoko-rts/src/idl.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 98855ac4d39..3a9d698bc6f 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -570,11 +570,7 @@ unsafe fn sub( typtbl2: *mut *mut u8, t1: i32, t2: i32, - depth: i32, ) -> bool { - if depth > 1023 { - idl_trap_with("sub: subtyping too deep"); - } if t1 >= 0 && t2 >= 0 { let t1 = t1 as u32; @@ -653,7 +649,7 @@ unsafe fn sub( (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); - return sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1); + return sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21); } (IDL_CON_func, IDL_CON_func) => { // contra in domain @@ -669,7 +665,7 @@ unsafe fn sub( let t21 = sleb128_decode(&mut tb2); in2 -= 1; // NB: invert p and args! - if !sub(rel, !p, end2, end1, typtbl2, typtbl1, t21, t11, depth + 1) { + if !sub(rel, !p, end2, end1, typtbl2, typtbl1, t21, t11) { return false; } } @@ -690,7 +686,7 @@ unsafe fn sub( } else { let t11 = sleb128_decode(&mut tb1); out1 -= 1; - if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21) { return false; } } @@ -757,7 +753,7 @@ unsafe fn sub( advance = false; // reconsider this field in next round continue; }; - if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21) { return false; } advance = true; @@ -786,7 +782,7 @@ unsafe fn sub( if tag1 != tag2 { return false; }; - if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21) { return false; } } @@ -822,7 +818,7 @@ unsafe fn sub( if !(cmp == 0) { return false; }; - if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21, depth + 1) { + if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21) { return false; } } @@ -883,5 +879,5 @@ unsafe extern "C" fn idl_sub( rel.init(); - return sub(&rel, true, end1, end2, typtbl1, typtbl2, t1, t2, 0); + return sub(&rel, true, end1, end2, typtbl1, typtbl2, t1, t2); } From 164c7deb44aa77132e382cdde87870151b6bd3c3 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 22 Mar 2022 10:50:37 +0000 Subject: [PATCH 046/128] remove dead code --- rts/motoko-rts/src/bitrel.rs | 33 ----------------- rts/motoko-rts/src/idl.rs | 70 ------------------------------------ 2 files changed, 103 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 1447f914db1..e08a4e85cab 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -5,39 +5,6 @@ use crate::idl_trap_with; use crate::mem_utils::memzero; use crate::types::Words; -/* TODO: delete me -#[repr(packed)] -pub struct BitSet { - /// Pointer into the bit set - pub ptr: *mut u8, - /// Pointer to the end of the bit set - pub end: *mut u8, -} - -impl BitSet { - pub(crate) unsafe fn set(self: *mut Self, n: u32) { - let byte = (n / 8) as usize; - let bit = (n % 8) as u8; - let dst = (*self).ptr.add(byte); - if dst > (*self).end { - idl_trap_with("BitSet.set out of bounds"); - }; - *dst = *dst | (1 << bit); - } - - pub(crate) unsafe fn get(self: *mut Self, n: u32) -> bool { - let byte = (n / 8) as usize; - let bit = (n % 8) as u8; - let src = (*self).ptr.add(byte); - if src > (*self).end { - idl_trap_with("BitSet.get out of bounds"); - }; - let mask = 1 << bit; - return *src & mask == mask; - } -} -*/ - #[repr(packed)] pub struct BitRel { /// Pointer into the bit set diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 3a9d698bc6f..c91e0207cf7 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -513,15 +513,6 @@ unsafe extern "C" fn skip_fields(tb: *mut Buf, buf: *mut Buf, typtbl: *mut *mut } } -// TODO: delete me -unsafe fn unfold(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> i32 { - let mut tb = Buf { - ptr: *typtbl.add(t as usize), - end: (*buf).end, - }; - return sleb128_decode(&mut tb); -} - unsafe fn is_null_opt_reserved(end: *mut u8, typtbl: *mut *mut u8, t: i32) -> bool { if is_primitive_type(t) { return t == IDL_PRIM_null || t == IDL_PRIM_reserved; @@ -540,25 +531,6 @@ unsafe fn is_null_opt_reserved(end: *mut u8, typtbl: *mut *mut u8, t: i32) -> bo return t == IDL_CON_opt; } -// TODO: delete me -unsafe fn null_sub(buf: *mut Buf, typtbl: *mut *mut u8, t: i32) -> bool { - if is_primitive_type(t) { - return t == IDL_PRIM_empty || t == IDL_PRIM_null; - } - - // unfold t - let mut t = t; - - let mut tb = Buf { - ptr: *typtbl.add(t as usize), - end: (*buf).end, - }; - - t = sleb128_decode(&mut tb); - - return t == IDL_CON_opt; -} - // https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 // https://github.com/dfinity/candid/blob/20b84d1c1515e2c1db353ebe02b738486f835466/spec/Candid.md unsafe fn sub( @@ -625,26 +597,6 @@ unsafe fn sub( (_, IDL_PRIM_reserved) => true, (IDL_PRIM_empty, _) => true, (IDL_PRIM_nat, IDL_PRIM_int) => true, - /* - (IDL_PRIM_null, IDL_CON_opt) => true, - (IDL_CON_opt, IDL_CON_opt) => { - let t11 = sleb128_decode(&mut tb1); - let t21 = sleb128_decode(&mut tb2); - return sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - }, - (_, IDL_CON_opt) => { - let t21 = sleb128_decode(&mut tb2); - return - !null_sub(buf1, typetbl1, t1) && - !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - }, - (_, IDL_CON_opt) => { - let t21 = sleb128_decode(&mut tb2); - return - !null_sub(buf1, typetbl1, t1) && - !sub(buf1, buf2, typtbl1, typtbl2, t11, t21, depth + 1); - }, - */ (_, IDL_CON_opt) => true, // apparently, this is admissable (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); @@ -829,28 +781,6 @@ unsafe fn sub( } } -// TODO: DELETE -#[no_mangle] -unsafe extern "C" fn table_size(buf: *mut Buf) -> u32 { - let mut buf = Buf { - ptr: (*buf).ptr, - end: (*buf).end, - }; - - if buf.ptr == buf.end { - idl_trap_with( - "empty input. Expected Candid-encoded argument, but received a zero-length argument", - ); - } - - // Magic bytes (DIDL) - if read_word(&mut buf) != 0x4C444944 { - idl_trap_with("missing magic bytes"); - } - - return leb128_decode(&mut buf); -} - #[no_mangle] unsafe extern "C" fn idl_sub_buf_words(n_types1: u32, n_types2: u32) -> u32 { return BitRel::words(n_types1, n_types2); From 465fea550d969af1928be92bb65f2263631dbfde Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 22 Mar 2022 11:06:36 +0000 Subject: [PATCH 047/128] formatting --- rts/motoko-rts/src/idl.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index c91e0207cf7..0008043696a 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -543,7 +543,6 @@ unsafe fn sub( t1: i32, t2: i32, ) -> bool { - if t1 >= 0 && t2 >= 0 { let t1 = t1 as u32; let t2 = t2 as u32; @@ -721,8 +720,8 @@ unsafe fn sub( }; let tag1 = leb128_decode(&mut tb1); let t11 = sleb128_decode(&mut tb1); - let mut tag2 = 0; - let mut t21 = 0; + let mut tag2: u32; + let mut t21: i32; loop { tag2 = leb128_decode(&mut tb2); t21 = sleb128_decode(&mut tb2); @@ -751,10 +750,10 @@ unsafe fn sub( let p2 = tb2.ptr; Buf::advance(&mut tb2, len2); let t21 = sleb128_decode(&mut tb2); - let mut len1 = 0; - let mut p1 = core::ptr::null_mut(); - let mut t11 = 0; - let mut cmp: i32 = 0; + let mut len1: u32; + let mut p1: *mut u8; + let mut t11: i32; + let mut cmp: i32; loop { len1 = leb128_decode(&mut tb1); p1 = tb1.ptr; From eb0faec7a552690d01bbb431df29a861e51c765a Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 22 Mar 2022 11:59:50 +0000 Subject: [PATCH 048/128] refactor, renaming and reordering arguments --- rts/motoko-rts/src/bitrel.rs | 44 ++++++++++++++++----------- rts/motoko-rts/src/idl.rs | 59 +++++++++++++++++++++--------------- src/codegen/compile.ml | 44 +++++++++++++-------------- 3 files changed, 82 insertions(+), 65 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index e08a4e85cab..9a4cd248cee 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -10,36 +10,40 @@ pub struct BitRel { /// Pointer into the bit set pub ptr: *mut u32, /// Pointer to the end of the bit set - /// must allow at least 2 * n * m bits + /// must allow at least 2 * size1 * size2 bits pub end: *mut u32, - pub n: u32, - pub m: u32, + pub size1: u32, + pub size2: u32, } impl BitRel { - pub(crate) unsafe fn words(n_types1: u32, n_types2: u32) -> u32 { - return ((2 * n_types1 * n_types2) + (usize::BITS - 1)) / usize::BITS; + pub(crate) unsafe fn words(size1: u32, size2: u32) -> u32 { + return ((2 * size1 * size2) + (usize::BITS - 1)) / usize::BITS; } pub(crate) unsafe fn init(self: &Self) { let bytes = ((self.end as usize) - (self.ptr as usize)) as u32; - if (self.n * self.m * 2) > bytes * 8 { + if (self.size1 * self.size2 * 2) > bytes * 8 { idl_trap_with("BitRel not enough bytes"); }; memzero(self.ptr as usize, Words(bytes / WORD_SIZE)); } pub(crate) unsafe fn set(self: &Self, p: bool, i_j: u32, j_i: u32) { - let n = self.n; - let m = self.m; - let (base, i, j) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; - if i >= n { + let size1 = self.size1; + let size2 = self.size2; + let (base, i, j) = if p { + (0, i_j, j_i) + } else { + (size1 * size2, j_i, i_j) + }; + if i >= size1 { idl_trap_with("BitRel.set i out of bounds"); }; - if j >= m { + if j >= size2 { idl_trap_with("BitRel.set j out of bounds"); }; - let k = base + i * m + j; + let k = base + i * size2 + j; let word = (k / usize::BITS) as usize; let bit = (k % usize::BITS) as u32; let dst = self.ptr.add(word); @@ -50,16 +54,20 @@ impl BitRel { } pub(crate) unsafe fn get(self: &Self, p: bool, i_j: u32, j_i: u32) -> bool { - let n = self.n; - let m = self.m; - let (base, i, j) = if p { (0, i_j, j_i) } else { (n * m, j_i, i_j) }; - if i >= n { + let size1 = self.size1; + let size2 = self.size2; + let (base, i, j) = if p { + (0, i_j, j_i) + } else { + (size1 * size2, j_i, i_j) + }; + if i >= size1 { idl_trap_with("BitRel.set i out of bounds"); }; - if j >= m { + if j >= size2 { idl_trap_with("BitRel.set j out of bounds"); }; - let k = base + i * m + j; + let k = base + i * size2 + j; let word = (k / usize::BITS) as usize; let bit = (k % usize::BITS) as u32; let src = self.ptr.add(word); diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 0008043696a..12be5e5b88b 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -513,7 +513,7 @@ unsafe extern "C" fn skip_fields(tb: *mut Buf, buf: *mut Buf, typtbl: *mut *mut } } -unsafe fn is_null_opt_reserved(end: *mut u8, typtbl: *mut *mut u8, t: i32) -> bool { +unsafe fn is_null_opt_reserved(typtbl: *mut *mut u8, end: *mut u8, t: i32) -> bool { if is_primitive_type(t) { return t == IDL_PRIM_null || t == IDL_PRIM_reserved; } @@ -536,10 +536,10 @@ unsafe fn is_null_opt_reserved(end: *mut u8, typtbl: *mut *mut u8, t: i32) -> bo unsafe fn sub( rel: &BitRel, p: bool, - end1: *mut u8, - end2: *mut u8, typtbl1: *mut *mut u8, typtbl2: *mut *mut u8, + end1: *mut u8, + end2: *mut u8, t1: i32, t2: i32, ) -> bool { @@ -600,7 +600,7 @@ unsafe fn sub( (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); - return sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21); + return sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21); } (IDL_CON_func, IDL_CON_func) => { // contra in domain @@ -609,14 +609,14 @@ unsafe fn sub( for _ in 0..in1 { let t11 = sleb128_decode(&mut tb1); if in2 == 0 { - if !is_null_opt_reserved(end1, typtbl1, t11) { + if !is_null_opt_reserved(typtbl1, end1, t11) { return false; } } else { let t21 = sleb128_decode(&mut tb2); in2 -= 1; // NB: invert p and args! - if !sub(rel, !p, end2, end1, typtbl2, typtbl1, t21, t11) { + if !sub(rel, !p, typtbl2, typtbl1, end2, end1, t21, t11) { return false; } } @@ -631,13 +631,13 @@ unsafe fn sub( for _ in 0..out2 { let t21 = sleb128_decode(&mut tb2); if out1 == 0 { - if !is_null_opt_reserved(end2, typtbl2, t21) { + if !is_null_opt_reserved(typtbl2, end2, t21) { return false; } } else { let t11 = sleb128_decode(&mut tb1); out1 -= 1; - if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21) { + if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { return false; } } @@ -681,7 +681,7 @@ unsafe fn sub( let t21 = sleb128_decode(&mut tb2); if n1 == 0 { // check all remaining fields optional - if !is_null_opt_reserved(end2, typtbl2, t21) { + if !is_null_opt_reserved(typtbl2, end2, t21) { return false; } continue; @@ -697,14 +697,14 @@ unsafe fn sub( } }; if tag1 > tag2 { - if !is_null_opt_reserved(end2, typtbl2, t21) { + if !is_null_opt_reserved(typtbl2, end2, t21) { // missing, non_opt field return false; } advance = false; // reconsider this field in next round continue; }; - if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21) { + if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { return false; } advance = true; @@ -733,7 +733,7 @@ unsafe fn sub( if tag1 != tag2 { return false; }; - if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21) { + if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { return false; } } @@ -769,7 +769,7 @@ unsafe fn sub( if !(cmp == 0) { return false; }; - if !sub(rel, p, end1, end2, typtbl1, typtbl2, t11, t21) { + if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { return false; } } @@ -787,26 +787,35 @@ unsafe extern "C" fn idl_sub_buf_words(n_types1: u32, n_types2: u32) -> u32 { #[no_mangle] unsafe extern "C" fn idl_sub( - rel_buf: *mut u32, // a buffer with at least 2 * n * m bits - end1: *mut u8, - end2: *mut u8, - n_types1: u32, - n_types2: u32, - typtbl1: *mut *mut u8, // of len n_types1 - typtbl2: *mut *mut u8, // of len n_types2 + rel_buf: *mut u32, // a buffer with at least 2 * typtbl_size1 * typtbl_size2 bits + typtbl1: *mut *mut u8, + typtbl2: *mut *mut u8, + typtbl_end1: *mut u8, + typtbl_end2: *mut u8, + typtbl_size1: u32, + typtbl_size2: u32, t1: i32, t2: i32, ) -> bool { let rel = BitRel { ptr: rel_buf, - end: rel_buf.add(idl_sub_buf_words(n_types1, n_types2) as usize), - n: n_types1, - m: n_types2, + end: rel_buf.add(idl_sub_buf_words(typtbl_size1, typtbl_size2) as usize), + size1: typtbl_size1, + size2: typtbl_size2, }; - debug_assert!(t1 < (n_types1 as i32) && t2 < (n_types2 as i32)); + debug_assert!(t1 < (typtbl_size1 as i32) && t2 < (typtbl_size2 as i32)); rel.init(); - return sub(&rel, true, end1, end2, typtbl1, typtbl2, t1, t2); + return sub( + &rel, + true, + typtbl1, + typtbl2, + typtbl_end1, + typtbl_end2, + t1, + t2, + ); } diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 4f21f73823f..af06d6185af 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -4808,18 +4808,18 @@ module Serialization = struct let idl_sub env t2 = Func.share_code4 env ("idl_sub<" ^ typ_hash t2 ^ ">") - (("get_end1", I32Type), - ("n_types1", I32Type), - ("typtbl1", I32Type), + (("typtbl1", I32Type), + ("typtbl_end1", I32Type), + ("typtbl_size1", I32Type), ("idltyp1", I32Type) ) [I32Type] - (fun env get_end1 get_n_types1 get_typtbl1 get_idltyp1 -> + (fun env get_typtbl1 get_typtbl_end1 get_typtbl_size1 get_idltyp1 -> let typdesc, offsets, idltyps2 = type_desc env [t2] in let idltyp2 = List.hd idltyps2 in - let (set_end2, get_end2) = new_local env "end2" in - let (set_n_types2, get_n_types2) = new_local env "n_types2" in let (set_typtbl2, get_typtbl2) = new_local env "typetbl2" in + let (set_typtbl_end2, get_typtbl_end2) = new_local env "typtbl_end2" in + let (set_typtbl_size2, get_typtbl_size2) = new_local env "typtbl_size2" in let (set_idltyp2, get_idltyp2) = new_local env "idltyp2" in let static_typedesc = Int32.(add (Blob.vanilla_lit env typdesc) Blob.unskewed_payload_offset) @@ -4838,20 +4838,20 @@ module Serialization = struct Int32.add (Blob.vanilla_lit env tbl2) Blob.unskewed_payload_offset in compile_unboxed_const Int32.(add static_typedesc (of_int (String.length typdesc))) - ^^ set_end2 ^^ - compile_unboxed_const (Int32.of_int (List.length offsets)) ^^ set_n_types2 ^^ + ^^ set_typtbl_end2 ^^ + compile_unboxed_const (Int32.of_int (List.length offsets)) ^^ set_typtbl_size2 ^^ compile_unboxed_const static_typtbl2 ^^ set_typtbl2 ^^ compile_unboxed_const idltyp2 ^^ set_idltyp2 ^^ - get_n_types1 ^^ get_n_types2 ^^ + get_typtbl_size1 ^^ get_typtbl_size2 ^^ E.call_import env "rts" "idl_sub_buf_words" ^^ Stack.dynamic_with_words env "rel_buf" (fun get_rel_buf_ptr -> get_rel_buf_ptr ^^ - get_end1 ^^ - get_end2 ^^ - get_n_types1 ^^ - get_n_types2 ^^ get_typtbl1 ^^ get_typtbl2 ^^ + get_typtbl_end1 ^^ + get_typtbl_end2 ^^ + get_typtbl_size1 ^^ + get_typtbl_size2 ^^ get_idltyp1 ^^ get_idltyp2 ^^ E.call_import env "rts" "idl_sub")) @@ -4864,14 +4864,14 @@ module Serialization = struct (("extended", I32Type), ("data_buffer", I32Type), ("ref_buffer", I32Type), - ("typtbl_end", I32Type), ("typtbl", I32Type), - ("idltyp", I32Type), + ("typtbl_end", I32Type), ("typtbl_size", I32Type), + ("idltyp", I32Type), ("depth", I32Type), ("can_recover", I32Type) ) [I32Type] - (fun env get_extended get_data_buf get_ref_buf get_typtbl_end get_typtbl get_idltyp get_typtbl_size get_depth get_can_recover -> + (fun env get_extended get_data_buf get_ref_buf get_typtbl get_typtbl_end get_typtbl_size get_idltyp get_depth get_can_recover -> (* Check recursion depth (protects against empty record etc.) *) (* Factor 2 because at each step, the expected type could go through one @@ -4892,10 +4892,10 @@ module Serialization = struct get_extended ^^ get_data_buf ^^ get_ref_buf ^^ - get_typtbl_end ^^ get_typtbl ^^ - get_idlty ^^ + get_typtbl_end ^^ get_typtbl_size ^^ + get_idlty ^^ ( (* Reset depth counter if we made progress *) ReadBuf.get_ptr get_data_buf ^^ get_old_pos ^^ G.i (Compare (Wasm.Values.I32 I32Op.Eq)) ^^ @@ -5436,9 +5436,9 @@ module Serialization = struct G.if1 I32Type (compile_unboxed_const 1l) (begin + get_typtbl ^^ get_typtbl_end ^^ get_typtbl_size ^^ - get_typtbl ^^ get_idltyp ^^ idl_sub env t end) ^^ @@ -5456,9 +5456,9 @@ module Serialization = struct G.if1 I32Type (compile_unboxed_const 1l) (begin + get_typtbl ^^ get_typtbl_end ^^ get_typtbl_size ^^ - get_typtbl ^^ get_idltyp ^^ idl_sub env t end) ^^ @@ -5602,10 +5602,10 @@ module Serialization = struct (begin compile_unboxed_const (if extended then 1l else 0l) ^^ get_data_buf ^^ get_ref_buf ^^ - get_maintyps_ptr ^^ load_unskewed_ptr ^^ (* typtbl_end *) get_typtbl_ptr ^^ load_unskewed_ptr ^^ - ReadBuf.read_sleb128 env get_main_typs_buf ^^ + get_maintyps_ptr ^^ load_unskewed_ptr ^^ (* typtbl_end *) get_typtbl_size_ptr ^^ load_unskewed_ptr ^^ + ReadBuf.read_sleb128 env get_main_typs_buf ^^ compile_unboxed_const 0l ^^ (* initial depth *) can_recover ^^ deserialize_go env t ^^ set_val ^^ From fc2bb2852edc5fe6a932d4a3a7a4506d920e3ce1 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 23 Mar 2022 11:43:03 +0000 Subject: [PATCH 049/128] create and use global typtbl --- src/codegen/compile.ml | 109 ++++++++++++++++++++++++++++------------- 1 file changed, 74 insertions(+), 35 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index af06d6185af..1fb84302d5d 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -257,6 +257,8 @@ module E = struct (* Sanity check: Nothing should bump end_of_static_memory once it has been read *) static_roots : int32 list ref; (* GC roots in static memory. (Everything that may be mutable.) *) + typtbl_typs : Type.typ list ref; + (* Types accumulated in global typtbl (for candid subtype checks *) (* Metadata *) args : (bool * string) option ref; @@ -265,7 +267,6 @@ module E = struct labs : LabSet.t ref; (* Used labels (fields and variants), collected for Motoko custom section 0 *) - (* Local fields (only valid/used inside a function) *) (* Static *) n_param : int32; (* Number of parameters (to calculate indices of locals) *) @@ -298,6 +299,7 @@ module E = struct static_memory = ref []; static_memory_frozen = ref false; static_roots = ref []; + typtbl_typs = ref []; (* Metadata *) args = ref None; service = ref None; @@ -4240,6 +4242,23 @@ module Serialization = struct by the next GC. *) + let register_delayed_globals env = + (E.add_global32_delayed env "__typtbl" Immutable, + E.add_global32_delayed env "__typtbl_size" Immutable, + E.add_global32_delayed env "__typtbl_end" Immutable, + E.add_global32_delayed env "__typtbl_idltyps" Immutable) + + + let get_typtbl env = + G.i (GlobalGet (nr (E.get_global env "__typtbl"))) + let get_typtbl_size env = + G.i (GlobalGet (nr (E.get_global env "__typtbl_size"))) + let get_typtbl_end env = + G.i (GlobalGet (nr (E.get_global env "__typtbl_end"))) + let get_typtbl_idltyps env = + G.i (GlobalGet (nr (E.get_global env "__typtbl_idltyps"))) + + open Typ_hash let sort_by_hash fs = @@ -4444,6 +4463,41 @@ module Serialization = struct offsets, List.map idx ts) + let set_delayed_globals (env : E.t) (set_typtbl, set_typtbl_end, set_typtbl_size, set_typtbl_idltyps) = + let typdesc, offsets, idltyps = type_desc env (!(env.E.typtbl_typs)) in + let static_typedesc = + Int32.(add (Blob.vanilla_lit env typdesc) Blob.unskewed_payload_offset) + in + let tbl = + let buf = Buffer.create (List.length offsets * 4) in + begin + List.iter (fun offset -> + Buffer.add_int32_le buf + Int32.(add static_typedesc (of_int(offset)))) + offsets; + Buffer.contents buf + end + in + let static_typtbl = + Int32.add (Blob.vanilla_lit env tbl) Blob.unskewed_payload_offset + in + let static_idltyps = + let buf = Buffer.create (List.length idltyps * 4) in + begin + List.iter (fun idltyp -> + Buffer.add_int32_le buf idltyp) + idltyps; + Buffer.contents buf + end + in + let static_idltyps = + Int32.add (Blob.vanilla_lit env static_idltyps) Blob.unskewed_payload_offset + in + set_typtbl static_typtbl; + set_typtbl_end Int32.(add static_typedesc (of_int (String.length typdesc))); + set_typtbl_size (Int32.of_int (List.length offsets)); + set_typtbl_idltyps static_idltyps + (* Returns data (in bytes) and reference buffer size (in entries) needed *) let rec buffer_size env t = let open Type in @@ -4807,7 +4861,9 @@ module Serialization = struct *) let idl_sub env t2 = - Func.share_code4 env ("idl_sub<" ^ typ_hash t2 ^ ">") + let idx = List.length (!(env.E.typtbl_typs)) in + env.E.typtbl_typs := !(env.E.typtbl_typs) @ [t2]; + Func.share_code4 env ("idl_sub_"^Int.to_string idx) (* TODO FIX ME *) (("typtbl1", I32Type), ("typtbl_end1", I32Type), ("typtbl_size1", I32Type), @@ -4815,43 +4871,21 @@ module Serialization = struct ) [I32Type] (fun env get_typtbl1 get_typtbl_end1 get_typtbl_size1 get_idltyp1 -> - let typdesc, offsets, idltyps2 = type_desc env [t2] in - let idltyp2 = List.hd idltyps2 in - let (set_typtbl2, get_typtbl2) = new_local env "typetbl2" in - let (set_typtbl_end2, get_typtbl_end2) = new_local env "typtbl_end2" in - let (set_typtbl_size2, get_typtbl_size2) = new_local env "typtbl_size2" in let (set_idltyp2, get_idltyp2) = new_local env "idltyp2" in - let static_typedesc = - Int32.(add (Blob.vanilla_lit env typdesc) Blob.unskewed_payload_offset) - in - let tbl2 = - let buf = Buffer.create (List.length offsets * 4) in - begin - List.iter (fun offset -> - Buffer.add_int32_le buf - Int32.(add static_typedesc (of_int(offset)))) - offsets; - Buffer.contents buf - end - in - let static_typtbl2 = - Int32.add (Blob.vanilla_lit env tbl2) Blob.unskewed_payload_offset - in - compile_unboxed_const Int32.(add static_typedesc (of_int (String.length typdesc))) - ^^ set_typtbl_end2 ^^ - compile_unboxed_const (Int32.of_int (List.length offsets)) ^^ set_typtbl_size2 ^^ - compile_unboxed_const static_typtbl2 ^^ set_typtbl2 ^^ - compile_unboxed_const idltyp2 ^^ set_idltyp2 ^^ - get_typtbl_size1 ^^ get_typtbl_size2 ^^ + get_typtbl_idltyps env ^^ + compile_add_const (Int32.of_int (idx*4)) ^^ + G.i (Load {ty = I32Type; align = 0; offset = 0l; sz = None}) ^^ + set_idltyp2 ^^ + get_typtbl_size1 ^^ get_typtbl_size env ^^ E.call_import env "rts" "idl_sub_buf_words" ^^ Stack.dynamic_with_words env "rel_buf" (fun get_rel_buf_ptr -> get_rel_buf_ptr ^^ get_typtbl1 ^^ - get_typtbl2 ^^ + get_typtbl env ^^ get_typtbl_end1 ^^ - get_typtbl_end2 ^^ + get_typtbl_end env ^^ get_typtbl_size1 ^^ - get_typtbl_size2 ^^ + get_typtbl_size env ^^ get_idltyp1 ^^ get_idltyp2 ^^ E.call_import env "rts" "idl_sub")) @@ -5711,7 +5745,8 @@ To detect and preserve aliasing, these steps are taken: after checking the type hash field to make sure we are aliasing at the same type. -*) + *) + end (* Serialization *) @@ -9175,10 +9210,12 @@ and main_actor as_opt mod_env ds fs up = decls_codeW G.nop ) -and conclude_module env start_fi_o = +and conclude_module env set_serialization_globals start_fi_o = FuncDec.export_async_method env; + Serialization.set_delayed_globals env set_serialization_globals; + let static_roots = GC.store_static_roots env in (* declare before building GC *) @@ -9275,6 +9312,8 @@ let compile mode rts (prog : Ir.prog) : Wasm_exts.CustomModule.extended_module = Stack.register_globals env; StableMem.register_globals env; + let set_serialization_globals = Serialization.register_delayed_globals env in + IC.system_imports env; RTS.system_imports env; RTS_Exports.system_exports env; @@ -9291,4 +9330,4 @@ let compile mode rts (prog : Ir.prog) : Wasm_exts.CustomModule.extended_module = Some (nr (E.built_in env "init")) in - conclude_module env start_fi_o + conclude_module env set_serialization_globals start_fi_o From b2b1d9362e18d70dd271d14a50ea0c72cd8aa9fa Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 23 Mar 2022 16:03:35 +0000 Subject: [PATCH 050/128] fix silly bug --- src/codegen/compile.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 1fb84302d5d..45e34859177 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -4244,8 +4244,8 @@ module Serialization = struct let register_delayed_globals env = (E.add_global32_delayed env "__typtbl" Immutable, - E.add_global32_delayed env "__typtbl_size" Immutable, E.add_global32_delayed env "__typtbl_end" Immutable, + E.add_global32_delayed env "__typtbl_size" Immutable, E.add_global32_delayed env "__typtbl_idltyps" Immutable) From f091758e19f06483afef0eed3a8560302159bfdd Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 23 Mar 2022 16:56:29 +0000 Subject: [PATCH 051/128] share idl_sub properly --- src/codegen/compile.ml | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 45e34859177..da0e39d0345 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -760,13 +760,21 @@ module Func = struct (G.i (LocalGet (nr 1l))) (G.i (LocalGet (nr 2l))) ) - let share_code4 env name (p1, p2, p3, p4) retty mk_body = + let _share_code4 env name (p1, p2, p3, p4) retty mk_body = share_code env name [p1; p2; p3; p4] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) (G.i (LocalGet (nr 1l))) (G.i (LocalGet (nr 2l))) (G.i (LocalGet (nr 3l))) ) + let share_code5 env name (p1, p2, p3, p4, p5) retty mk_body = + share_code env name [p1; p2; p3; p4; p5] retty (fun env -> mk_body env + (G.i (LocalGet (nr 0l))) + (G.i (LocalGet (nr 1l))) + (G.i (LocalGet (nr 2l))) + (G.i (LocalGet (nr 3l))) + (G.i (LocalGet (nr 4l))) + ) let _share_code6 env name (p1, p2, p3, p4, p5, p6) retty mk_body = share_code env name [p1; p2; p3; p4; p5; p6] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) @@ -4863,19 +4871,18 @@ module Serialization = struct let idl_sub env t2 = let idx = List.length (!(env.E.typtbl_typs)) in env.E.typtbl_typs := !(env.E.typtbl_typs) @ [t2]; - Func.share_code4 env ("idl_sub_"^Int.to_string idx) (* TODO FIX ME *) + get_typtbl_idltyps env ^^ + compile_add_const (Int32.of_int (idx * 4)) ^^ + G.i (Load {ty = I32Type; align = 0; offset = 0l; sz = None}) ^^ + Func.share_code5 env ("idl_sub") (("typtbl1", I32Type), ("typtbl_end1", I32Type), ("typtbl_size1", I32Type), - ("idltyp1", I32Type) + ("idltyp1", I32Type), + ("idltyp2", I32Type) ) [I32Type] - (fun env get_typtbl1 get_typtbl_end1 get_typtbl_size1 get_idltyp1 -> - let (set_idltyp2, get_idltyp2) = new_local env "idltyp2" in - get_typtbl_idltyps env ^^ - compile_add_const (Int32.of_int (idx*4)) ^^ - G.i (Load {ty = I32Type; align = 0; offset = 0l; sz = None}) ^^ - set_idltyp2 ^^ + (fun env get_typtbl1 get_typtbl_end1 get_typtbl_size1 get_idltyp1 get_idltyp2 -> get_typtbl_size1 ^^ get_typtbl_size env ^^ E.call_import env "rts" "idl_sub_buf_words" ^^ Stack.dynamic_with_words env "rel_buf" (fun get_rel_buf_ptr -> From 99c8e18f2738d988f8cc9224e42b0db55bbfb469 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 24 Mar 2022 14:52:51 +0000 Subject: [PATCH 052/128] extend bitrel with visited bits; store both positive and negative results --- rts/motoko-rts/src/bitrel.rs | 34 ++++++++++++++------- rts/motoko-rts/src/idl.rs | 59 +++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 9a4cd248cee..f46a12cbc1a 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -5,6 +5,8 @@ use crate::idl_trap_with; use crate::mem_utils::memzero; use crate::types::Words; +const BITS: u32 = 2; + #[repr(packed)] pub struct BitRel { /// Pointer into the bit set @@ -18,24 +20,24 @@ pub struct BitRel { impl BitRel { pub(crate) unsafe fn words(size1: u32, size2: u32) -> u32 { - return ((2 * size1 * size2) + (usize::BITS - 1)) / usize::BITS; + return ((2 * size1 * size2 * BITS) + (usize::BITS - 1)) / usize::BITS; } pub(crate) unsafe fn init(self: &Self) { let bytes = ((self.end as usize) - (self.ptr as usize)) as u32; - if (self.size1 * self.size2 * 2) > bytes * 8 { + if (2 * self.size1 * self.size2 * BITS) > bytes * 8 { idl_trap_with("BitRel not enough bytes"); }; memzero(self.ptr as usize, Words(bytes / WORD_SIZE)); } - pub(crate) unsafe fn set(self: &Self, p: bool, i_j: u32, j_i: u32) { + pub(crate) unsafe fn set(self: &Self, p: bool, i_j: u32, j_i: u32, bit: u32, v: bool) { let size1 = self.size1; let size2 = self.size2; let (base, i, j) = if p { (0, i_j, j_i) } else { - (size1 * size2, j_i, i_j) + (size1 * size2 * BITS, j_i, i_j) }; if i >= size1 { idl_trap_with("BitRel.set i out of bounds"); @@ -43,31 +45,41 @@ impl BitRel { if j >= size2 { idl_trap_with("BitRel.set j out of bounds"); }; - let k = base + i * size2 + j; + if bit >= BITS { + idl_trap_with("BitRel.set bit out of bounds"); + }; + let k = base + i * size2 * BITS + j + bit; let word = (k / usize::BITS) as usize; let bit = (k % usize::BITS) as u32; let dst = self.ptr.add(word); if dst > self.end { idl_trap_with("BitRel.set out of bounds"); }; - *dst = *dst | (1 << bit); + if v { + *dst = *dst | (1 << bit); + } else { + *dst = *dst & !(1 << bit); + } } - pub(crate) unsafe fn get(self: &Self, p: bool, i_j: u32, j_i: u32) -> bool { + pub(crate) unsafe fn get(self: &Self, p: bool, i_j: u32, j_i: u32, bit: u32) -> bool { let size1 = self.size1; let size2 = self.size2; let (base, i, j) = if p { (0, i_j, j_i) } else { - (size1 * size2, j_i, i_j) + (size1 * size2 * BITS, j_i, i_j) }; if i >= size1 { - idl_trap_with("BitRel.set i out of bounds"); + idl_trap_with("BitRel.get i out of bounds"); }; if j >= size2 { - idl_trap_with("BitRel.set j out of bounds"); + idl_trap_with("BitRel.get j out of bounds"); + }; + if bit >= BITS { + idl_trap_with("BitRel.get bit out of bounds"); }; - let k = base + i * size2 + j; + let k = base + i * size2 * BITS + j + bit; let word = (k / usize::BITS) as usize; let bit = (k % usize::BITS) as u32; let src = self.ptr.add(word); diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 12be5e5b88b..c0200da9d02 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -546,18 +546,15 @@ unsafe fn sub( if t1 >= 0 && t2 >= 0 { let t1 = t1 as u32; let t2 = t2 as u32; - if rel.get(p, t1, t2) { + if rel.get(p, t1, t2, 0) { // cached: succeed! - return true; + return rel.get(p, t1, t2, 1); }; // cache and continue - rel.set(p, t1, t2); + rel.set(p, t1, t2, 0, true); // mark visited + rel.set(p, t1, t2, 1, true); // assume true }; - // re-declare as mut for any unfolding - let mut t1 = t1; - let mut t2 = t2; - /* primitives reflexive */ if is_primitive_type(t1) && is_primitive_type(t2) && t1 == t2 { return true; @@ -573,8 +570,10 @@ unsafe fn sub( end: end1, }; - if t1 >= 0 { - t1 = sleb128_decode(&mut tb1); + let u1 = if t1 >= 0 { + sleb128_decode(&mut tb1) + } else { + t1 }; // unfold t2, if necessary @@ -587,11 +586,13 @@ unsafe fn sub( end: end2, }; - if t2 >= 0 { - t2 = sleb128_decode(&mut tb2); + let u2 = if t2 >= 0 { + sleb128_decode(&mut tb2) + } else { + t2 }; - match (t1, t2) { + match (u1, u2) { (_, IDL_CON_alias) | (IDL_CON_alias, _) => idl_trap_with("sub: unexpected alias"), (_, IDL_PRIM_reserved) => true, (IDL_PRIM_empty, _) => true, @@ -600,7 +601,12 @@ unsafe fn sub( (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); - return sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21); + if sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + return true; + } else { + rel.set(p, t1 as u32, t2 as u32, 1, false); + return false; + } } (IDL_CON_func, IDL_CON_func) => { // contra in domain @@ -610,6 +616,7 @@ unsafe fn sub( let t11 = sleb128_decode(&mut tb1); if in2 == 0 { if !is_null_opt_reserved(typtbl1, end1, t11) { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; } } else { @@ -617,6 +624,7 @@ unsafe fn sub( in2 -= 1; // NB: invert p and args! if !sub(rel, !p, typtbl2, typtbl1, end2, end1, t21, t11) { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; } } @@ -632,12 +640,14 @@ unsafe fn sub( let t21 = sleb128_decode(&mut tb2); if out1 == 0 { if !is_null_opt_reserved(typtbl2, end2, t21) { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; } } else { let t11 = sleb128_decode(&mut tb1); out1 -= 1; if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; } } @@ -668,7 +678,12 @@ unsafe fn sub( _ => {} } } - return (a11 == a21) && (a12 == a22); + if (a11 == a21) && (a12 == a22) { + return true; + } else { + rel.set(p, t1 as u32, t2 as u32, 1, false); + return false; + } } (IDL_CON_record, IDL_CON_record) => { let mut n1 = leb128_decode(&mut tb1); @@ -682,6 +697,7 @@ unsafe fn sub( if n1 == 0 { // check all remaining fields optional if !is_null_opt_reserved(typtbl2, end2, t21) { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; } continue; @@ -699,12 +715,14 @@ unsafe fn sub( if tag1 > tag2 { if !is_null_opt_reserved(typtbl2, end2, t21) { // missing, non_opt field + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; } advance = false; // reconsider this field in next round continue; }; if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; } advance = true; @@ -716,6 +734,7 @@ unsafe fn sub( let mut n2 = leb128_decode(&mut tb2); for _ in 0..n1 { if n2 == 0 { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; }; let tag1 = leb128_decode(&mut tb1); @@ -731,9 +750,11 @@ unsafe fn sub( } } if tag1 != tag2 { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; }; if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; } } @@ -744,6 +765,7 @@ unsafe fn sub( let n2 = leb128_decode(&mut tb2); for _ in 0..n2 { if n1 == 0 { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; }; let len2 = leb128_decode(&mut tb2); @@ -767,16 +789,23 @@ unsafe fn sub( break; } if !(cmp == 0) { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; }; if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + rel.set(p, t1 as u32, t2 as u32, 1, false); return false; } } return true; } // default - (_, _) => false, + (_, _) => { + if t1 >= 0 && t2 >= 0 { + rel.set(p, t1 as u32, t2 as u32, 1, false); + } + return false; + } } } From 58e2a9b0c6431209789773f74fa937cf516660fd Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 24 Mar 2022 17:32:38 +0000 Subject: [PATCH 053/128] refactor --- rts/motoko-rts/src/bitrel.rs | 61 +++++++++++++++--------------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index f46a12cbc1a..179c6f598fc 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -19,11 +19,11 @@ pub struct BitRel { } impl BitRel { - pub(crate) unsafe fn words(size1: u32, size2: u32) -> u32 { + pub(crate) fn words(size1: u32, size2: u32) -> u32 { return ((2 * size1 * size2 * BITS) + (usize::BITS - 1)) / usize::BITS; } - pub(crate) unsafe fn init(self: &Self) { + pub(crate) unsafe fn init(&self) { let bytes = ((self.end as usize) - (self.ptr as usize)) as u32; if (2 * self.size1 * self.size2 * BITS) > bytes * 8 { idl_trap_with("BitRel not enough bytes"); @@ -31,7 +31,13 @@ impl BitRel { memzero(self.ptr as usize, Words(bytes / WORD_SIZE)); } - pub(crate) unsafe fn set(self: &Self, p: bool, i_j: u32, j_i: u32, bit: u32, v: bool) { + unsafe fn locate_ptr_bit( + self: &Self, + p: bool, + i_j: u32, + j_i: u32, + bit: u32, + ) -> (*mut u32, u32) { let size1 = self.size1; let size2 = self.size2; let (base, i, j) = if p { @@ -40,53 +46,36 @@ impl BitRel { (size1 * size2 * BITS, j_i, i_j) }; if i >= size1 { - idl_trap_with("BitRel.set i out of bounds"); + idl_trap_with("BitRel i out of bounds"); }; if j >= size2 { - idl_trap_with("BitRel.set j out of bounds"); + idl_trap_with("BitRel j out of bounds"); }; if bit >= BITS { - idl_trap_with("BitRel.set bit out of bounds"); + idl_trap_with("BitRel bit out of bounds"); }; let k = base + i * size2 * BITS + j + bit; let word = (k / usize::BITS) as usize; let bit = (k % usize::BITS) as u32; - let dst = self.ptr.add(word); - if dst > self.end { - idl_trap_with("BitRel.set out of bounds"); + let ptr = self.ptr.add(word); + if ptr > self.end { + idl_trap_with("BitRel ptr out of bounds"); }; + return (ptr, bit); + } + + pub(crate) unsafe fn set(&self, p: bool, i_j: u32, j_i: u32, bit: u32, v: bool) { + let (ptr, bit) = self.locate_ptr_bit(p, i_j, j_i, bit); if v { - *dst = *dst | (1 << bit); + *ptr = *ptr | (1 << bit); } else { - *dst = *dst & !(1 << bit); + *ptr = *ptr & !(1 << bit); } } - pub(crate) unsafe fn get(self: &Self, p: bool, i_j: u32, j_i: u32, bit: u32) -> bool { - let size1 = self.size1; - let size2 = self.size2; - let (base, i, j) = if p { - (0, i_j, j_i) - } else { - (size1 * size2 * BITS, j_i, i_j) - }; - if i >= size1 { - idl_trap_with("BitRel.get i out of bounds"); - }; - if j >= size2 { - idl_trap_with("BitRel.get j out of bounds"); - }; - if bit >= BITS { - idl_trap_with("BitRel.get bit out of bounds"); - }; - let k = base + i * size2 * BITS + j + bit; - let word = (k / usize::BITS) as usize; - let bit = (k % usize::BITS) as u32; - let src = self.ptr.add(word); - if src > self.end { - idl_trap_with("BitRel.get out of bounds"); - }; + pub(crate) unsafe fn get(&self, p: bool, i_j: u32, j_i: u32, bit: u32) -> bool { + let (ptr, bit) = self.locate_ptr_bit(p, i_j, j_i, bit); let mask = 1 << bit; - return *src & mask == mask; + return *ptr & mask == mask; } } From 6b1431fae03fade6442a8c64f796a15f5f763797 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 24 Mar 2022 18:14:41 +0000 Subject: [PATCH 054/128] use a labeled (trivial) loop to factor out the common failure continuation that memoized the false result --- rts/motoko-rts/src/idl.rs | 365 +++++++++++++++++++------------------- 1 file changed, 178 insertions(+), 187 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index c0200da9d02..4325ea15f80 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -592,221 +592,212 @@ unsafe fn sub( t2 }; - match (u1, u2) { - (_, IDL_CON_alias) | (IDL_CON_alias, _) => idl_trap_with("sub: unexpected alias"), - (_, IDL_PRIM_reserved) => true, - (IDL_PRIM_empty, _) => true, - (IDL_PRIM_nat, IDL_PRIM_int) => true, - (_, IDL_CON_opt) => true, // apparently, this is admissable - (IDL_CON_vec, IDL_CON_vec) => { - let t11 = sleb128_decode(&mut tb1); - let t21 = sleb128_decode(&mut tb2); - if sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { - return true; - } else { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - } - } - (IDL_CON_func, IDL_CON_func) => { - // contra in domain - let in1 = leb128_decode(&mut tb1); - let mut in2 = leb128_decode(&mut tb2); - for _ in 0..in1 { + // exit either via 'return true' or 'break 'return_false' to memoize the negative result + 'return_false: loop { + match (u1, u2) { + (_, IDL_CON_alias) | (IDL_CON_alias, _) => idl_trap_with("sub: unexpected alias"), + (_, IDL_PRIM_reserved) => return true, + (IDL_PRIM_empty, _) => return true, + (IDL_PRIM_nat, IDL_PRIM_int) => return true, + (_, IDL_CON_opt) => return true, // apparently, this is admissable + (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); - if in2 == 0 { - if !is_null_opt_reserved(typtbl1, end1, t11) { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - } + let t21 = sleb128_decode(&mut tb2); + if sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + return true; } else { - let t21 = sleb128_decode(&mut tb2); - in2 -= 1; - // NB: invert p and args! - if !sub(rel, !p, typtbl2, typtbl1, end2, end1, t21, t11) { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - } + break 'return_false; } } - while in2 > 0 { - let _ = sleb128_decode(&mut tb2); - in2 -= 1; - } - // co in range - let mut out1 = leb128_decode(&mut tb1); - let out2 = leb128_decode(&mut tb2); - for _ in 0..out2 { - let t21 = sleb128_decode(&mut tb2); - if out1 == 0 { - if !is_null_opt_reserved(typtbl2, end2, t21) { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - } - } else { + (IDL_CON_func, IDL_CON_func) => { + // contra in domain + let in1 = leb128_decode(&mut tb1); + let mut in2 = leb128_decode(&mut tb2); + for _ in 0..in1 { let t11 = sleb128_decode(&mut tb1); + if in2 == 0 { + if !is_null_opt_reserved(typtbl1, end1, t11) { + break 'return_false; + } + } else { + let t21 = sleb128_decode(&mut tb2); + in2 -= 1; + // NB: invert p and args! + if !sub(rel, !p, typtbl2, typtbl1, end2, end1, t21, t11) { + break 'return_false; + } + } + } + while in2 > 0 { + let _ = sleb128_decode(&mut tb2); + in2 -= 1; + } + // co in range + let mut out1 = leb128_decode(&mut tb1); + let out2 = leb128_decode(&mut tb2); + for _ in 0..out2 { + let t21 = sleb128_decode(&mut tb2); + if out1 == 0 { + if !is_null_opt_reserved(typtbl2, end2, t21) { + break 'return_false; + } + } else { + let t11 = sleb128_decode(&mut tb1); + out1 -= 1; + if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + break 'return_false; + } + } + } + while out1 > 0 { + let _ = sleb128_decode(&mut tb1); out1 -= 1; - if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; + } + // check annotations (that we care about) + // TODO: more generally, we would check equality of 256-bit bit-vectors, + // but validity ensures each entry is 1 or 2 (for now) + // c.f. https://github.com/dfinity/candid/issues/318 + let mut a11 = false; + let mut a12 = false; + for _ in 0..leb128_decode(&mut tb1) { + match read_byte(&mut tb1) { + 1 => a11 = true, + 2 => a12 = true, + _ => {} } } - } - while out1 > 0 { - let _ = sleb128_decode(&mut tb1); - out1 -= 1; - } - // check annotations (that we care about) - // TODO: more generally, we would check equality of 256-bit bit-vectors, - // but validity ensures each entry is 1 or 2 (for now) - // c.f. https://github.com/dfinity/candid/issues/318 - let mut a11 = false; - let mut a12 = false; - for _ in 0..leb128_decode(&mut tb1) { - match read_byte(&mut tb1) { - 1 => a11 = true, - 2 => a12 = true, - _ => {} + let mut a21 = false; + let mut a22 = false; + for _ in 0..leb128_decode(&mut tb2) { + match read_byte(&mut tb2) { + 1 => a21 = true, + 2 => a22 = true, + _ => {} + } } - } - let mut a21 = false; - let mut a22 = false; - for _ in 0..leb128_decode(&mut tb2) { - match read_byte(&mut tb2) { - 1 => a21 = true, - 2 => a22 = true, - _ => {} + if (a11 == a21) && (a12 == a22) { + return true; + } else { + break 'return_false; } } - if (a11 == a21) && (a12 == a22) { + (IDL_CON_record, IDL_CON_record) => { + let mut n1 = leb128_decode(&mut tb1); + let n2 = leb128_decode(&mut tb2); + let mut tag1 = 0; + let mut t11 = 0; + let mut advance = true; + for _ in 0..n2 { + let tag2 = leb128_decode(&mut tb2); + let t21 = sleb128_decode(&mut tb2); + if n1 == 0 { + // check all remaining fields optional + if !is_null_opt_reserved(typtbl2, end2, t21) { + break 'return_false; + } + continue; + }; + if advance { + loop { + tag1 = leb128_decode(&mut tb1); + t11 = sleb128_decode(&mut tb1); + n1 -= 1; + if !(tag1 < tag2 && n1 > 0) { + break; + } + } + }; + if tag1 > tag2 { + if !is_null_opt_reserved(typtbl2, end2, t21) { + // missing, non_opt field + break 'return_false; + } + advance = false; // reconsider this field in next round + continue; + }; + if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + break 'return_false; + } + advance = true; + } return true; - } else { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; } - } - (IDL_CON_record, IDL_CON_record) => { - let mut n1 = leb128_decode(&mut tb1); - let n2 = leb128_decode(&mut tb2); - let mut tag1 = 0; - let mut t11 = 0; - let mut advance = true; - for _ in 0..n2 { - let tag2 = leb128_decode(&mut tb2); - let t21 = sleb128_decode(&mut tb2); - if n1 == 0 { - // check all remaining fields optional - if !is_null_opt_reserved(typtbl2, end2, t21) { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - } - continue; - }; - if advance { + (IDL_CON_variant, IDL_CON_variant) => { + let n1 = leb128_decode(&mut tb1); + let mut n2 = leb128_decode(&mut tb2); + for _ in 0..n1 { + if n2 == 0 { + break 'return_false; + }; + let tag1 = leb128_decode(&mut tb1); + let t11 = sleb128_decode(&mut tb1); + let mut tag2: u32; + let mut t21: i32; loop { - tag1 = leb128_decode(&mut tb1); - t11 = sleb128_decode(&mut tb1); - n1 -= 1; - if !(tag1 < tag2 && n1 > 0) { + tag2 = leb128_decode(&mut tb2); + t21 = sleb128_decode(&mut tb2); + n2 -= 1; + if !(tag2 < tag1 && n2 > 0) { break; } } - }; - if tag1 > tag2 { - if !is_null_opt_reserved(typtbl2, end2, t21) { - // missing, non_opt field - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; + if tag1 != tag2 { + break 'return_false; + }; + if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + break 'return_false; } - advance = false; // reconsider this field in next round - continue; - }; - if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; } - advance = true; + return true; } - return true; - } - (IDL_CON_variant, IDL_CON_variant) => { - let n1 = leb128_decode(&mut tb1); - let mut n2 = leb128_decode(&mut tb2); - for _ in 0..n1 { - if n2 == 0 { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - }; - let tag1 = leb128_decode(&mut tb1); - let t11 = sleb128_decode(&mut tb1); - let mut tag2: u32; - let mut t21: i32; - loop { - tag2 = leb128_decode(&mut tb2); - t21 = sleb128_decode(&mut tb2); - n2 -= 1; - if !(tag2 < tag1 && n2 > 0) { + (IDL_CON_service, IDL_CON_service) => { + let mut n1 = leb128_decode(&mut tb1); + let n2 = leb128_decode(&mut tb2); + for _ in 0..n2 { + if n1 == 0 { + break 'return_false; + }; + let len2 = leb128_decode(&mut tb2); + let p2 = tb2.ptr; + Buf::advance(&mut tb2, len2); + let t21 = sleb128_decode(&mut tb2); + let mut len1: u32; + let mut p1: *mut u8; + let mut t11: i32; + let mut cmp: i32; + loop { + len1 = leb128_decode(&mut tb1); + p1 = tb1.ptr; + Buf::advance(&mut tb1, len1); + t11 = sleb128_decode(&mut tb1); + n1 -= 1; + cmp = utf8_cmp(len1, p1, len2, p2); + if cmp < 0 && n1 > 0 { + continue; + }; break; } - } - if tag1 != tag2 { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - }; - if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - } - } - return true; - } - (IDL_CON_service, IDL_CON_service) => { - let mut n1 = leb128_decode(&mut tb1); - let n2 = leb128_decode(&mut tb2); - for _ in 0..n2 { - if n1 == 0 { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - }; - let len2 = leb128_decode(&mut tb2); - let p2 = tb2.ptr; - Buf::advance(&mut tb2, len2); - let t21 = sleb128_decode(&mut tb2); - let mut len1: u32; - let mut p1: *mut u8; - let mut t11: i32; - let mut cmp: i32; - loop { - len1 = leb128_decode(&mut tb1); - p1 = tb1.ptr; - Buf::advance(&mut tb1, len1); - t11 = sleb128_decode(&mut tb1); - n1 -= 1; - cmp = utf8_cmp(len1, p1, len2, p2); - if cmp < 0 && n1 > 0 { - continue; + if !(cmp == 0) { + break 'return_false; }; - break; - } - if !(cmp == 0) { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; - }; - if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { - rel.set(p, t1 as u32, t2 as u32, 1, false); - return false; + if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { + break 'return_false; + } } + return true; } - return true; - } - // default - (_, _) => { - if t1 >= 0 && t2 >= 0 { - rel.set(p, t1 as u32, t2 as u32, 1, false); + // default + (_, _) => { + break 'return_false; } - return false; } } + // remember negative result ... + if t1 >= 0 && t2 >= 0 { + rel.set(p, t1 as u32, t2 as u32, 1, false); + } + // .. only then return false + return false; } #[no_mangle] From c9949d07938086b85ff9ed06530594747682583d Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 24 Mar 2022 18:20:38 +0000 Subject: [PATCH 055/128] comments + renaming --- rts/motoko-rts/src/idl.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 4325ea15f80..2c5c2138e78 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -551,8 +551,8 @@ unsafe fn sub( return rel.get(p, t1, t2, 1); }; // cache and continue - rel.set(p, t1, t2, 0, true); // mark visited - rel.set(p, t1, t2, 1, true); // assume true + rel.set(p, t1, t2, 0, true); // mark bit 0 visited (bit 0) + rel.set(p, t1, t2, 1, true); // assume t1 <:/:> t2 true (bit 1) }; /* primitives reflexive */ @@ -592,6 +592,7 @@ unsafe fn sub( t2 }; + // NB we use a trivial labelled loop so we can factor out the common failure continuation. // exit either via 'return true' or 'break 'return_false' to memoize the negative result 'return_false: loop { match (u1, u2) { @@ -794,6 +795,7 @@ unsafe fn sub( } // remember negative result ... if t1 >= 0 && t2 >= 0 { + // falsify t1 <:/:> t2 (bit 1) rel.set(p, t1 as u32, t2 as u32, 1, false); } // .. only then return false @@ -801,8 +803,8 @@ unsafe fn sub( } #[no_mangle] -unsafe extern "C" fn idl_sub_buf_words(n_types1: u32, n_types2: u32) -> u32 { - return BitRel::words(n_types1, n_types2); +unsafe extern "C" fn idl_sub_buf_words(typtbl_size1: u32, typtbl_size2: u32) -> u32 { + return BitRel::words(typtbl_size1, typtbl_size2); } #[no_mangle] From a42cb8fd18c5fcfefea67172334e5c0c987c8a14 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 24 Mar 2022 19:03:12 +0000 Subject: [PATCH 056/128] fix comment --- rts/motoko-rts/src/idl.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 2c5c2138e78..8fe3e0e9be8 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -546,8 +546,8 @@ unsafe fn sub( if t1 >= 0 && t2 >= 0 { let t1 = t1 as u32; let t2 = t2 as u32; - if rel.get(p, t1, t2, 0) { - // cached: succeed! + if rel.get(p, t1, t2, 0) { // visited? (bit 0) + // return assumed or determined result (bit 1) return rel.get(p, t1, t2, 1); }; // cache and continue From 03cf17e5f2ee277201f4b225c6bfff2bca2c1c14 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 24 Mar 2022 22:11:48 +0000 Subject: [PATCH 057/128] appease gods of rusts --- rts/motoko-rts/src/idl.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 8fe3e0e9be8..f24845d1498 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -546,7 +546,8 @@ unsafe fn sub( if t1 >= 0 && t2 >= 0 { let t1 = t1 as u32; let t2 = t2 as u32; - if rel.get(p, t1, t2, 0) { // visited? (bit 0) + if rel.get(p, t1, t2, 0) { + // visited? (bit 0) // return assumed or determined result (bit 1) return rel.get(p, t1, t2, 1); }; From 5502400c778ced4ccb7cfb24dbc1b8009e963256 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 1 Apr 2022 16:18:03 +0100 Subject: [PATCH 058/128] thread memo table --- src/codegen/compile.ml | 60 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index da0e39d0345..543eebe59a2 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -767,15 +767,7 @@ module Func = struct (G.i (LocalGet (nr 2l))) (G.i (LocalGet (nr 3l))) ) - let share_code5 env name (p1, p2, p3, p4, p5) retty mk_body = - share_code env name [p1; p2; p3; p4; p5] retty (fun env -> mk_body env - (G.i (LocalGet (nr 0l))) - (G.i (LocalGet (nr 1l))) - (G.i (LocalGet (nr 2l))) - (G.i (LocalGet (nr 3l))) - (G.i (LocalGet (nr 4l))) - ) - let _share_code6 env name (p1, p2, p3, p4, p5, p6) retty mk_body = + let share_code6 env name (p1, p2, p3, p4, p5, p6) retty mk_body = share_code env name [p1; p2; p3; p4; p5; p6] retty (fun env -> mk_body env (G.i (LocalGet (nr 0l))) (G.i (LocalGet (nr 1l))) @@ -4868,25 +4860,34 @@ module Serialization = struct It advances the data_buffer past the decoded value (even if it returns coercion_error_value!) *) + let with_rel_buf_opt env extended get_typtbl_size1 f = + if extended then + f (compile_unboxed_const 0l) + else + get_typtbl_size1 ^^ get_typtbl_size env ^^ + E.call_import env "rts" "idl_sub_buf_words" ^^ + Stack.dynamic_with_words env "rel_buf" f + + let idl_sub env t2 = let idx = List.length (!(env.E.typtbl_typs)) in env.E.typtbl_typs := !(env.E.typtbl_typs) @ [t2]; get_typtbl_idltyps env ^^ compile_add_const (Int32.of_int (idx * 4)) ^^ G.i (Load {ty = I32Type; align = 0; offset = 0l; sz = None}) ^^ - Func.share_code5 env ("idl_sub") - (("typtbl1", I32Type), + Func.share_code6 env ("idl_sub") + (("rel_buf", I32Type), + ("typtbl1", I32Type), ("typtbl_end1", I32Type), ("typtbl_size1", I32Type), ("idltyp1", I32Type), ("idltyp2", I32Type) ) [I32Type] - (fun env get_typtbl1 get_typtbl_end1 get_typtbl_size1 get_idltyp1 get_idltyp2 -> - get_typtbl_size1 ^^ get_typtbl_size env ^^ - E.call_import env "rts" "idl_sub_buf_words" ^^ - Stack.dynamic_with_words env "rel_buf" (fun get_rel_buf_ptr -> - get_rel_buf_ptr ^^ + (fun env get_rel_buf get_typtbl1 get_typtbl_end1 get_typtbl_size1 get_idltyp1 get_idltyp2 -> + get_rel_buf ^^ + E.else_trap_with env "null rel_buf" ^^ + get_rel_buf ^^ get_typtbl1 ^^ get_typtbl env ^^ get_typtbl_end1 ^^ @@ -4895,14 +4896,14 @@ module Serialization = struct get_typtbl_size env ^^ get_idltyp1 ^^ get_idltyp2 ^^ - E.call_import env "rts" "idl_sub")) + E.call_import env "rts" "idl_sub") let rec deserialize_go env t = let open Type in let t = Type.normalize t in let name = "@deserialize_go<" ^ typ_hash t ^ ">" in Func.share_code9 env name - (("extended", I32Type), + (("rel_buf_opt", I32Type), ("data_buffer", I32Type), ("ref_buffer", I32Type), ("typtbl", I32Type), @@ -4912,7 +4913,7 @@ module Serialization = struct ("depth", I32Type), ("can_recover", I32Type) ) [I32Type] - (fun env get_extended get_data_buf get_ref_buf get_typtbl get_typtbl_end get_typtbl_size get_idltyp get_depth get_can_recover -> + (fun env get_rel_buf_opt get_data_buf get_ref_buf get_typtbl get_typtbl_end get_typtbl_size get_idltyp get_depth get_can_recover -> (* Check recursion depth (protects against empty record etc.) *) (* Factor 2 because at each step, the expected type could go through one @@ -4930,7 +4931,7 @@ module Serialization = struct let go' can_recover env t = let (set_idlty, get_idlty) = new_local env "idl_ty" in set_idlty ^^ - get_extended ^^ + get_rel_buf_opt ^^ get_data_buf ^^ get_ref_buf ^^ get_typtbl ^^ @@ -5473,16 +5474,16 @@ module Serialization = struct ( coercion_failed "IDL error: unexpected variant tag" ) ) | Func _ -> - get_extended ^^ + get_rel_buf_opt ^^ G.if1 I32Type - (compile_unboxed_const 1l) (begin get_typtbl ^^ get_typtbl_end ^^ get_typtbl_size ^^ get_idltyp ^^ idl_sub env t - end) ^^ + end) + (compile_unboxed_const 1l) ^^ G.if1 I32Type (with_composite_typ idl_func (fun _get_typ_buf -> read_byte_tagged @@ -5493,16 +5494,16 @@ module Serialization = struct ])) (coercion_failed "IDL error: incompatible function type") | Obj (Actor, _) -> - get_extended ^^ + get_rel_buf_opt ^^ G.if1 I32Type - (compile_unboxed_const 1l) (begin get_typtbl ^^ get_typtbl_end ^^ get_typtbl_size ^^ get_idltyp ^^ idl_sub env t - end) ^^ + end) + (compile_unboxed_const 1l) ^^ G.if1 I32Type (with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data ())) @@ -5622,6 +5623,9 @@ module Serialization = struct Bool.lit extended ^^ get_data_buf ^^ get_typtbl_ptr ^^ get_typtbl_size_ptr ^^ get_maintyps_ptr ^^ E.call_import env "rts" "parse_idl_header" ^^ + (* Allocate memo table, if necessary *) + with_rel_buf_opt env extended (get_typtbl_size_ptr ^^ load_unskewed_ptr) (fun get_rel_buf_opt -> + (* set up a dedicated read buffer for the list of main types *) ReadBuf.alloc env (fun get_main_typs_buf -> ReadBuf.set_ptr get_main_typs_buf (get_maintyps_ptr ^^ load_unskewed_ptr) ^^ @@ -5641,7 +5645,7 @@ module Serialization = struct G.if1 I32Type (default_or_trap ("IDL error: too few arguments " ^ ts_name)) (begin - compile_unboxed_const (if extended then 1l else 0l) ^^ + get_rel_buf_opt ^^ get_data_buf ^^ get_ref_buf ^^ get_typtbl_ptr ^^ load_unskewed_ptr ^^ get_maintyps_ptr ^^ load_unskewed_ptr ^^ (* typtbl_end *) @@ -5676,7 +5680,7 @@ module Serialization = struct E.else_trap_with env ("IDL error: left-over references " ^ ts_name) )))))) - ) + )) let deserialize env ts = Blob.of_size_copy env From 77bef3cd52d324b36c360fd72dab40359860d6e9 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 1 Apr 2022 16:23:29 +0100 Subject: [PATCH 059/128] fix bug --- src/codegen/compile.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 543eebe59a2..f249fd45664 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5477,6 +5477,7 @@ module Serialization = struct get_rel_buf_opt ^^ G.if1 I32Type (begin + get_rel_buf_opt ^^ get_typtbl ^^ get_typtbl_end ^^ get_typtbl_size ^^ @@ -5497,6 +5498,7 @@ module Serialization = struct get_rel_buf_opt ^^ G.if1 I32Type (begin + get_rel_buf_opt ^^ get_typtbl ^^ get_typtbl_end ^^ get_typtbl_size ^^ From 99257c166b4d9665d54390a553a6e7904d18b714 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 1 Apr 2022 16:46:06 +0100 Subject: [PATCH 060/128] cleanup --- rts/motoko-rts/src/idl.rs | 6 ++++-- src/codegen/compile.ml | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 12be5e5b88b..f8c8152ea2f 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -781,8 +781,8 @@ unsafe fn sub( } #[no_mangle] -unsafe extern "C" fn idl_sub_buf_words(n_types1: u32, n_types2: u32) -> u32 { - return BitRel::words(n_types1, n_types2); +unsafe extern "C" fn idl_sub_buf_words(typtbl_size1: u32, typtbl_size2: u32) -> u32 { + return BitRel::words(typtbl_size1, typtbl_size2); } #[no_mangle] @@ -797,6 +797,8 @@ unsafe extern "C" fn idl_sub( t1: i32, t2: i32, ) -> bool { + debug_assert!(rel_buf != (0 as *mut u32)); + let rel = BitRel { ptr: rel_buf, end: rel_buf.add(idl_sub_buf_words(typtbl_size1, typtbl_size2) as usize), diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index f249fd45664..e554961d962 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -1082,7 +1082,6 @@ module Stack = struct f get_x ^^ dynamic_free_words env get_n - end (* Stack *) From e39887d94e83ddbc90f0dca69199d67a185d4fb6 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 4 Apr 2022 13:06:52 +0100 Subject: [PATCH 061/128] wip: negative ho tests --- test/run-drun/idl-sub-ho-neg.mo | 206 ++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 test/run-drun/idl-sub-ho-neg.mo diff --git a/test/run-drun/idl-sub-ho-neg.mo b/test/run-drun/idl-sub-ho-neg.mo new file mode 100644 index 00000000000..22f661c41ef --- /dev/null +++ b/test/run-drun/idl-sub-ho-neg.mo @@ -0,0 +1,206 @@ +import Prim "mo:⛔"; + +// test candid subtype test with higher-order arguments +actor this { + + public func send_f0( + f : shared (Nat) -> async Int + ) : async () { + Prim.debugPrint("wrong_0"); + }; + + public func send_f2( + f : shared (Nat, [Nat], {f:Nat;g:Nat}, {#l:Nat; #m:Nat}) -> + async(Int, [Int], {f:Int;g:Int}, {#l:Int; #m:Int}) + ) : async () { + Prim.debugPrint("wrong_2"); + }; + + public func send_f3( + f : shared () -> + async (Null, Any, ?None) + ) : async () { + Prim.debugPrint("wrong_3"); + }; + + public func f0(n : Nat) : async Int { 0 }; + + public func f0_1_a(n : None) : async Int { 0 }; + public func f0_1_b(n : Nat) : async Any { () }; + + public func f0_2_a() : async (Any, Bool) { ((), true) }; + public func f0_2_b(n : Nat, a : Bool ) : async (Int, Bool) { (1, true) }; + + public func f0_3_a(on : ?Nat, i : Nat) : async (Int, ?Nat) { (0, null); }; + public func f0_3_b(i : Nat, on : ?Nat) : async (?Nat, Int) { (null, 0); }; + + public func f0_4(ob : ?Bool, n : Nat) : async Int { 0 }; + + public func f1_0(n : ?Nat) : async (Bool, Nat) { (true, 0) }; + + public func f2_0(n : Nat, a : [Nat], r : {f : Nat; g : Nat}, v : {#l : Nat; #m : Nat}) : + async (Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Int}) { + (1, [1], {f=1;g=1}, (#l 0)) + }; + + public func f2_1(n : Int, a : [Int], r : {f : Int}, v : {#l : Int; #m : Int; #o : Int}) : + async (Nat, [Nat], {f : Nat; g : Nat; h : Nat}, { #l : Nat}) { + (1, [1], {f = 1; g = 2; h = 3}, (#l 0)) + }; + + public func f3_0() : + async (n : Null, a : ?None, r : Any) { + (null, null, null) + }; + + public func go() : async () { + let t = debug_show (Prim.principalOfActor(this)); + + // vanilla subtyping on in/out args + do { + let this = actor (t) : actor { + send_f0 : (shared (n:None) -> async Int) -> async (); + }; + try { + await this.send_f0(f0_1_a); + Prim.debugPrint "wrong_0_1_a"; + } + catch e { + Prim.debugPrint "ok_0_1_a"; + } + }; + + // vanilla subtyping on in/out args + do { + let this = actor (t) : actor { + send_f0 : (shared (n:Nat) -> async Any) -> async (); + }; + try { + await this.send_f0(f0_1_b); + Prim.debugPrint "wrong_0_1_b"; + } + catch e { + Prim.debugPrint "ok_0_1_b"; + } + }; + + // negative vanilla subtyping on in/out arg sequences + do { + let this = actor (t) : actor { + send_f0 : (shared () -> async (Any, Bool)) -> async (); + }; + try { + await this.send_f0(f0_2_a); + Prim.debugPrint "wrong_0_2_a"; + } + catch e { + Prim.debugPrint "ok_0_2_a"; + } + }; + + // negative vanilla subtyping on in/out arg sequences + do { + let this = actor (t) : actor { + send_f0 : (shared (n : Nat, a : Bool) -> async (Int, Bool)) -> async (); + }; + try { + await this.send_f0(f0_2_b); + Prim.debugPrint "wrong_0_2_b"; + } + catch e { + Prim.debugPrint "ok_0_2_a"; + } + }; + + // negative opt subtyping in arg and return + do { + let this = actor (t) : actor { + send_f0 : (shared (?Nat, Nat) -> async (Int, ?Nat)) -> async (); + }; + try { + await this.send_f0(f0_3_a); + Prim.debugPrint "wrong_0_3_a"; + } + catch e { + Prim.debugPrint "ok_0_3_a"; + } + }; + + // negative opt subtyping in arg and return + do { + let this = actor (t) : actor { + send_f0 : (shared (Nat, ?Nat) -> async (?Nat, Int)) -> async (); + }; + try { + await this.send_f0(f0_3_b); + Prim.debugPrint "wrong_0_3_b"; + } + catch e { + Prim.debugPrint "ok_0_3_b"; + } + }; + + // negative opt override in arg + do { + let this = actor (t) : actor { + send_f0 : (shared (?Bool, Nat) -> async Int) -> async (); + }; + try { + await this.send_f0(f0_4); + Prim.debugPrint "wrong_0_4"; + } + catch e { + Prim.debugPrint "ok 0_4"; } + }; + + + // several args + do { + let this = actor (t) : actor { + send_f2 : + (shared (Nat, [Nat], {f : Nat; g : Nat}, {#l : Nat; #m : Nat}) -> + async (Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Int})) -> + async () + }; + try { + await this.send_f2(f2_0); + } + catch e { Prim.debugPrint "wrong_2_0"; } + }; + + // several args, contra-co subtyping + do { + let this = actor (t) : actor { + send_f2 : + (shared (Int, [Int], {f : Int}, {#l : Int; #m : Int; #o : Int}) -> + async (Nat, [Nat], {f : Nat; g : Nat; h : Nat}, {#l : Nat})) -> + async () + }; + try { + await this.send_f2(f2_1); + } + catch e { Prim.debugPrint "wrong_2_1"; } + }; + + + // null, opt and any trailing args, defaulting + do { + let this = actor (t) : actor { + send_f3 : + (shared () -> + async (Null, ?None, Any)) -> + async () + }; + try { + await this.send_f3(f3_0); + } + catch e { Prim.debugPrint "wrong_3_0"; } + }; + + }; + +} +//SKIP run +//SKIP run-ir +//SKIP run-low +//CALL ingress go "DIDL\x00\x00" \ No newline at end of file From d7fdb43ca102e76bc102fe176d96b3c3dc193af6 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 4 Apr 2022 14:17:26 +0100 Subject: [PATCH 062/128] add negative ho candid subtype tests --- test/run-drun/idl-sub-ho-neg.mo | 102 +++++++++++++++--- test/run-drun/ok/idl-sub-ho-neg.drun-run.ok | 16 +++ test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok | 19 ++++ 3 files changed, 123 insertions(+), 14 deletions(-) create mode 100644 test/run-drun/ok/idl-sub-ho-neg.drun-run.ok create mode 100644 test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok diff --git a/test/run-drun/idl-sub-ho-neg.mo b/test/run-drun/idl-sub-ho-neg.mo index 22f661c41ef..5330ca363e1 100644 --- a/test/run-drun/idl-sub-ho-neg.mo +++ b/test/run-drun/idl-sub-ho-neg.mo @@ -18,7 +18,7 @@ actor this { public func send_f3( f : shared () -> - async (Null, Any, ?None) + async (Null, Any, ?None, Nat) ) : async () { Prim.debugPrint("wrong_3"); }; @@ -38,21 +38,39 @@ actor this { public func f1_0(n : ?Nat) : async (Bool, Nat) { (true, 0) }; - public func f2_0(n : Nat, a : [Nat], r : {f : Nat; g : Nat}, v : {#l : Nat; #m : Nat}) : + public func f2_0_a(n : Nat, a : [Nat], r : {f : Nat; g : Nat}, v : {#l : Nat; #m : None}) : async (Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Int}) { (1, [1], {f=1;g=1}, (#l 0)) }; - public func f2_1(n : Int, a : [Int], r : {f : Int}, v : {#l : Int; #m : Int; #o : Int}) : + public func f2_0_b(n : Nat, a : [Nat], r : {f : Nat; g : Nat}, v : {#l : Nat; #m : Nat}) : + async (Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Any}) { + (1, [1], {f=1;g=1}, (#l 0)) + }; + + + public func f2_1_a(n : Int, a : [Int], r : {f : Int}, v : {#l : Int; #m : None; #o : Int}) : async (Nat, [Nat], {f : Nat; g : Nat; h : Nat}, { #l : Nat}) { (1, [1], {f = 1; g = 2; h = 3}, (#l 0)) }; - public func f3_0() : + public func f2_1_b(n : Int, a : [Int], r : {f : Int}, v : {#l : Int; #m : Int; #o : Int}) : + async (Nat, [Nat], {f : Nat; g : Nat; h : Nat}, { #l : Any}) { + (1, [1], {f = 1; g = 2; h = 3}, (#l 0)) + }; + + + public func f3_0_a(x : Nat) : async (n : Null, a : ?None, r : Any) { (null, null, null) }; + public func f3_0_b() : + async (n : Null, a : ?None, r : Any) { + (null, null, null) + }; + + public func go() : async () { let t = debug_show (Prim.principalOfActor(this)); @@ -154,36 +172,88 @@ actor this { }; + // negative several args + do { + let this = actor (t) : actor { + send_f2 : + (shared (Nat, [Nat], {f : Nat; g : Nat}, {#l : Nat; #m : None}) -> + async (Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Int})) -> + async () + }; + try { + await this.send_f2(f2_0_a); + Prim.debugPrint "wrong_2_0_a"; + } + catch e { + Prim.debugPrint "ok 2_0_a"; } + }; + // several args do { let this = actor (t) : actor { send_f2 : (shared (Nat, [Nat], {f : Nat; g : Nat}, {#l : Nat; #m : Nat}) -> - async (Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Int})) -> + async (Int, [Int], {f : Int; g : Int}, {#l : Int; #m : Any})) -> async () }; try { - await this.send_f2(f2_0); + await this.send_f2(f2_0_b); + Prim.debugPrint "wrong_2_0_b"; } - catch e { Prim.debugPrint "wrong_2_0"; } + catch e { + Prim.debugPrint "ok 2_0_b"; } }; - // several args, contra-co subtyping + // negative several args, contra-co subtyping do { let this = actor (t) : actor { send_f2 : - (shared (Int, [Int], {f : Int}, {#l : Int; #m : Int; #o : Int}) -> + (shared (Int, [Int], {f : Int}, {#l : Int; #m : None; #o : Int}) -> async (Nat, [Nat], {f : Nat; g : Nat; h : Nat}, {#l : Nat})) -> async () }; try { - await this.send_f2(f2_1); + await this.send_f2(f2_1_a); + Prim.debugPrint "wrong 2_1_a"; } - catch e { Prim.debugPrint "wrong_2_1"; } + catch e { Prim.debugPrint "ok 2_1_a"; } }; + // negative several args, contra-co subtyping + do { + let this = actor (t) : actor { + send_f2 : + (shared (Int, [Int], {f : Int}, {#l : Int; #m : Int; #o : Int}) -> + async (Nat, [Nat], {f : Nat; g : Nat; h : Nat}, {#l : Any})) -> + async () + }; + try { + await this.send_f2(f2_1_b); + Prim.debugPrint "wrong 2_1_b"; + } + catch e { + Prim.debugPrint "ok 2_1_b";} + }; + + + // negative null, opt and any trailing args, defaulting + do { + let this = actor (t) : actor { + send_f3 : + (shared Nat -> + async (Null, ?None, Any)) -> + async () + }; + try { + await this.send_f3(f3_0_a); + Prim.debugPrint "wrong 3_0_a"; + } + catch e { + Prim.debugPrint "ok 3_0_a"; + } + }; - // null, opt and any trailing args, defaulting + // negative null, opt and any trailing args, defaulting do { let this = actor (t) : actor { send_f3 : @@ -192,11 +262,15 @@ actor this { async () }; try { - await this.send_f3(f3_0); + await this.send_f3(f3_0_b); + Prim.debugPrint "wrong 3_0_b"; + } + catch e { + Prim.debugPrint "ok 3_0_b"; } - catch e { Prim.debugPrint "wrong_3_0"; } }; + }; } diff --git a/test/run-drun/ok/idl-sub-ho-neg.drun-run.ok b/test/run-drun/ok/idl-sub-ho-neg.drun-run.ok new file mode 100644 index 00000000000..cb5b49b3aef --- /dev/null +++ b/test/run-drun/ok/idl-sub-ho-neg.drun-run.ok @@ -0,0 +1,16 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: ok_0_1_a +debug.print: ok_0_1_b +debug.print: ok_0_2_a +debug.print: ok_0_2_a +debug.print: ok_0_3_a +debug.print: ok_0_3_b +debug.print: ok 0_4 +debug.print: ok 2_0_a +debug.print: ok 2_0_b +debug.print: ok 2_1_a +debug.print: ok 2_1_b +debug.print: ok 3_0_a +debug.print: ok 3_0_b +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok b/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok new file mode 100644 index 00000000000..4e4ee892f57 --- /dev/null +++ b/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok @@ -0,0 +1,19 @@ +→ update create_canister(record {settings = null}) +← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… +← replied: () +→ update go() +debug.print: ok_0_1_a +debug.print: ok_0_1_b +debug.print: ok_0_2_a +debug.print: ok_0_2_a +debug.print: ok_0_3_a +debug.print: ok_0_3_b +debug.print: ok 0_4 +debug.print: ok 2_0_a +debug.print: ok 2_0_b +debug.print: ok 2_1_a +debug.print: ok 2_1_b +debug.print: ok 3_0_a +debug.print: ok 3_0_b +← replied: () From 9c76d7d64d844339a0b4752f9d47f19fbfc801e3 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 4 Apr 2022 14:19:54 +0100 Subject: [PATCH 063/128] rename test --- test/run-drun/{idl-sub-default.mo => idl-sub-ho.mo} | 0 .../ok/{idl-sub-default.drun-run.ok => id-sub-ho.drun-run.ok} | 0 .../ok/{idl-sub-default.ic-ref-run.ok => id-sub-ho.ic-ref-run.ok} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename test/run-drun/{idl-sub-default.mo => idl-sub-ho.mo} (100%) rename test/run-drun/ok/{idl-sub-default.drun-run.ok => id-sub-ho.drun-run.ok} (100%) rename test/run-drun/ok/{idl-sub-default.ic-ref-run.ok => id-sub-ho.ic-ref-run.ok} (100%) diff --git a/test/run-drun/idl-sub-default.mo b/test/run-drun/idl-sub-ho.mo similarity index 100% rename from test/run-drun/idl-sub-default.mo rename to test/run-drun/idl-sub-ho.mo diff --git a/test/run-drun/ok/idl-sub-default.drun-run.ok b/test/run-drun/ok/id-sub-ho.drun-run.ok similarity index 100% rename from test/run-drun/ok/idl-sub-default.drun-run.ok rename to test/run-drun/ok/id-sub-ho.drun-run.ok diff --git a/test/run-drun/ok/idl-sub-default.ic-ref-run.ok b/test/run-drun/ok/id-sub-ho.ic-ref-run.ok similarity index 100% rename from test/run-drun/ok/idl-sub-default.ic-ref-run.ok rename to test/run-drun/ok/id-sub-ho.ic-ref-run.ok From b5315f315615aa83d9db3eda372f3f818ecc9907 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 4 Apr 2022 15:23:28 +0100 Subject: [PATCH 064/128] add test output --- test/run-drun/ok/idl-sub-ho.drun-run.ok | 12 ++++++++++++ test/run-drun/ok/idl-sub-ho.ic-ref-run.ok | 15 +++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 test/run-drun/ok/idl-sub-ho.drun-run.ok create mode 100644 test/run-drun/ok/idl-sub-ho.ic-ref-run.ok diff --git a/test/run-drun/ok/idl-sub-ho.drun-run.ok b/test/run-drun/ok/idl-sub-ho.drun-run.ok new file mode 100644 index 00000000000..a10eda26a67 --- /dev/null +++ b/test/run-drun/ok/idl-sub-ho.drun-run.ok @@ -0,0 +1,12 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok new file mode 100644 index 00000000000..85e03181f69 --- /dev/null +++ b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok @@ -0,0 +1,15 @@ +→ update create_canister(record {settings = null}) +← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… +← replied: () +→ update go() +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +debug.print: ok +← replied: () From 9ed2870b33bcf6ce56c3d2af01fd0e31f91b2018 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 4 Apr 2022 15:40:26 +0100 Subject: [PATCH 065/128] add record test --- test/run-drun/idl-sub-ho.mo | 60 ++++++++++++++++++----- test/run-drun/ok/idl-sub-ho.drun-run.ok | 1 + test/run-drun/ok/idl-sub-ho.ic-ref-run.ok | 1 + 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/test/run-drun/idl-sub-ho.mo b/test/run-drun/idl-sub-ho.mo index beb979bde3a..384a66fd597 100644 --- a/test/run-drun/idl-sub-ho.mo +++ b/test/run-drun/idl-sub-ho.mo @@ -29,6 +29,13 @@ actor this { Prim.debugPrint("ok"); }; + public func send_f5( + f : shared {a : Nat; b : [Nat]; c : {f:Nat;g:Nat}; d : {#l:Nat; #m:Nat}} -> + async {a : Int; b : [Int]; c : {f:Int;g:Int}; d : {#l:Int; #m:Int}} + ) : async () { + Prim.debugPrint("ok"); + }; + public func f0(n : Nat) : async Int { 0 }; public func f0_1(n : Int) : async Nat { 0 }; @@ -56,6 +63,16 @@ actor this { (null, null, null) }; + public func f5_0({a = n : Nat; b = a : [Nat]; c = r : {f : Nat; g : Nat}; d = v : {#l : Nat; #m : Nat}}) : + async { a : Int; b : [Int]; c : {f : Int; g : Int}; d : {#l : Int; #m : Int} } { + { a = 1; b = [1]; c = {f =1 ; g = 1}; d = (#l 0)} + }; + + public func f5_1({a = n : Int; b = a : [Int]; c = r : {f : Int}; d = v : {#l : Int; #m : Int; #o : Int} }) : + async { a : Nat; b : [Nat]; c : {f : Nat; g : Nat; h : Nat}; d : { #l : Nat}} { + { a = 1; b = [1]; c = {f = 1; g = 2; h = 3}; d = (#l 0)} + }; + public func go() : async () { let t = debug_show (Prim.principalOfActor(this)); @@ -115,19 +132,6 @@ actor this { catch e { Prim.debugPrint "wrong_1_0"; } }; - - // opt override in return - do { - let this = actor (t) : actor { - send_f1 : (shared (?Nat) -> async Bool) -> async (); - }; - try { - await this.send_f1(f1_0); - } - catch e { Prim.debugPrint "wrong_1_0"; } - }; - - // several args do { let this = actor (t) : actor { @@ -171,6 +175,36 @@ actor this { catch e { Prim.debugPrint "wrong_3_0"; } }; + + // several args + do { + let this = actor (t) : actor { + send_f5 : + (shared {a : Nat; b : [Nat]; c : {f : Nat; g : Nat}; d : {#l : Nat; #m : Nat}} -> + async {a : Int; b : [Int]; c : {f : Int; g : Int}; d : {#l : Int; #m : Int}}) -> + async () + }; + try { + await this.send_f5(f5_0); + } + catch e { Prim.debugPrint "wrong_5_0"; } + }; + + // several args, contra-co subtyping + do { + let this = actor (t) : actor { + send_f5 : + (shared {a : Int; b : [Int]; c : {f : Int}; d : {#l : Int; #m : Int; #o : Int}} -> + async {a : Nat; b : [Nat]; c : {f : Nat; g : Nat; h : Nat}; d : {#l : Nat}}) -> + async () + }; + try { + await this.send_f5(f5_1); + } + catch e { Prim.debugPrint "wrong_5_1"; } + }; + + }; } diff --git a/test/run-drun/ok/idl-sub-ho.drun-run.ok b/test/run-drun/ok/idl-sub-ho.drun-run.ok index a10eda26a67..ef77bf84a86 100644 --- a/test/run-drun/ok/idl-sub-ho.drun-run.ok +++ b/test/run-drun/ok/idl-sub-ho.drun-run.ok @@ -9,4 +9,5 @@ debug.print: ok debug.print: ok debug.print: ok debug.print: ok +debug.print: ok ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok index 85e03181f69..f9aea809886 100644 --- a/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok @@ -12,4 +12,5 @@ debug.print: ok debug.print: ok debug.print: ok debug.print: ok +debug.print: ok ← replied: () From 753d9499014d4166111f5a2e4f0f8372cbb0ad8f Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 4 Apr 2022 15:52:43 +0100 Subject: [PATCH 066/128] test optional record fields --- test/run-drun/idl-sub-ho.mo | 31 +++++++++++++++++++++-- test/run-drun/ok/idl-sub-ho.drun-run.ok | 1 + test/run-drun/ok/idl-sub-ho.ic-ref-run.ok | 1 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/test/run-drun/idl-sub-ho.mo b/test/run-drun/idl-sub-ho.mo index 384a66fd597..30a3bd0dd1f 100644 --- a/test/run-drun/idl-sub-ho.mo +++ b/test/run-drun/idl-sub-ho.mo @@ -36,6 +36,13 @@ actor this { Prim.debugPrint("ok"); }; + public func send_f6( + f : shared () -> + async {a : Null; b : Any; c : ?None} + ) : async () { + Prim.debugPrint("ok"); + }; + public func f0(n : Nat) : async Int { 0 }; public func f0_1(n : Int) : async Nat { 0 }; @@ -73,7 +80,13 @@ actor this { { a = 1; b = [1]; c = {f = 1; g = 2; h = 3}; d = (#l 0)} }; + public func f6_0() : + async {a : Null; b : ?None; c : Any} { + { a= null; b = null; c = null} + }; + public func go() : async () { + let t = debug_show (Prim.principalOfActor(this)); // vanilla subtyping on in/out args @@ -176,7 +189,7 @@ actor this { }; - // several args + // record arg do { let this = actor (t) : actor { send_f5 : @@ -190,7 +203,7 @@ actor this { catch e { Prim.debugPrint "wrong_5_0"; } }; - // several args, contra-co subtyping + // record arg, contra-co subtyping do { let this = actor (t) : actor { send_f5 : @@ -205,6 +218,20 @@ actor this { }; + // null, opt and any record fields, defaulting + do { + let this = actor (t) : actor { + send_f6 : + (shared () -> + async {a : Null; b : ?None; c : Any}) -> + async () + }; + try { + await this.send_f6(f6_0); + } + catch e { Prim.debugPrint "wrong_6_0"; } + }; + }; } diff --git a/test/run-drun/ok/idl-sub-ho.drun-run.ok b/test/run-drun/ok/idl-sub-ho.drun-run.ok index ef77bf84a86..0566758d621 100644 --- a/test/run-drun/ok/idl-sub-ho.drun-run.ok +++ b/test/run-drun/ok/idl-sub-ho.drun-run.ok @@ -10,4 +10,5 @@ debug.print: ok debug.print: ok debug.print: ok debug.print: ok +debug.print: ok ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok index f9aea809886..65ea0b31682 100644 --- a/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok @@ -13,4 +13,5 @@ debug.print: ok debug.print: ok debug.print: ok debug.print: ok +debug.print: ok ← replied: () From 8c7146a4bd01ebb571e5aabffd28153758a1f260 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 4 Apr 2022 16:16:07 +0100 Subject: [PATCH 067/128] add negative record tests --- test/run-drun/idl-sub-ho-neg.mo | 142 ++++++++++++++++++ test/run-drun/ok/idl-sub-ho-neg.drun-run.ok | 6 + test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok | 6 + 3 files changed, 154 insertions(+) diff --git a/test/run-drun/idl-sub-ho-neg.mo b/test/run-drun/idl-sub-ho-neg.mo index 5330ca363e1..64ecb105e2d 100644 --- a/test/run-drun/idl-sub-ho-neg.mo +++ b/test/run-drun/idl-sub-ho-neg.mo @@ -23,6 +23,21 @@ actor this { Prim.debugPrint("wrong_3"); }; + public func send_f5( + f : shared {a : Nat; b : [Nat]; c : {f:Nat;g:Nat}; d : {#l:Nat; #m:Nat}} -> + async {a : Int; b : [Int]; c : {f:Int;g:Int}; d : {#l:Int; #m:Int}} + ) : async () { + Prim.debugPrint("ok"); + }; + + public func send_f6( + f : shared () -> + async {a : Null; b : Any; c : ?None} + ) : async () { + Prim.debugPrint("ok"); + }; + + public func f0(n : Nat) : async Int { 0 }; public func f0_1_a(n : None) : async Int { 0 }; @@ -70,6 +85,36 @@ actor this { (null, null, null) }; + public func f5_0_a({a = n : Nat; b = a : [Nat]; c = r : {f : Nat; g : Nat}; d = v : {#l : Nat; #m : None}}) : + async { a : Int; b : [Int]; c : {f : Int; g : Int}; d : {#l : Int; #m : Int} } { + { a = 1; b = [1]; c = {f =1 ; g = 1}; d = (#l 0)} + }; + + public func f5_0_b({a = n : Nat; b = a : [Nat]; c = r : {f : Nat; g : Nat}; d = v : {#l : Nat; #m : Nat}}) : + async { a : Int; b : [Int]; c : {f : Int; g : Int}; d : {#l : Int; #m : Any} } { + { a = 1; b = [1]; c = {f =1 ; g = 1}; d = (#l 0)} + }; + + public func f5_1_a({a = n : Int; b = a : [Int]; c = r : {f : Int}; d = v : {#l : Int; #m : None; #o : Int} }) : + async { a : Nat; b : [Nat]; c : {f : Nat; g : Nat; h : Nat}; d : { #l : Nat}} { + { a = 1; b = [1]; c = {f = 1; g = 2; h = 3}; d = (#l 0)} + }; + + public func f5_1_b({a = n : Int; b = a : [Int]; c = r : {f : Int}; d = v : {#l : Int; #m : Int; #o : Int} }) : + async { a : Nat; b : [Nat]; c : {f : Nat; g : Nat; h : Nat}; d : { #l : Any}} { + { a = 1; b = [1]; c = {f = 1; g = 2; h = 3}; d = (#l 0)} + }; + + + public func f6_0_a({x = _:Nat}) : + async {a : Null; b : ?None; c : Any} { + { a= null; b = null; c = null} + }; + + public func f6_0_b({}) : + async {a : Null; b : ?None; c : Any} { + { a= null; b = null; c = null} + }; public func go() : async () { let t = debug_show (Prim.principalOfActor(this)); @@ -270,6 +315,103 @@ actor this { } }; + // negative several fields + do { + let this = actor (t) : actor { + send_f5 : + (shared {a : Nat; b : [Nat]; c : {f : Nat; g : Nat}; d : {#l : Nat; #m : None}} -> + async {a : Int; b : [Int]; c : {f : Int; g : Int}; d : {#l : Int; #m : Int}}) -> + async () + }; + try { + await this.send_f5(f5_0_a); + Prim.debugPrint "wrong 5_0_a"; + } + catch e { + Prim.debugPrint "ok 5_0_a"; } + }; + + // negative several fields + do { + let this = actor (t) : actor { + send_f5 : + (shared { a : Nat; b : [Nat]; c : {f : Nat; g : Nat}; d : {#l : Nat; #m : Nat}} -> + async { a : Int; b : [Int]; c : {f : Int; g : Int}; d : {#l : Int; #m : Any}}) -> + async () + }; + try { + await this.send_f5(f5_0_b); + Prim.debugPrint "wrong 5_0_b"; + } + catch e { + Prim.debugPrint "ok 5_0_b"; } + }; + + // negative several fields, contra-co subtyping + do { + let this = actor (t) : actor { + send_f5 : + (shared { a : Int; b : [Int]; c : {f : Int}; d : {#l : Int; #m : None; #o : Int}} -> + async { a : Nat; b : [Nat]; c : {f : Nat; g : Nat; h : Nat}; d : {#l : Nat}}) -> + async () + }; + try { + await this.send_f5(f5_1_a); + Prim.debugPrint "wrong 5_1_a"; + } + catch e { Prim.debugPrint "ok 5_1_a"; } + }; + + // negative several args, contra-co subtyping + do { + let this = actor (t) : actor { + send_f5 : + (shared { a : Int; b : [Int]; c : {f : Int}; d : {#l : Int; #m : Int; #o : Int}} -> + async { a : Nat; b : [Nat]; c : {f : Nat; g : Nat; h : Nat}; d : {#l : Any}}) -> + async () + }; + try { + await this.send_f5(f5_1_b); + Prim.debugPrint "wrong 5_1_b"; + } + catch e { + Prim.debugPrint "ok 5_1_b";} + }; + + + // negative null, opt and any fields, defaulting + do { + let this = actor (t) : actor { + send_f6 : + (shared {x : Nat} -> + async { a : Null; b : ?None; c : Any}) -> + async () + }; + try { + await this.send_f6(f6_0_a); + Prim.debugPrint "wrong 6_0_a"; + } + catch e { + Prim.debugPrint "ok 6_0_a"; + } + }; + + // negative null, opt and any fields, defaulting + do { + let this = actor (t) : actor { + send_f6 : + (shared {} -> + async {a : Null; b : ?None; c : Any}) -> + async () + }; + try { + await this.send_f6(f6_0_b); + Prim.debugPrint "wrong 6_0_b"; + } + catch e { + Prim.debugPrint "ok 6_0_b"; + } + }; }; diff --git a/test/run-drun/ok/idl-sub-ho-neg.drun-run.ok b/test/run-drun/ok/idl-sub-ho-neg.drun-run.ok index cb5b49b3aef..5247ea3b4df 100644 --- a/test/run-drun/ok/idl-sub-ho-neg.drun-run.ok +++ b/test/run-drun/ok/idl-sub-ho-neg.drun-run.ok @@ -13,4 +13,10 @@ debug.print: ok 2_1_a debug.print: ok 2_1_b debug.print: ok 3_0_a debug.print: ok 3_0_b +debug.print: ok 5_0_a +debug.print: ok 5_0_b +debug.print: ok 5_1_a +debug.print: ok 5_1_b +debug.print: ok 6_0_a +debug.print: ok 6_0_b ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok b/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok index 4e4ee892f57..d22f4e9b9cc 100644 --- a/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok @@ -16,4 +16,10 @@ debug.print: ok 2_1_a debug.print: ok 2_1_b debug.print: ok 3_0_a debug.print: ok 3_0_b +debug.print: ok 5_0_a +debug.print: ok 5_0_b +debug.print: ok 5_1_a +debug.print: ok 5_1_b +debug.print: ok 6_0_a +debug.print: ok 6_0_b ← replied: () From 19e75c0e28a7cadc358a7587b908b2ddf83f69ce Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 4 Apr 2022 17:58:23 +0100 Subject: [PATCH 068/128] positive tests for recursive types --- test/run-drun/idl-sub-rec.mo | 59 ++++++++++++++++++++++ test/run-drun/ok/idl-sub-rec.drun-run.ok | 13 +++++ test/run-drun/ok/idl-sub-rec.ic-ref-run.ok | 16 ++++++ 3 files changed, 88 insertions(+) create mode 100644 test/run-drun/idl-sub-rec.mo create mode 100644 test/run-drun/ok/idl-sub-rec.drun-run.ok create mode 100644 test/run-drun/ok/idl-sub-rec.ic-ref-run.ok diff --git a/test/run-drun/idl-sub-rec.mo b/test/run-drun/idl-sub-rec.mo new file mode 100644 index 00000000000..ea9e104aff0 --- /dev/null +++ b/test/run-drun/idl-sub-rec.mo @@ -0,0 +1,59 @@ +import Prim "mo:⛔"; + +actor this { + + type List = { + #nil; + #left:(T,List) + }; + + type Tree = { + #nil; + #left: (T, Tree); + #right: (T, Tree) + }; + + public func f0(l : List) : async Tree { l }; + public func f1(l : List) : async Tree { l }; + public func f2(l : List) : async Tree { #nil }; + public func f3(l : Tree) : async List { #nil }; + public func f4(l : Any) : async None { Prim.trap "bail" }; + + public func send_f0( + f : shared List -> async Tree + ) : async () { + Prim.debugPrint("ok 0"); + }; + + public func send_f1( + a : [shared List -> async Tree] + ) : async () { + Prim.debugPrint("ok 0"); + }; + + func tabulate(n : Nat, v : T) : [T] { + Prim.Array_tabulate(n, func (_ : Nat) : T { v }); + }; + + public func go() : async () { + await this.send_f0(f0); + await this.send_f0(f1); + await this.send_f0(f2); + await this.send_f0(f3); + await this.send_f0(f4); + + await this.send_f1(tabulate(1024, f0)); + await this.send_f1(tabulate(1024, f1)); + await this.send_f1(tabulate(1024, f2)); + await this.send_f1(tabulate(1024, f3)); + await this.send_f1(tabulate(1024, f4)); + + }; + + +} +//SKIP run +//SKIP run-ir +//SKIP run-low +///SKIP comp-ref +//CALL ingress go "DIDL\x00\x00" \ No newline at end of file diff --git a/test/run-drun/ok/idl-sub-rec.drun-run.ok b/test/run-drun/ok/idl-sub-rec.drun-run.ok new file mode 100644 index 00000000000..1ca8e07e4ba --- /dev/null +++ b/test/run-drun/ok/idl-sub-rec.drun-run.ok @@ -0,0 +1,13 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok b/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok new file mode 100644 index 00000000000..d96f46a4c3f --- /dev/null +++ b/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok @@ -0,0 +1,16 @@ +→ update create_canister(record {settings = null}) +← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… +← replied: () +→ update go() +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +debug.print: ok 0 +← replied: () From e36a6cbec1d02730e11db4a1aa644f5908bb4473 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 5 Apr 2022 11:28:57 +0100 Subject: [PATCH 069/128] formatting --- test/run-drun/idl-sub-rec.mo | 98 ++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/test/run-drun/idl-sub-rec.mo b/test/run-drun/idl-sub-rec.mo index ea9e104aff0..852b39f51f2 100644 --- a/test/run-drun/idl-sub-rec.mo +++ b/test/run-drun/idl-sub-rec.mo @@ -1,56 +1,54 @@ import Prim "mo:⛔"; - +// test candid subtype check on recursive types actor this { - type List = { - #nil; - #left:(T,List) - }; - - type Tree = { - #nil; - #left: (T, Tree); - #right: (T, Tree) - }; - - public func f0(l : List) : async Tree { l }; - public func f1(l : List) : async Tree { l }; - public func f2(l : List) : async Tree { #nil }; - public func f3(l : Tree) : async List { #nil }; - public func f4(l : Any) : async None { Prim.trap "bail" }; - - public func send_f0( - f : shared List -> async Tree - ) : async () { - Prim.debugPrint("ok 0"); - }; - - public func send_f1( - a : [shared List -> async Tree] - ) : async () { - Prim.debugPrint("ok 0"); - }; - - func tabulate(n : Nat, v : T) : [T] { - Prim.Array_tabulate(n, func (_ : Nat) : T { v }); - }; - - public func go() : async () { - await this.send_f0(f0); - await this.send_f0(f1); - await this.send_f0(f2); - await this.send_f0(f3); - await this.send_f0(f4); - - await this.send_f1(tabulate(1024, f0)); - await this.send_f1(tabulate(1024, f1)); - await this.send_f1(tabulate(1024, f2)); - await this.send_f1(tabulate(1024, f3)); - await this.send_f1(tabulate(1024, f4)); - - }; - - + type List = { + #nil; + #left:(T,List) + }; + + type Tree = { + #nil; + #left: (T, Tree); + #right: (T, Tree) + }; + + public func f0(l : List) : async Tree { l }; + public func f1(l : List) : async Tree { l }; + public func f2(l : List) : async Tree { #nil }; + public func f3(l : Tree) : async List { #nil }; + public func f4(l : Any) : async None { Prim.trap "bail" }; + + public func send_f0( + f : shared List -> async Tree + ) : async () { + Prim.debugPrint("ok 0"); + }; + + public func send_f1( + a : [shared List -> async Tree] + ) : async () { + Prim.debugPrint("ok 0"); + }; + + func tabulate(n : Nat, v : T) : [T] { + Prim.Array_tabulate(n, func (_ : Nat) : T { v }); + }; + + public func go() : async () { + await this.send_f0(f0); + await this.send_f0(f1); + await this.send_f0(f2); + await this.send_f0(f3); + await this.send_f0(f4); + + // test vectors, should benefit from memoization + await this.send_f1(tabulate(1024, f0)); + await this.send_f1(tabulate(1024, f1)); + await this.send_f1(tabulate(1024, f2)); + await this.send_f1(tabulate(1024, f3)); + await this.send_f1(tabulate(1024, f4)); + }; } //SKIP run //SKIP run-ir From 3c68763b1140dc75667fb15eab7254173635c97c Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 5 Apr 2022 13:17:38 +0100 Subject: [PATCH 070/128] found bug --- test/run-drun/idl-sub-rec.mo | 213 +++++++++++++++++++++++++++++++---- 1 file changed, 192 insertions(+), 21 deletions(-) diff --git a/test/run-drun/idl-sub-rec.mo b/test/run-drun/idl-sub-rec.mo index 852b39f51f2..1a1bb8fe928 100644 --- a/test/run-drun/idl-sub-rec.mo +++ b/test/run-drun/idl-sub-rec.mo @@ -4,54 +4,225 @@ actor this { type List = { #nil; - #left:(T,List) + #left: (T, List) }; - type Tree = { + type Seq = { #nil; - #left: (T, Tree); - #right: (T, Tree) + #left: (T, Seq); + #right: (T, Seq) }; - public func f0(l : List) : async Tree { l }; - public func f1(l : List) : async Tree { l }; - public func f2(l : List) : async Tree { #nil }; - public func f3(l : Tree) : async List { #nil }; + type EvenList = { + #nil; + #left: + (T, { + //#nil; + #left: (T, EvenList)}) + }; + + type EvenSeq = { + #nil; + #left: (T, { + // #nil; + #left: (T, EvenSeq); + #right: (T, EvenSeq) + }); + #right: (T, { + // #nil; + #left: (T, EvenSeq); + #right: (T, EvenSeq)}); + }; + + // sanity subtype checks, verify: + // List <: Seq + // EvenList <: List + // EvenSeq <: Seq + func sub1(t : List) : Seq { t }; + func sub2(t : EvenList) : List { t }; + func sub3(t : EvenSeq) : Seq { t }; + + public func f0(l : Seq) : async EvenList { #nil }; + public func f1(l : List) : async Seq { l }; + public func f2(l : List) : async Seq { #nil }; + public func f3(l : Seq) : async List { #nil }; public func f4(l : Any) : async None { Prim.trap "bail" }; public func send_f0( - f : shared List -> async Tree + f : shared EvenList -> async Seq ) : async () { Prim.debugPrint("ok 0"); }; public func send_f1( - a : [shared List -> async Tree] + a : [shared EvenList -> async Seq] + ) : async () { + Prim.debugPrint("ok 0"); + }; + + public func send_f2( + f : shared List -> async EvenSeq + ) : async () { + Prim.debugPrint("ok 0"); + }; + + public func send_f3( + a : [shared List -> async EvenSeq] + ) : async () { + Prim.debugPrint("ok 0"); + }; + + public func send_f4( + a : [?(shared List -> async EvenSeq)] ) : async () { Prim.debugPrint("ok 0"); }; + func tabulate(n : Nat, v : T) : [T] { Prim.Array_tabulate(n, func (_ : Nat) : T { v }); }; public func go() : async () { - await this.send_f0(f0); - await this.send_f0(f1); - await this.send_f0(f2); - await this.send_f0(f3); - await this.send_f0(f4); + + let t = debug_show (Prim.principalOfActor(this)); + + do { + try { + await this.send_f0(f0); + } + catch e { + Prim.debugPrint "wrong_0"; }; + }; + + do { + let this = actor (t) : actor { + send_f0 : (shared List -> async Seq) -> async (); + }; + try { + await this.send_f0(f0); + } + catch e { + Prim.debugPrint "wrong_1"; }; + }; + + + do { + let this = actor (t) : actor { + send_f0 : (shared Seq -> async List) -> async (); + }; + try { + await this.send_f0(f0); + } + catch e { + Prim.debugPrint "wrong_2"; }; + }; + + do { + let this = actor (t) : actor { + send_f0 : (shared Seq -> async List) -> async (); + }; + try { + await this.send_f0(f0); + } + catch e { + Prim.debugPrint "wrong_3"; + }; + }; + + do { + let this = actor (t) : actor { + send_f0 : (shared EvenSeq -> async EvenList) -> async (); + }; + try { + await this.send_f0(f0); + } + catch e { + Prim.debugPrint "wrong_4"; + }; + }; + + // negative test + do { + let this = actor (t) : actor { + send_f2 : (shared EvenList -> async Seq) -> async (); + }; + try { + await this.send_f2(f0); + Prim.debugPrint "wrong_5"; + } + catch e { + Prim.debugPrint ("ok 5" # Prim.errorMessage(e)) + }; + }; // test vectors, should benefit from memoization - await this.send_f1(tabulate(1024, f0)); - await this.send_f1(tabulate(1024, f1)); - await this.send_f1(tabulate(1024, f2)); - await this.send_f1(tabulate(1024, f3)); - await this.send_f1(tabulate(1024, f4)); + do { + try { + await this.send_f1(tabulate(1024, f0)); + } + catch e { + Prim.debugPrint "wrong_6"; + }; + }; + + do { + let this = actor (t) : actor { + send_f1 : [shared List -> async Seq] -> async (); + }; + try { + await this.send_f1(tabulate(1024, f0)); + } + catch e { + Prim.debugPrint "wrong_7"; + }; + }; + + do { + let this = actor (t) : actor { + send_f1 : [shared Seq -> async List] -> async (); + }; + try { + await this.send_f1(tabulate(1024, f0)); + } + catch e { + Prim.debugPrint "wrong_8"; + }; + }; + + // negative test + do { + let this = actor (t) : actor { + send_f3 : [shared EvenList -> async Seq] -> async (); + }; + try { + await this.send_f3(tabulate(1024, f0)); + Prim.debugPrint "wrong_9"; + } + catch e { + Prim.debugPrint ("ok 9" # Prim.errorMessage(e)) + }; + }; + + // test defaulting + do { + let this = actor (t) : actor { + send_f4 : [?(shared EvenList -> async Seq)] -> async (); + }; + try { + await this.send_f4(tabulate(1024, ?f0)); + Prim.debugPrint ("ok 10") + } + catch e { + Prim.debugPrint ("wrong_10" # Prim.errorMessage(e)) + }; + }; + + }; } //SKIP run //SKIP run-ir //SKIP run-low -///SKIP comp-ref +//SKIP comp-ref //CALL ingress go "DIDL\x00\x00" \ No newline at end of file From 1f613d12d6d5df6f1150f635a16dcea520cad637 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 6 Apr 2022 11:05:15 +0100 Subject: [PATCH 071/128] fix bug (skip value on idl_sub failure); add test for recursive types --- src/codegen/compile.ml | 8 +++-- test/run-drun/idl-sub-rec.mo | 39 ++++++++++++---------- test/run-drun/ok/idl-sub-rec.drun-run.ok | 29 ++++++++++------ test/run-drun/ok/idl-sub-rec.ic-ref-run.ok | 29 ++++++++++------ 4 files changed, 65 insertions(+), 40 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index e554961d962..a412f5c772b 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5492,7 +5492,8 @@ module Serialization = struct read_text () ^^ Tuple.from_stack env 2 ])) - (coercion_failed "IDL error: incompatible function type") + (skip get_idltyp ^^ + coercion_failed "IDL error: incompatible function type") | Obj (Actor, _) -> get_rel_buf_opt ^^ G.if1 I32Type @@ -5508,7 +5509,8 @@ module Serialization = struct G.if1 I32Type (with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data ())) - (coercion_failed "IDL error: incompatible actor type") + (skip get_idltyp ^^ + coercion_failed "IDL error: incompatible actor type") | Mut t -> read_alias env (Mut t) (fun get_arg_typ on_alloc -> let (set_result, get_result) = new_local env "result" in @@ -5655,8 +5657,8 @@ module Serialization = struct compile_unboxed_const 0l ^^ (* initial depth *) can_recover ^^ deserialize_go env t ^^ set_val ^^ - get_val ^^ compile_eq_const (coercion_error_value env) ^^ get_arg_count ^^ compile_sub_const 1l ^^ set_arg_count ^^ + get_val ^^ compile_eq_const (coercion_error_value env) ^^ (G.if1 I32Type (default_or_trap "IDL error: coercion failure encountered") get_val) diff --git a/test/run-drun/idl-sub-rec.mo b/test/run-drun/idl-sub-rec.mo index 1a1bb8fe928..b98c3f9a822 100644 --- a/test/run-drun/idl-sub-rec.mo +++ b/test/run-drun/idl-sub-rec.mo @@ -43,39 +43,35 @@ actor this { func sub3(t : EvenSeq) : Seq { t }; public func f0(l : Seq) : async EvenList { #nil }; - public func f1(l : List) : async Seq { l }; - public func f2(l : List) : async Seq { #nil }; - public func f3(l : Seq) : async List { #nil }; - public func f4(l : Any) : async None { Prim.trap "bail" }; public func send_f0( f : shared EvenList -> async Seq ) : async () { - Prim.debugPrint("ok 0"); + Prim.debugPrint("ok f0"); }; public func send_f1( a : [shared EvenList -> async Seq] ) : async () { - Prim.debugPrint("ok 0"); + Prim.debugPrint("ok f1"); }; public func send_f2( f : shared List -> async EvenSeq ) : async () { - Prim.debugPrint("ok 0"); + Prim.debugPrint("ok f2"); }; public func send_f3( a : [shared List -> async EvenSeq] ) : async () { - Prim.debugPrint("ok 0"); + Prim.debugPrint("ok f3"); }; public func send_f4( a : [?(shared List -> async EvenSeq)] ) : async () { - Prim.debugPrint("ok 0"); + Prim.debugPrint("ok f4"); }; @@ -90,9 +86,11 @@ actor this { do { try { await this.send_f0(f0); + Prim.debugPrint "ok_0"; } catch e { - Prim.debugPrint "wrong_0"; }; + Prim.debugPrint "wrong_0"; + }; }; do { @@ -101,9 +99,11 @@ actor this { }; try { await this.send_f0(f0); + Prim.debugPrint "ok_1"; } catch e { - Prim.debugPrint "wrong_1"; }; + Prim.debugPrint "wrong_1"; + }; }; @@ -113,9 +113,11 @@ actor this { }; try { await this.send_f0(f0); + Prim.debugPrint "ok_2"; } catch e { - Prim.debugPrint "wrong_2"; }; + Prim.debugPrint "wrong_2"; + }; }; do { @@ -124,6 +126,7 @@ actor this { }; try { await this.send_f0(f0); + Prim.debugPrint "ok_3"; } catch e { Prim.debugPrint "wrong_3"; @@ -136,6 +139,7 @@ actor this { }; try { await this.send_f0(f0); + Prim.debugPrint "ok_4"; } catch e { Prim.debugPrint "wrong_4"; @@ -152,7 +156,7 @@ actor this { Prim.debugPrint "wrong_5"; } catch e { - Prim.debugPrint ("ok 5" # Prim.errorMessage(e)) + Prim.debugPrint ("ok 5:" # Prim.errorMessage(e)) }; }; @@ -160,6 +164,7 @@ actor this { do { try { await this.send_f1(tabulate(1024, f0)); + Prim.debugPrint "ok_6"; } catch e { Prim.debugPrint "wrong_6"; @@ -184,6 +189,7 @@ actor this { }; try { await this.send_f1(tabulate(1024, f0)); + Prim.debugPrint "ok_8"; } catch e { Prim.debugPrint "wrong_8"; @@ -200,18 +206,18 @@ actor this { Prim.debugPrint "wrong_9"; } catch e { - Prim.debugPrint ("ok 9" # Prim.errorMessage(e)) + Prim.debugPrint ("ok_9" # Prim.errorMessage(e)) }; }; - // test defaulting + // test vector defaulting, should benefit from memoization do { let this = actor (t) : actor { send_f4 : [?(shared EvenList -> async Seq)] -> async (); }; try { await this.send_f4(tabulate(1024, ?f0)); - Prim.debugPrint ("ok 10") + Prim.debugPrint ("ok_10") } catch e { Prim.debugPrint ("wrong_10" # Prim.errorMessage(e)) @@ -224,5 +230,4 @@ actor this { //SKIP run //SKIP run-ir //SKIP run-low -//SKIP comp-ref //CALL ingress go "DIDL\x00\x00" \ No newline at end of file diff --git a/test/run-drun/ok/idl-sub-rec.drun-run.ok b/test/run-drun/ok/idl-sub-rec.drun-run.ok index 1ca8e07e4ba..88b93db6860 100644 --- a/test/run-drun/ok/idl-sub-rec.drun-run.ok +++ b/test/run-drun/ok/idl-sub-rec.drun-run.ok @@ -1,13 +1,22 @@ ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 ingress Completed: Reply: 0x4449444c0000 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 +debug.print: ok f0 +debug.print: ok_0 +debug.print: ok f0 +debug.print: ok_1 +debug.print: ok f0 +debug.print: ok_2 +debug.print: ok f0 +debug.print: ok_3 +debug.print: ok f0 +debug.print: ok_4 +debug.print: ok 5:IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: incompatible function type +debug.print: ok f1 +debug.print: ok_6 +debug.print: ok f1 +debug.print: ok f1 +debug.print: ok_8 +debug.print: ok_9IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: incompatible function type +debug.print: ok f4 +debug.print: ok_10 ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok b/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok index d96f46a4c3f..0aefb98889e 100644 --- a/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok @@ -3,14 +3,23 @@ → update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… ← replied: () → update go() -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 -debug.print: ok 0 +debug.print: ok f0 +debug.print: ok_0 +debug.print: ok f0 +debug.print: ok_1 +debug.print: ok f0 +debug.print: ok_2 +debug.print: ok f0 +debug.print: ok_3 +debug.print: ok f0 +debug.print: ok_4 +debug.print: ok 5:canister trapped: EvalTrapError region:0xXXX-0xXXX "canister trapped explicitly: IDL error: incompatible function type" +debug.print: ok f1 +debug.print: ok_6 +debug.print: ok f1 +debug.print: ok f1 +debug.print: ok_8 +debug.print: ok_9canister trapped: EvalTrapError region:0xXXX-0xXXX "canister trapped explicitly: IDL error: incompatible function type" +debug.print: ok f4 +debug.print: ok_10 ← replied: () From 84faad6ea259c89edea36a5f510d9ace21153b30 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 6 Apr 2022 12:01:42 +0100 Subject: [PATCH 072/128] test for stack underflow for dynamic stack allocations --- src/codegen/compile.ml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index a412f5c772b..8eba2c4c08c 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -1057,8 +1057,12 @@ module Stack = struct f get_x ^^ free_words env n - (* TODO: check for overflow *) let dynamic_alloc_words env get_n = + get_stack_ptr env ^^ + compile_divU_const Heap.word_size ^^ + get_n ^^ + G.i (Compare (Wasm.Values.I32 I32Op.LtU)) ^^ + E.then_trap_with env "RTS Stack underflow" ^^ get_stack_ptr env ^^ get_n ^^ compile_mul_const Heap.word_size ^^ @@ -8753,7 +8757,7 @@ The compilation of declarations (and patterns!) needs to handle mutual recursion This requires conceptually three passes: 1. First we need to collect all names bound in a block, and find locations for then (which extends the environment). - The environment is extended monotonously: The type-checker ensures that + The environment is extended monotonicly: The type-checker ensures that a Block does not bind the same name twice. We would not need to pass in the environment, just out ... but because it is bundled in the E.t type, threading it through is also easy. From 39ef5a154dd489f6b6f30410ac275d7ad4193a16 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 6 Apr 2022 12:31:06 +0100 Subject: [PATCH 073/128] refactor RTS idl_sub and bitrel to avoid setting bits for initial assumptions (by negating bit representation) --- rts/motoko-rts/src/bitrel.rs | 26 ++++++++++++++++++++++++-- rts/motoko-rts/src/idl.rs | 13 ++++++------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 179c6f598fc..9e816ffa02f 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -64,7 +64,7 @@ impl BitRel { return (ptr, bit); } - pub(crate) unsafe fn set(&self, p: bool, i_j: u32, j_i: u32, bit: u32, v: bool) { + unsafe fn set(&self, p: bool, i_j: u32, j_i: u32, bit: u32, v: bool) { let (ptr, bit) = self.locate_ptr_bit(p, i_j, j_i, bit); if v { *ptr = *ptr | (1 << bit); @@ -73,9 +73,31 @@ impl BitRel { } } - pub(crate) unsafe fn get(&self, p: bool, i_j: u32, j_i: u32, bit: u32) -> bool { + unsafe fn get(&self, p: bool, i_j: u32, j_i: u32, bit: u32) -> bool { let (ptr, bit) = self.locate_ptr_bit(p, i_j, j_i, bit); let mask = 1 << bit; return *ptr & mask == mask; } + + pub(crate) unsafe fn visited(&self, p: bool, i_j: u32, j_i: u32) -> bool { + self.get(p, i_j, j_i, 0) + } + + pub(crate) unsafe fn visit(&self, p: bool, i_j: u32, j_i: u32) -> () { + self.set(p, i_j, j_i, 0, true) + } + + // NB: we store related bits in negated form to avoid setting on assumption + // This code is a nop in production code. + pub(crate) unsafe fn assume(&self, p: bool, i_j: u32, j_i: u32) -> () { + debug_assert!(!self.get(p, i_j, j_i, 1)); + } + + pub(crate) unsafe fn related(&self, p: bool, i_j: u32, j_i: u32) -> bool { + !self.get(p, i_j, j_i, 1) + } + + pub(crate) unsafe fn disprove(&self, p: bool, i_j: u32, j_i: u32) -> () { + self.set(p, i_j, j_i, 1, true) + } } diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index febf4149ea4..a811f985671 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -546,14 +546,14 @@ unsafe fn sub( if t1 >= 0 && t2 >= 0 { let t1 = t1 as u32; let t2 = t2 as u32; - if rel.get(p, t1, t2, 0) { + if rel.visited(p, t1, t2) { // visited? (bit 0) - // return assumed or determined result (bit 1) - return rel.get(p, t1, t2, 1); + // return assumed or determined result + return rel.related(p, t1, t2); }; // cache and continue - rel.set(p, t1, t2, 0, true); // mark bit 0 visited (bit 0) - rel.set(p, t1, t2, 1, true); // assume t1 <:/:> t2 true (bit 1) + rel.visit(p, t1, t2); // mark visited + rel.assume(p, t1, t2); // assume t1 <:/:> t2 true }; /* primitives reflexive */ @@ -796,8 +796,7 @@ unsafe fn sub( } // remember negative result ... if t1 >= 0 && t2 >= 0 { - // falsify t1 <:/:> t2 (bit 1) - rel.set(p, t1 as u32, t2 as u32, 1, false); + rel.disprove(p, t1 as u32, t2 as u32); } // .. only then return false return false; From d311afd553207161f7cedf444aa630ff53085c7d Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 6 Apr 2022 12:39:24 +0100 Subject: [PATCH 074/128] add compile.ml TODO referencing ISSUE --- src/codegen/compile.ml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 8eba2c4c08c..75efd2911cb 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5596,6 +5596,9 @@ module Serialization = struct let deserialize_from_blob extended env ts = let ts_name = typ_seq_hash ts in let name = + (* TODO(#3185): this specialization on `extended` seems redundant, + removing it might simplify things *and* share more code in binaries. + The only tricky bit might be the conditional Stack.dynamic_with_words bit... *) if extended then "@deserialize_extended<" ^ ts_name ^ ">" else "@deserialize<" ^ ts_name ^ ">" in From 358639de367f96bf3de7b76efd819cd5354cca19 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 6 Apr 2022 12:46:22 +0100 Subject: [PATCH 075/128] add TODO --- rts/motoko-rts/src/idl.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index a811f985671..67d0494d6d4 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -533,6 +533,7 @@ unsafe fn is_null_opt_reserved(typtbl: *mut *mut u8, end: *mut u8, t: i32) -> bo // https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 // https://github.com/dfinity/candid/blob/20b84d1c1515e2c1db353ebe02b738486f835466/spec/Candid.md +// TODO: consider storing fixed args typtbl1...end2 in `rel` to use less stack. unsafe fn sub( rel: &BitRel, p: bool, From 6f217e50afb7d64fcad50dbdd837fca787993b78 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 6 Apr 2022 14:08:01 +0100 Subject: [PATCH 076/128] Update src/codegen/compile.ml --- src/codegen/compile.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 75efd2911cb..d09f997c449 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -8760,7 +8760,7 @@ The compilation of declarations (and patterns!) needs to handle mutual recursion This requires conceptually three passes: 1. First we need to collect all names bound in a block, and find locations for then (which extends the environment). - The environment is extended monotonicly: The type-checker ensures that + The environment is extended monotonically: The type-checker ensures that a Block does not bind the same name twice. We would not need to pass in the environment, just out ... but because it is bundled in the E.t type, threading it through is also easy. From 9632450ebdb45a240c98464532c4cb4a56809a7a Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 6 Apr 2022 14:35:59 +0100 Subject: [PATCH 077/128] add sanity check --- rts/motoko-rts/src/bitrel.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 9e816ffa02f..0e6354bbdeb 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -24,6 +24,10 @@ impl BitRel { } pub(crate) unsafe fn init(&self) { + if (self.end as usize) < (self.ptr as usize) { + idl_trap_with("BitRel invalid fields"); + }; + let bytes = ((self.end as usize) - (self.ptr as usize)) as u32; if (2 * self.size1 * self.size2 * BITS) > bytes * 8 { idl_trap_with("BitRel not enough bytes"); From 405924679e5e680b397a257835da3c422aa0b1e3 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 6 Apr 2022 15:31:41 +0100 Subject: [PATCH 078/128] fix build after merge --- src/codegen/compile.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index ee4db921dd3..cd3cd375877 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -8199,7 +8199,7 @@ and compile_prim_invocation (env : E.t) ae p es at = | ICStableSize t, [e] -> SR.UnboxedWord64, - let tydesc = Serialization.type_desc env [t] in + let (tydesc, _, _) = Serialization.type_desc env [t] in let tydesc_len = Int32.of_int (String.length tydesc) in compile_exp_vanilla env ae e ^^ Serialization.buffer_size env t ^^ From 3cf157ceb52cecda7ceaf18270ee70f7f72f4d82 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 7 Apr 2022 11:13:21 +0100 Subject: [PATCH 079/128] Apply suggestions from code review Co-authored-by: Joachim Breitner --- src/codegen/compile.ml | 16 ++++++++-------- test/run-drun/idl-sub-ho.mo | 2 +- test/run-drun/idl-sub-rec.mo | 2 +- test/run-drun/idl-sub.mo | 3 +-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index cd3cd375877..9f8e8c814c1 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -814,7 +814,7 @@ module RTS = struct E.add_func_import env "rts" "parse_idl_header" [I32Type; I32Type; I32Type; I32Type; I32Type] []; E.add_func_import env "rts" "idl_sub_buf_words" [I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "idl_sub" - [I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type] [I32Type]; + (i32s 9) [I32Type]; E.add_func_import env "rts" "leb128_decode" [I32Type] [I32Type]; E.add_func_import env "rts" "sleb128_decode" [I32Type] [I32Type]; E.add_func_import env "rts" "bigint_of_word32" [I32Type] [I32Type]; @@ -5038,7 +5038,7 @@ module MakeSerialization (Strm : Stream) = struct let idl_sub env t2 = - let idx = List.length (!(env.E.typtbl_typs)) in + let idx = List.length !(env.E.typtbl_typs) in env.E.typtbl_typs := !(env.E.typtbl_typs) @ [t2]; get_typtbl_idltyps env ^^ compile_add_const (Int32.of_int (idx * 4)) ^^ @@ -5224,7 +5224,7 @@ module MakeSerialization (Strm : Stream) = struct let read_actor_data () = read_byte_tagged - [ E.trap_with env ("IDL error: unexpected actor reference") + [ E.trap_with env "IDL error: unexpected actor reference" ; read_principal () ] in @@ -5653,7 +5653,7 @@ module MakeSerialization (Strm : Stream) = struct G.if1 I32Type (with_composite_typ idl_func (fun _get_typ_buf -> read_byte_tagged - [ E.trap_with env ("IDL error: unexpected function reference") + [ E.trap_with env "IDL error: unexpected function reference" ; read_actor_data () ^^ read_text () ^^ Tuple.from_stack env 2 @@ -5807,12 +5807,12 @@ module MakeSerialization (Strm : Stream) = struct let can_recover, default_or_trap = Type.( match normalize t with | Prim Null | Opt _ | Any -> - (compile_unboxed_one, fun msg -> Opt.null_lit env) + (true, fun msg -> Opt.null_lit env) | _ -> - (compile_unboxed_zero, fun msg -> E.trap_with env msg)) + (false, fun msg -> E.trap_with env msg)) in get_arg_count ^^ - compile_rel_const I32Op.Eq 0l ^^ + compile_eq_const 0l ^^ G.if1 I32Type (default_or_trap ("IDL error: too few arguments " ^ ts_name)) (begin @@ -5823,7 +5823,7 @@ module MakeSerialization (Strm : Stream) = struct get_typtbl_size_ptr ^^ load_unskewed_ptr ^^ ReadBuf.read_sleb128 env get_main_typs_buf ^^ compile_unboxed_const 0l ^^ (* initial depth *) - can_recover ^^ + Bool.lit can_recover ^^ deserialize_go env t ^^ set_val ^^ get_arg_count ^^ compile_sub_const 1l ^^ set_arg_count ^^ get_val ^^ compile_eq_const (coercion_error_value env) ^^ diff --git a/test/run-drun/idl-sub-ho.mo b/test/run-drun/idl-sub-ho.mo index 30a3bd0dd1f..85ed78331cd 100644 --- a/test/run-drun/idl-sub-ho.mo +++ b/test/run-drun/idl-sub-ho.mo @@ -238,4 +238,4 @@ actor this { //SKIP run //SKIP run-ir //SKIP run-low -//CALL ingress go "DIDL\x00\x00" \ No newline at end of file +//CALL ingress go "DIDL\x00\x00" diff --git a/test/run-drun/idl-sub-rec.mo b/test/run-drun/idl-sub-rec.mo index b98c3f9a822..f6dc181e52b 100644 --- a/test/run-drun/idl-sub-rec.mo +++ b/test/run-drun/idl-sub-rec.mo @@ -230,4 +230,4 @@ actor this { //SKIP run //SKIP run-ir //SKIP run-low -//CALL ingress go "DIDL\x00\x00" \ No newline at end of file +//CALL ingress go "DIDL\x00\x00" diff --git a/test/run-drun/idl-sub.mo b/test/run-drun/idl-sub.mo index 7b3e5b26551..3eb39531df9 100644 --- a/test/run-drun/idl-sub.mo +++ b/test/run-drun/idl-sub.mo @@ -172,7 +172,6 @@ actor this { await this.send_f13(f13); await this.send_f14(f14); await this.send_f15(f15); - }; @@ -180,4 +179,4 @@ actor this { //SKIP run //SKIP run-ir //SKIP run-low -//CALL ingress go "DIDL\x00\x00" \ No newline at end of file +//CALL ingress go "DIDL\x00\x00" From b453486ee65861dff60f1b7f8676e8d41d0810ab Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 7 Apr 2022 13:13:43 +0100 Subject: [PATCH 080/128] revert use of i32s - not available here --- src/codegen/compile.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 9f8e8c814c1..0f8d62ef560 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -814,7 +814,7 @@ module RTS = struct E.add_func_import env "rts" "parse_idl_header" [I32Type; I32Type; I32Type; I32Type; I32Type] []; E.add_func_import env "rts" "idl_sub_buf_words" [I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "idl_sub" - (i32s 9) [I32Type]; + [I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "leb128_decode" [I32Type] [I32Type]; E.add_func_import env "rts" "sleb128_decode" [I32Type] [I32Type]; E.add_func_import env "rts" "bigint_of_word32" [I32Type] [I32Type]; From d52d84cd7de59d998455042e4502fc61b06a5c59 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 8 Apr 2022 15:57:22 +0100 Subject: [PATCH 081/128] sort out nulls --- rts/motoko-rts/src/idl.rs | 12 ++++++------ src/codegen/compile.ml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 67d0494d6d4..93e2cb39702 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -513,9 +513,9 @@ unsafe extern "C" fn skip_fields(tb: *mut Buf, buf: *mut Buf, typtbl: *mut *mut } } -unsafe fn is_null_opt_reserved(typtbl: *mut *mut u8, end: *mut u8, t: i32) -> bool { +unsafe fn is_opt_reserved(typtbl: *mut *mut u8, end: *mut u8, t: i32) -> bool { if is_primitive_type(t) { - return t == IDL_PRIM_null || t == IDL_PRIM_reserved; + return t == IDL_PRIM_reserved; } // unfold t @@ -619,7 +619,7 @@ unsafe fn sub( for _ in 0..in1 { let t11 = sleb128_decode(&mut tb1); if in2 == 0 { - if !is_null_opt_reserved(typtbl1, end1, t11) { + if !is_opt_reserved(typtbl1, end1, t11) { break 'return_false; } } else { @@ -641,7 +641,7 @@ unsafe fn sub( for _ in 0..out2 { let t21 = sleb128_decode(&mut tb2); if out1 == 0 { - if !is_null_opt_reserved(typtbl2, end2, t21) { + if !is_opt_reserved(typtbl2, end2, t21) { break 'return_false; } } else { @@ -695,7 +695,7 @@ unsafe fn sub( let t21 = sleb128_decode(&mut tb2); if n1 == 0 { // check all remaining fields optional - if !is_null_opt_reserved(typtbl2, end2, t21) { + if !is_opt_reserved(typtbl2, end2, t21) { break 'return_false; } continue; @@ -711,7 +711,7 @@ unsafe fn sub( } }; if tag1 > tag2 { - if !is_null_opt_reserved(typtbl2, end2, t21) { + if !is_opt_reserved(typtbl2, end2, t21) { // missing, non_opt field break 'return_false; } diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 0f8d62ef560..6ff761312fd 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5806,7 +5806,7 @@ module MakeSerialization (Strm : Stream) = struct G.concat_map (fun t -> let can_recover, default_or_trap = Type.( match normalize t with - | Prim Null | Opt _ | Any -> + | Opt _ | Any -> (true, fun msg -> Opt.null_lit env) | _ -> (false, fun msg -> E.trap_with env msg)) From 12c5bfef18e5b0c2979bc08b418fe14b3a53c379 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 8 Apr 2022 17:02:52 +0100 Subject: [PATCH 082/128] test extra args --- test/run-drun/idl-sub-opt-any.mo | 102 ++++++++++++++++++ test/run-drun/ok/idl-sub-opt-any.drun-run.ok | 10 ++ .../run-drun/ok/idl-sub-opt-any.ic-ref-run.ok | 13 +++ 3 files changed, 125 insertions(+) create mode 100644 test/run-drun/idl-sub-opt-any.mo create mode 100644 test/run-drun/ok/idl-sub-opt-any.drun-run.ok create mode 100644 test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok diff --git a/test/run-drun/idl-sub-opt-any.mo b/test/run-drun/idl-sub-opt-any.mo new file mode 100644 index 00000000000..0f92195afaf --- /dev/null +++ b/test/run-drun/idl-sub-opt-any.mo @@ -0,0 +1,102 @@ +import Prim "mo:⛔"; + +// test candid subtype test with higher-order arguments +actor this { + + public func send_f0( + f : shared (a : Int) -> async Bool) + : async () { + Prim.debugPrint("ok_0"); + }; + + public func f0() : async () { }; + + public func f0_1_a(a : Int, n : Null) : async (Bool, Null) { (true, null) }; + public func f0_1_b(a : Int, n : ?Null) : async (Bool, ?Null) { (true, null) }; + public func f0_1_c(a : Int, n : Any) : async (Bool, Any) { (true, null) }; + public func f0_1_d(n : ?Null, a : Int) : async (?Null, Bool) { (null, true) }; + public func f0_1_e(n : Any, a : Int) : async (Any, Bool) { (null, true) }; + + + public func go() : async () { + let t = debug_show (Prim.principalOfActor(this)); + + // appending Null not ok + do { + let this = actor (t) : actor { + send_f0 : (shared (a : Int, n : Null) -> async (Bool, Null)) -> async (); + }; + try { + await this.send_f0(f0_1_a); + Prim.debugPrint "wrong_0_1_a"; + } + catch e { + Prim.debugPrint "ok_0_1_a"; + } + }; + + // appending ?_ ok + do { + let this = actor (t) : actor { + send_f0 : (shared (a : Int, n : ?Null) -> async (Bool, ?Null)) -> async (); + }; + try { + await this.send_f0(f0_1_b); + Prim.debugPrint "ok_0_1_b"; + + } + catch e { + Prim.debugPrint "wrong_0_1_b"; + } + }; + + // appending Any ok + do { + let this = actor (t) : actor { + send_f0 : (shared (a : Int, n : Any) -> async (Bool, Any)) -> async (); + }; + try { + await this.send_f0(f0_1_c); + Prim.debugPrint "ok_0_1_c"; + } + catch e { + Prim.debugPrint "wrong_0_1_c"; + } + }; + + // prepending Any not ok + do { + let this = actor (t) : actor { + send_f0 : (shared (n : ?Null, a : Int) -> async (?Null, Bool)) -> async (); + }; + try { + await this.send_f0(f0_1_d); + Prim.debugPrint "wrong_0_1_d"; + } + catch e { + Prim.debugPrint "ok_0_1_d"; + } + }; + + // prepending ?_ not ok + do { + let this = actor (t) : actor { + send_f0 : (shared (n : Any, a : Int) -> async (Any, Bool)) -> async (); + }; + try { + await this.send_f0(f0_1_e); + Prim.debugPrint "wrong_0_1_e"; + + } + catch e { + Prim.debugPrint "ok_0_1_e"; + } + }; + + }; + +} +//SKIP run +//SKIP run-ir +//SKIP run-low +//CALL ingress go "DIDL\x00\x00" \ No newline at end of file diff --git a/test/run-drun/ok/idl-sub-opt-any.drun-run.ok b/test/run-drun/ok/idl-sub-opt-any.drun-run.ok new file mode 100644 index 00000000000..3eccfc5383f --- /dev/null +++ b/test/run-drun/ok/idl-sub-opt-any.drun-run.ok @@ -0,0 +1,10 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: ok_0_1_a +debug.print: ok_0 +debug.print: ok_0_1_b +debug.print: ok_0 +debug.print: ok_0_1_c +debug.print: ok_0_1_d +debug.print: ok_0_1_e +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok b/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok new file mode 100644 index 00000000000..b07ee86e01a --- /dev/null +++ b/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok @@ -0,0 +1,13 @@ +→ update create_canister(record {settings = null}) +← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… +← replied: () +→ update go() +debug.print: ok_0_1_a +debug.print: ok_0 +debug.print: ok_0_1_b +debug.print: ok_0 +debug.print: ok_0_1_c +debug.print: ok_0_1_d +debug.print: ok_0_1_e +← replied: () From cc5bd7d97c9b9f5c910701b4344541d2f23bd9d0 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 8 Apr 2022 17:13:41 +0100 Subject: [PATCH 083/128] add tests for optional args/fields --- test/run-drun/idl-sub-opt-any-record.mo | 71 +++++++++++++++++++ test/run-drun/idl-sub-opt-any.mo | 2 +- .../ok/idl-sub-opt-any-record.drun-run.ok | 8 +++ .../ok/idl-sub-opt-any-record.ic-ref-run.ok | 11 +++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 test/run-drun/idl-sub-opt-any-record.mo create mode 100644 test/run-drun/ok/idl-sub-opt-any-record.drun-run.ok create mode 100644 test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok diff --git a/test/run-drun/idl-sub-opt-any-record.mo b/test/run-drun/idl-sub-opt-any-record.mo new file mode 100644 index 00000000000..be9f5effe35 --- /dev/null +++ b/test/run-drun/idl-sub-opt-any-record.mo @@ -0,0 +1,71 @@ +import Prim "mo:⛔"; + +// test candid subtype test with optional record extension +actor this { + + public func send_f0( + f : shared {a : Int} -> async {b : Bool}) + : async () { + Prim.debugPrint("ok_0"); + }; + + public func f0() : async () { }; + + public func f0_1_a({a : Int; n : Null}) : async {b : Bool; x : Null} { {b = true; x = null} }; + public func f0_1_b({a : Int; n : ?Null}) : async {b : Bool; x : ?Null} { {b = true; x = null} }; + public func f0_1_c({a : Int; n : Any}) : async {b : Bool; x : Any} { {b = true; x = null } }; + + + public func go() : async () { + let t = debug_show (Prim.principalOfActor(this)); + + // appending Null not ok + do { + let this = actor (t) : actor { + send_f0 : (shared {a : Int; n : Null } -> async {b : Bool; x : Null}) -> async (); + }; + try { + await this.send_f0(f0_1_a); + Prim.debugPrint "wrong_0_1_a"; + } + catch e { + Prim.debugPrint "ok_0_1_a"; + } + }; + + // appending ?_ ok + do { + let this = actor (t) : actor { + send_f0 : (shared {a : Int; n : ?Null} -> async {b : Bool; x : ?Null}) -> async (); + }; + try { + await this.send_f0(f0_1_b); + Prim.debugPrint "ok_0_1_b"; + + } + catch e { + Prim.debugPrint "wrong_0_1_b"; + } + }; + + // appending Any ok + do { + let this = actor (t) : actor { + send_f0 : (shared {a : Int; n : Any} -> async {b : Bool; x : Any}) -> async (); + }; + try { + await this.send_f0(f0_1_c); + Prim.debugPrint "ok_0_1_c"; + } + catch e { + Prim.debugPrint "wrong_0_1_c"; + } + }; + + }; + +} +//SKIP run +//SKIP run-ir +//SKIP run-low +//CALL ingress go "DIDL\x00\x00" \ No newline at end of file diff --git a/test/run-drun/idl-sub-opt-any.mo b/test/run-drun/idl-sub-opt-any.mo index 0f92195afaf..1d689c7007d 100644 --- a/test/run-drun/idl-sub-opt-any.mo +++ b/test/run-drun/idl-sub-opt-any.mo @@ -1,6 +1,6 @@ import Prim "mo:⛔"; -// test candid subtype test with higher-order arguments +// test candid subtype test with optional argument extension actor this { public func send_f0( diff --git a/test/run-drun/ok/idl-sub-opt-any-record.drun-run.ok b/test/run-drun/ok/idl-sub-opt-any-record.drun-run.ok new file mode 100644 index 00000000000..4eed30d4928 --- /dev/null +++ b/test/run-drun/ok/idl-sub-opt-any-record.drun-run.ok @@ -0,0 +1,8 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: ok_0_1_a +debug.print: ok_0 +debug.print: ok_0_1_b +debug.print: ok_0 +debug.print: ok_0_1_c +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok b/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok new file mode 100644 index 00000000000..7e2f3619f86 --- /dev/null +++ b/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok @@ -0,0 +1,11 @@ +→ update create_canister(record {settings = null}) +← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… +← replied: () +→ update go() +debug.print: ok_0_1_a +debug.print: ok_0 +debug.print: ok_0_1_b +debug.print: ok_0 +debug.print: ok_0_1_c +← replied: () From 298c36489b26192bdea9d43360afb811f46ec00b Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 8 Apr 2022 17:23:26 +0100 Subject: [PATCH 084/128] bump candid tests --- nix/sources.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nix/sources.json b/nix/sources.json index 42c1e7a3ef7..a7e95a3adc4 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -6,10 +6,10 @@ "homepage": "", "owner": "dfinity", "repo": "candid", - "rev": "9b0e92e8729e660bfdcf02a3169b9a4b829762a4", - "sha256": "0rh3n0wqkbj8ry2n2pgni18bfwn8x80cpk741kis3d7l61n808jk", + "rev": "734b796a7c2ffc8f4bb317c99ee3281d54bb36d5", + "sha256": "0nx0bw0r3l9zpvczrh0w97sng2900hh987yx7gakzahff4albl5v", "type": "tarball", - "url": "https://github.com/dfinity/candid/archive/9b0e92e8729e660bfdcf02a3169b9a4b829762a4.tar.gz", + "url": "https://github.com/dfinity/candid/archive/734b796a7c2ffc8f4bb317c99ee3281d54bb36d5.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "esm": { From ef7f5dd178eb6e81d74f30ae22aea6476bfdd8e2 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Sat, 9 Apr 2022 21:32:55 +0100 Subject: [PATCH 085/128] experiments to get extended candid-tests passing --- nix/sources.json | 6 +++--- src/exes/candid_tests.ml | 10 +++++----- src/mo_idl/idl_to_mo_value.ml | 3 ++- src/mo_types/type.ml | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/nix/sources.json b/nix/sources.json index a7e95a3adc4..768cdc83266 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -6,10 +6,10 @@ "homepage": "", "owner": "dfinity", "repo": "candid", - "rev": "734b796a7c2ffc8f4bb317c99ee3281d54bb36d5", - "sha256": "0nx0bw0r3l9zpvczrh0w97sng2900hh987yx7gakzahff4albl5v", + "rev": "0889e288c8c44ce36682ffa67df010c83e912a33", + "sha256": "122v440prlcr0z6zj1a7j0rjpk1a2xwpvj8vxrdbldl6ss1krbff", "type": "tarball", - "url": "https://github.com/dfinity/candid/archive/734b796a7c2ffc8f4bb317c99ee3281d54bb36d5.tar.gz", + "url": "https://github.com/dfinity/candid/archive/0889e288c8c44ce36682ffa67df010c83e912a33.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "esm": { diff --git a/src/exes/candid_tests.ml b/src/exes/candid_tests.ml index e7f219d5f6d..0d672484b4b 100644 --- a/src/exes/candid_tests.ml +++ b/src/exes/candid_tests.ml @@ -78,7 +78,7 @@ let mo_of_test tenv test : (string * expected_behaviour, string) result = let not_equal e1 e2 = "assert (" ^ e1 ^ " != " ^ e2 ^ ")\n" in let ignore ts e = let open Type in - if sub (seq ts) unit then e (* avoid warnign about redundant ignore *) + if sub (seq ts) unit then e (* avoid warning about redundant ignore *) else "ignore (" ^ e ^ ")\n" in try @@ -155,7 +155,7 @@ type outcome = | UnwantedTrap of (string * string) (* stdout, stderr *) | Timeout | Ignored of string - | CantCompile of (string * string) (* stdout, stderr *) + | CantCompile of (string * string * string) (* stdout, stderr, src *) let red s = "\027[31m" ^ s ^ "\027[0m" let green s = "\027[32m" ^ s ^ "\027[0m" @@ -197,9 +197,9 @@ let report_outcome counts expected_fail outcome = | _, Ignored why -> bump counts.ignored; Printf.printf " %s\n" (grey (Printf.sprintf "ignored (%s)" why)) - | _, CantCompile (stdout, stderr) -> + | _, CantCompile (stdout, stderr, src) -> bump counts.fail; - Printf.printf " %s\n%s%s\n" (red "not ok (cannot compile)") stdout stderr + Printf.printf " %s\n%s%s\n%s" (red "not ok (cannot compile)") stdout stderr src (* Main *) let () = @@ -260,7 +260,7 @@ let () = Unix.putenv "MOC_UNLOCK_PRIM" "yesplease"; write_file "tmp.mo" src; match run_cmd "moc -Werror -wasi-system-api tmp.mo -o tmp.wasm" with - | ((Fail | Timeout), stdout, stderr) -> CantCompile (stdout, stderr) + | ((Fail | Timeout), stdout, stderr) -> CantCompile (stdout, stderr, src) | (Ok, _, _) -> match must_not_trap, run_cmd "timeout 10s wasmtime --disable-cache --cranelift tmp.wasm" with | ShouldPass, (Ok, _, _) -> WantedPass diff --git a/src/mo_idl/idl_to_mo_value.ml b/src/mo_idl/idl_to_mo_value.ml index bfa71bcf341..2d603194724 100644 --- a/src/mo_idl/idl_to_mo_value.ml +++ b/src/mo_idl/idl_to_mo_value.ml @@ -3,6 +3,7 @@ open Idllib.Exception open Source module T = Mo_types.Type +module Pretty = T.MakePretty(T.ElideStamps) (* This module can translate Candid values (as parsed from the textual representation) into Motoko values. This is a pragmatic translation which is @@ -71,7 +72,7 @@ let rec value v t = Printf.sprintf "(actor %s : actor { %s : %s }).%s" (text_lit s) (Idllib.Escape.escape_method Source.no_region m) - (T.string_of_typ t) + (Pretty.string_of_typ t) (Idllib.Escape.escape_method Source.no_region m) | PrincipalV s, _ -> "Prim.principalOfActor" ^ parens ("actor " ^ text_lit s ^ " : actor {}") diff --git a/src/mo_types/type.ml b/src/mo_types/type.ml index a4834704835..b505b5fc291 100644 --- a/src/mo_types/type.ml +++ b/src/mo_types/type.ml @@ -1224,13 +1224,13 @@ and pp_dom parens vs ppf ts = and pp_cod vs ppf ts = match ts with | [Tup _] -> fprintf ppf "@[<1>(%a)@]" (pp_typ' vs) (seq ts) - | _ -> pp_typ' vs ppf (seq ts) + | _ -> pp_typ_nullary vs ppf (seq ts) and pp_control_cod sugar c vs ppf ts = match c, ts with (* sugar *) | Returns, [Async (_,t)] when sugar -> - fprintf ppf "@[<2>async@ %a@]" (pp_typ' vs) t + fprintf ppf "@[<2>async@ %a@]" (pp_typ_nullary vs) t | Promises, ts when sugar -> fprintf ppf "@[<2>async@ %a@]" (pp_cod vs) ts (* explicit *) From 9e47504742cb6dad6832faf442f06f80986db5a1 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Sat, 9 Apr 2022 22:11:19 +0100 Subject: [PATCH 086/128] deseralization at Non should not trap but skip and (as determined by context) --- src/codegen/compile.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 6ff761312fd..d41d7885694 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5687,7 +5687,8 @@ module MakeSerialization (Strm : Stream) = struct Heap.store_field MutBox.field ) | Non -> - E.trap_with env "IDL error: deserializing value of type None" + skip get_idltyp ^^ + coercion_failed "IDL error: deserializing value of type None" | _ -> todo_trap env "deserialize" (Arrange_ir.typ t) end ^^ (* Parsed value on the stack, return that, unless the failure flag is set *) From ebf2c02124c4a54f480d41978ed0e11d7781140e Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 11 Apr 2022 15:27:15 +0100 Subject: [PATCH 087/128] tweak pretty printer --- src/mo_types/type.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mo_types/type.ml b/src/mo_types/type.ml index b505b5fc291..261f37a15c3 100644 --- a/src/mo_types/type.ml +++ b/src/mo_types/type.ml @@ -1224,7 +1224,7 @@ and pp_dom parens vs ppf ts = and pp_cod vs ppf ts = match ts with | [Tup _] -> fprintf ppf "@[<1>(%a)@]" (pp_typ' vs) (seq ts) - | _ -> pp_typ_nullary vs ppf (seq ts) + | _ -> pp_typ' vs ppf (seq ts) and pp_control_cod sugar c vs ppf ts = match c, ts with @@ -1232,7 +1232,7 @@ and pp_control_cod sugar c vs ppf ts = | Returns, [Async (_,t)] when sugar -> fprintf ppf "@[<2>async@ %a@]" (pp_typ_nullary vs) t | Promises, ts when sugar -> - fprintf ppf "@[<2>async@ %a@]" (pp_cod vs) ts + fprintf ppf "@[<2>async@ %a@]" (pp_typ_nullary vs) (seq ts) (* explicit *) | (Returns | Promises), _ -> pp_cod vs ppf ts | Replies, _ -> fprintf ppf "@[<2>replies@ %a@]" (pp_cod vs) ts From a81d547eaa9d3c28ad5d35c1d40a09669b96852f Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 11 Apr 2022 19:03:43 +0100 Subject: [PATCH 088/128] more pretty printer tweaks --- src/mo_types/type.ml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mo_types/type.ml b/src/mo_types/type.ml index 261f37a15c3..a9cb6152b96 100644 --- a/src/mo_types/type.ml +++ b/src/mo_types/type.ml @@ -1184,8 +1184,9 @@ let rec pp_typ_nullary vs ppf = function fprintf ppf "@[<1>[var %a]@]" (pp_typ_nullary vs) t | Array t -> fprintf ppf "@[<1>[%a]@]" (pp_typ_nullary vs) t - | Obj (Object, fs) -> - fprintf ppf "@[{@;<0 0>%a@;<0 -2>}@]" + | Obj (s, fs) -> + fprintf ppf "@[%s{@;<0 0>%a@;<0 -2>}@]" + (string_of_obj_sort s) (pp_print_list ~pp_sep:semi (pp_field vs)) fs | Variant [] -> pr ppf "{#}" | Variant fs -> From d33ef6a471d2a53da4e96513d1357d795ac51ee2 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 11 Apr 2022 21:40:22 +0100 Subject: [PATCH 089/128] more pretty printer tweaks --- src/mo_types/type.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mo_types/type.ml b/src/mo_types/type.ml index a9cb6152b96..571f4508cb5 100644 --- a/src/mo_types/type.ml +++ b/src/mo_types/type.ml @@ -1279,7 +1279,7 @@ and pp_typ' vs ppf t = | [tb] -> fprintf ppf "@[<2>%s%a ->@ %a@]" (string_of_func_sort s) - (pp_dom false (vs'vs)) ts1 + (pp_dom true (vs'vs)) ts1 (pp_control_cod true c (vs'vs)) ts2 | _ -> fprintf ppf "@[<2>%s%a%a ->@ %a@]" From 4475a8a3ec3356ff9c1bc92dbc7c13c38868e9be Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 11 Apr 2022 21:54:43 +0100 Subject: [PATCH 090/128] Revert "more pretty printer tweaks" This reverts commit d33ef6a471d2a53da4e96513d1357d795ac51ee2. --- src/mo_types/type.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mo_types/type.ml b/src/mo_types/type.ml index 571f4508cb5..a9cb6152b96 100644 --- a/src/mo_types/type.ml +++ b/src/mo_types/type.ml @@ -1279,7 +1279,7 @@ and pp_typ' vs ppf t = | [tb] -> fprintf ppf "@[<2>%s%a ->@ %a@]" (string_of_func_sort s) - (pp_dom true (vs'vs)) ts1 + (pp_dom false (vs'vs)) ts1 (pp_control_cod true c (vs'vs)) ts2 | _ -> fprintf ppf "@[<2>%s%a%a ->@ %a@]" From fa308b00e979f9a6b1f0af6eb31a7ec9a4d6ace7 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 11 Apr 2022 21:55:06 +0100 Subject: [PATCH 091/128] Revert "more pretty printer tweaks" This reverts commit a81d547eaa9d3c28ad5d35c1d40a09669b96852f. --- src/mo_types/type.ml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mo_types/type.ml b/src/mo_types/type.ml index a9cb6152b96..261f37a15c3 100644 --- a/src/mo_types/type.ml +++ b/src/mo_types/type.ml @@ -1184,9 +1184,8 @@ let rec pp_typ_nullary vs ppf = function fprintf ppf "@[<1>[var %a]@]" (pp_typ_nullary vs) t | Array t -> fprintf ppf "@[<1>[%a]@]" (pp_typ_nullary vs) t - | Obj (s, fs) -> - fprintf ppf "@[%s{@;<0 0>%a@;<0 -2>}@]" - (string_of_obj_sort s) + | Obj (Object, fs) -> + fprintf ppf "@[{@;<0 0>%a@;<0 -2>}@]" (pp_print_list ~pp_sep:semi (pp_field vs)) fs | Variant [] -> pr ppf "{#}" | Variant fs -> From af4c27f66d00fa1f7cf3326c0f2746c60adc5aca Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 11 Apr 2022 21:58:38 +0100 Subject: [PATCH 092/128] update test output --- test/run-drun/ok/explicit-actor-import.tc.ok | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/run-drun/ok/explicit-actor-import.tc.ok b/test/run-drun/ok/explicit-actor-import.tc.ok index 979a9876b22..2a648f81af0 100644 --- a/test/run-drun/ok/explicit-actor-import.tc.ok +++ b/test/run-drun/ok/explicit-actor-import.tc.ok @@ -1,4 +1,4 @@ explicit-actor-import.mo:10.8-10.29: type error [M0114], object pattern cannot consume actor type - actor {go : shared () -> async actor {}} + actor {go : shared () -> async (actor {})} explicit-actor-import.mo:11.8-11.29: type error [M0114], object pattern cannot consume actor type - actor {go : shared () -> async actor {}} + actor {go : shared () -> async (actor {})} From d16342df9423a4e802f42e600a416c3dbbd20769 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 12 Apr 2022 10:58:44 +0100 Subject: [PATCH 093/128] fix bug in pretty printer --- src/mo_types/type.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mo_types/type.ml b/src/mo_types/type.ml index 261f37a15c3..b5d1c6ddf42 100644 --- a/src/mo_types/type.ml +++ b/src/mo_types/type.ml @@ -1284,7 +1284,7 @@ and pp_typ' vs ppf t = fprintf ppf "@[<2>%s%a%a ->@ %a@]" (string_of_func_sort s) (pp_binds (vs'vs) vs'') tbs' - (pp_dom (tbs <> []) (vs'vs)) ts1 + (pp_dom (tbs' <> []) (vs'vs)) ts1 (pp_control_cod true c (vs'vs)) ts2 ) | Func (s, c, [], ts1, ts2) -> From 04b6238fc04e79f2139bd013935eace6843b102c Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 12 Apr 2022 11:31:56 +0100 Subject: [PATCH 094/128] use offset --- src/codegen/compile.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index d41d7885694..9eda465e319 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5041,8 +5041,7 @@ module MakeSerialization (Strm : Stream) = struct let idx = List.length !(env.E.typtbl_typs) in env.E.typtbl_typs := !(env.E.typtbl_typs) @ [t2]; get_typtbl_idltyps env ^^ - compile_add_const (Int32.of_int (idx * 4)) ^^ - G.i (Load {ty = I32Type; align = 0; offset = 0l; sz = None}) ^^ + G.i (Load {ty = I32Type; align = 0; offset = Int32.of_int (idx * 4) (*!*); sz = None}) ^^ Func.share_code6 env ("idl_sub") (("rel_buf", I32Type), ("typtbl1", I32Type), From 940ae96917399c7cae7c3be43d73342d9d4a4ff3 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 12 Apr 2022 12:39:55 +0100 Subject: [PATCH 095/128] exploit StaticBytes DSL to construct static type table data --- src/codegen/compile.ml | 55 +++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 9eda465e319..9578f384aa7 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -518,6 +518,9 @@ module E = struct env.static_strings := StringEnv.add b ptr !(env.static_strings); ptr + let add_static_unskewed (env : t) (data : StaticBytes.t) : int32 = + Int32.add (add_static env data) ptr_unskew + let get_end_of_static_memory env : int32 = env.static_memory_frozen := true; !(env.end_of_static_memory) @@ -4674,39 +4677,25 @@ module MakeSerialization (Strm : Stream) = struct List.map idx ts) let set_delayed_globals (env : E.t) (set_typtbl, set_typtbl_end, set_typtbl_size, set_typtbl_idltyps) = - let typdesc, offsets, idltyps = type_desc env (!(env.E.typtbl_typs)) in - let static_typedesc = - Int32.(add (Blob.vanilla_lit env typdesc) Blob.unskewed_payload_offset) - in - let tbl = - let buf = Buffer.create (List.length offsets * 4) in - begin - List.iter (fun offset -> - Buffer.add_int32_le buf - Int32.(add static_typedesc (of_int(offset)))) - offsets; - Buffer.contents buf - end - in - let static_typtbl = - Int32.add (Blob.vanilla_lit env tbl) Blob.unskewed_payload_offset - in - let static_idltyps = - let buf = Buffer.create (List.length idltyps * 4) in - begin - List.iter (fun idltyp -> - Buffer.add_int32_le buf idltyp) - idltyps; - Buffer.contents buf - end - in - let static_idltyps = - Int32.add (Blob.vanilla_lit env static_idltyps) Blob.unskewed_payload_offset - in - set_typtbl static_typtbl; - set_typtbl_end Int32.(add static_typedesc (of_int (String.length typdesc))); - set_typtbl_size (Int32.of_int (List.length offsets)); - set_typtbl_idltyps static_idltyps + let typdesc, offsets, idltyps = type_desc env (!(env.E.typtbl_typs)) in + let static_typedesc = + E.add_static_unskewed env [StaticBytes.Bytes typdesc] + in + let static_typtbl = + let bytes = StaticBytes.i32s + (List.map (fun offset -> + Int32.(add static_typedesc (of_int(offset)))) + offsets) + in + E.add_static_unskewed env [bytes] + in + let static_idltyps = + E.add_static_unskewed env [StaticBytes.i32s idltyps] + in + set_typtbl static_typtbl; + set_typtbl_end Int32.(add static_typedesc (of_int (String.length typdesc))); + set_typtbl_size (Int32.of_int (List.length offsets)); + set_typtbl_idltyps static_idltyps (* Returns data (in bytes) and reference buffer size (in entries) needed *) let rec buffer_size env t = From 8cf7e6b0f5e1cbb7f0a421d74d3075d57472cb6b Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 12 Apr 2022 12:49:38 +0100 Subject: [PATCH 096/128] double the RTS stack size --- src/codegen/compile.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 9578f384aa7..4a7fb412823 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -1034,7 +1034,7 @@ module Stack = struct All pointers here are unskewed. *) - let end_ = page_size (* 64k of stack *) + let end_ = 2 * page_size (* 128k of stack *) let register_globals env = (* stack pointer *) From 7f42dc0b6120e9717ce70b52026fa35d1f62accc Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 12 Apr 2022 15:07:10 +0100 Subject: [PATCH 097/128] use Int32.mul --- src/codegen/compile.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 4a7fb412823..b45354194af 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -1034,7 +1034,7 @@ module Stack = struct All pointers here are unskewed. *) - let end_ = 2 * page_size (* 128k of stack *) + let end_ = Int32.mul 2l page_size (* 128k of stack *) let register_globals env = (* stack pointer *) From aa78f0346fb5d43ac1016e199280e9ef00a3f56f Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 12 Apr 2022 17:30:09 +0100 Subject: [PATCH 098/128] add Note(s) --- rts/motoko-rts/src/idl.rs | 2 +- src/codegen/compile.ml | 101 +++++++++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 93e2cb39702..5fc3d6e7db2 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -831,7 +831,7 @@ unsafe extern "C" fn idl_sub( debug_assert!(t1 < (typtbl_size1 as i32) && t2 < (typtbl_size2 as i32)); - rel.init(); + rel.init(); // FIX ME return sub( &rel, diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index b45354194af..8f89ebfd0f3 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -258,7 +258,9 @@ module E = struct static_roots : int32 list ref; (* GC roots in static memory. (Everything that may be mutable.) *) typtbl_typs : Type.typ list ref; - (* Types accumulated in global typtbl (for candid subtype checks *) + (* Types accumulated in global typtbl (for candid subtype checks) + See Note [Candid subtype checks] + *) (* Metadata *) args : (bool * string) option ref; @@ -4676,6 +4678,7 @@ module MakeSerialization (Strm : Stream) = struct offsets, List.map idx ts) + (* See Note [Candid subtype checks] *) let set_delayed_globals (env : E.t) (set_typtbl, set_typtbl_end, set_typtbl_size, set_typtbl_idltyps) = let typdesc, offsets, idltyps = type_desc env (!(env.E.typtbl_typs)) in let static_typedesc = @@ -5003,20 +5006,7 @@ module MakeSerialization (Strm : Stream) = struct I32 Tagged.(int_of_tag CoercionFailure); ] - (* The main deserialization function, generated once per type hash. - Its parameters are: - * data_buffer: The current position of the input data buffer - * ref_buffer: The current position of the input references buffer - * typtbl: The type table, as returned by parse_idl_header - * idltyp: The idl type (prim type or table index) to decode now - * typtbl_size: The size of the type table, used to limit recursion - * depth: Recursion counter; reset when we make progres on the value - * can_recover: Whether coercion errors are recoverable, see coercion_failed below - - It returns the value of type t (vanilla representation) or coercion_error_value, - It advances the data_buffer past the decoded value (even if it returns coercion_error_value!) - *) - + (* See Note [Candid subtype checks] *) let with_rel_buf_opt env extended get_typtbl_size1 f = if extended then f (compile_unboxed_const 0l) @@ -5025,7 +5015,7 @@ module MakeSerialization (Strm : Stream) = struct E.call_import env "rts" "idl_sub_buf_words" ^^ Stack.dynamic_with_words env "rel_buf" f - + (* See Note [Candid subtype checks] *) let idl_sub env t2 = let idx = List.length !(env.E.typtbl_typs) in env.E.typtbl_typs := !(env.E.typtbl_typs) @ [t2]; @@ -5041,19 +5031,32 @@ module MakeSerialization (Strm : Stream) = struct ) [I32Type] (fun env get_rel_buf get_typtbl1 get_typtbl_end1 get_typtbl_size1 get_idltyp1 get_idltyp2 -> - get_rel_buf ^^ - E.else_trap_with env "null rel_buf" ^^ - get_rel_buf ^^ - get_typtbl1 ^^ - get_typtbl env ^^ - get_typtbl_end1 ^^ - get_typtbl_end env ^^ - get_typtbl_size1 ^^ - get_typtbl_size env ^^ - get_idltyp1 ^^ - get_idltyp2 ^^ - E.call_import env "rts" "idl_sub") + get_rel_buf ^^ + E.else_trap_with env "null rel_buf" ^^ + get_rel_buf ^^ + get_typtbl1 ^^ + get_typtbl env ^^ + get_typtbl_end1 ^^ + get_typtbl_end env ^^ + get_typtbl_size1 ^^ + get_typtbl_size env ^^ + get_idltyp1 ^^ + get_idltyp2 ^^ + E.call_import env "rts" "idl_sub") + (* The main deserialization function, generated once per type hash. + Its parameters are: + * data_buffer: The current position of the input data buffer + * ref_buffer: The current position of the input references buffer + * typtbl: The type table, as returned by parse_idl_header + * idltyp: The idl type (prim type or table index) to decode now + * typtbl_size: The size of the type table, used to limit recursion + * depth: Recursion counter; reset when we make progres on the value + * can_recover: Whether coercion errors are recoverable, see coercion_failed below + + It returns the value of type t (vanilla representation) or coercion_error_value, + It advances the data_buffer past the decoded value (even if it returns coercion_error_value!) + *) let rec deserialize_go env t = let open Type in let t = Type.normalize t in @@ -5627,6 +5630,7 @@ module MakeSerialization (Strm : Stream) = struct ( coercion_failed "IDL error: unexpected variant tag" ) ) | Func _ -> + (* See Note [Candid subtype checks] *) get_rel_buf_opt ^^ G.if1 I32Type (begin @@ -5649,6 +5653,7 @@ module MakeSerialization (Strm : Stream) = struct (skip get_idltyp ^^ coercion_failed "IDL error: incompatible function type") | Obj (Actor, _) -> + (* See Note [Candid subtype checks] *) get_rel_buf_opt ^^ G.if1 I32Type (begin @@ -5947,6 +5952,44 @@ To detect and preserve aliasing, these steps are taken: *) +(* +Note [Candid subtype checks] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Deserializing Candid values now requires a Candid subtype check when +deserializing reference types (actors and functions). + +The subtype test is performed directly on the expected and actual +candid type tables using RTS functions `idl_sub_buf_words` and +`idl_sub_init`. One type table and vector of types is generated +statically from the list of statically known types encountered during +code generation, the other is determined dynamically by, e.g. message +payload. + +The known Motoko types are accumulated in a global list when +encountered and then encoded to global type table and sequence of type +indices in a final compilation step. The encoding is stored as static +data referenced by dedicated wasm globals so that we can generate code +that references them before their final value is known. + +Deserializing a vanilla (not extended) Candid value stack allocates a +mutable word buffer, of size determined by `idl_sub_buf_words`. The +word buffer is used to initialize and provide storage for a Rust memo +table (see bitrel.rs) memoizing the result of sub and super type tests +performed during deserialization of a given Candid value sequence. +The memo table is initialized once and shared between recursive calls +to deserialize, by threading the (possibly null) wasm address of its +word buffer as an optional argument. The word buffer is stack +allocated in generated code, not Rust, because it's size is dynamic +and Rust doesn't do dynamically sized stack allocation (AFAICT). + +Currently, we only perform Candid subtyp checks when decoding vanilla +(not extended) Candid values. Extended values are required for stable +variables only: we can omit the check, because compatibility should +already be enforced by the static signature compatibility check. We +use the null-ness of the word buffer pointer to determine whether to +omit or perform Candid subtype checks. +*) end (* MakeSerialization *) @@ -9349,6 +9392,7 @@ and conclude_module env set_serialization_globals start_fi_o = FuncDec.export_async_method env; + (* See Note [Candid subtype checks] *) Serialization.set_delayed_globals env set_serialization_globals; let static_roots = GC.store_static_roots env in @@ -9445,6 +9489,7 @@ let compile mode rts (prog : Ir.prog) : Wasm_exts.CustomModule.extended_module = Stack.register_globals env; StableMem.register_globals env; + (* See Note [Candid subtype checks] *) let set_serialization_globals = Serialization.register_delayed_globals env in IC.system_imports env; From b4f097da698060a97a8f2d80d6829cebb699722e Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 12 Apr 2022 18:03:45 +0100 Subject: [PATCH 099/128] initialize memo table just once; not on every idl_sub call --- rts/motoko-rts/src/idl.rs | 17 +++++++++++++++-- src/codegen/compile.ml | 7 ++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 5fc3d6e7db2..3ee45e8e94f 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -808,6 +808,21 @@ unsafe extern "C" fn idl_sub_buf_words(typtbl_size1: u32, typtbl_size2: u32) -> return BitRel::words(typtbl_size1, typtbl_size2); } +#[no_mangle] +unsafe extern "C" fn idl_sub_buf_init( + rel_buf: *mut u32, + typtbl_size1: u32, + typtbl_size2: u32, +) -> () { + let rel = BitRel { + ptr: rel_buf, + end: rel_buf.add(idl_sub_buf_words(typtbl_size1, typtbl_size2) as usize), + size1: typtbl_size1, + size2: typtbl_size2, + }; + rel.init(); +} + #[no_mangle] unsafe extern "C" fn idl_sub( rel_buf: *mut u32, // a buffer with at least 2 * typtbl_size1 * typtbl_size2 bits @@ -831,8 +846,6 @@ unsafe extern "C" fn idl_sub( debug_assert!(t1 < (typtbl_size1 as i32) && t2 < (typtbl_size2 as i32)); - rel.init(); // FIX ME - return sub( &rel, true, diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 8f89ebfd0f3..66da2553f41 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -818,6 +818,7 @@ module RTS = struct E.add_func_import env "rts" "version" [] [I32Type]; E.add_func_import env "rts" "parse_idl_header" [I32Type; I32Type; I32Type; I32Type; I32Type] []; E.add_func_import env "rts" "idl_sub_buf_words" [I32Type; I32Type] [I32Type]; + E.add_func_import env "rts" "idl_sub_buf_init" [I32Type; I32Type; I32Type] []; E.add_func_import env "rts" "idl_sub" [I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "leb128_decode" [I32Type] [I32Type]; @@ -5013,7 +5014,11 @@ module MakeSerialization (Strm : Stream) = struct else get_typtbl_size1 ^^ get_typtbl_size env ^^ E.call_import env "rts" "idl_sub_buf_words" ^^ - Stack.dynamic_with_words env "rel_buf" f + Stack.dynamic_with_words env "rel_buf" + (fun get_ptr -> + get_ptr ^^ get_typtbl_size1 ^^ get_typtbl_size env ^^ + E.call_import env "rts" "idl_sub_buf_init" ^^ + f get_ptr) (* See Note [Candid subtype checks] *) let idl_sub env t2 = From a1f9753a5d312c6f3148eaaedd2fa4bed12b722d Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 12 Apr 2022 22:01:36 +0100 Subject: [PATCH 100/128] cleanup Env.typtbl_typs to use add/reg pattern; extend notes --- src/codegen/compile.ml | 97 +++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 40 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 66da2553f41..6104b1aada1 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -257,10 +257,11 @@ module E = struct (* Sanity check: Nothing should bump end_of_static_memory once it has been read *) static_roots : int32 list ref; (* GC roots in static memory. (Everything that may be mutable.) *) + + (* Types accumulated in global typtbl (for candid subtype checks) + See Note [Candid subtype checks] + *) typtbl_typs : Type.typ list ref; - (* Types accumulated in global typtbl (for candid subtype checks) - See Note [Candid subtype checks] - *) (* Metadata *) args : (bool * string) option ref; @@ -337,13 +338,12 @@ module E = struct let mode (env : t) = env.mode - let add_anon_local (env : t) ty = - let i = reg env.locals ty in - Wasm.I32.add env.n_param i + let i = reg env.locals ty in + Wasm.I32.add env.n_param i let add_local_name (env : t) li name = - let _ = reg env.local_names (li, name) in () + let _ = reg env.local_names (li, name) in () let get_locals (env : t) = !(env.locals) let get_local_names (env : t) : (int32 * string) list = !(env.local_names) @@ -547,6 +547,14 @@ module E = struct in let gc_fn = if !Flags.force_gc then gc_fn else "schedule_" ^ gc_fn in call_import env "rts" (gc_fn ^ "_gc") + + (* See Note [Candid subtype checks] *) + let add_typtbl_typ (env : t) ty : Int32.t = + reg env.typtbl_typs ty + + let get_typtbl_typs (env : t) : Type.typ list = + !(env.typtbl_typs) + end @@ -4458,13 +4466,15 @@ module MakeSerialization (Strm : Stream) = struct by the next GC. *) + (* Globals recording known Candid types + See Note [Candid subtype checks] + *) let register_delayed_globals env = (E.add_global32_delayed env "__typtbl" Immutable, E.add_global32_delayed env "__typtbl_end" Immutable, E.add_global32_delayed env "__typtbl_size" Immutable, E.add_global32_delayed env "__typtbl_idltyps" Immutable) - let get_typtbl env = G.i (GlobalGet (nr (E.get_global env "__typtbl"))) let get_typtbl_size env = @@ -4681,7 +4691,7 @@ module MakeSerialization (Strm : Stream) = struct (* See Note [Candid subtype checks] *) let set_delayed_globals (env : E.t) (set_typtbl, set_typtbl_end, set_typtbl_size, set_typtbl_idltyps) = - let typdesc, offsets, idltyps = type_desc env (!(env.E.typtbl_typs)) in + let typdesc, offsets, idltyps = type_desc env (E.get_typtbl_typs env) in let static_typedesc = E.add_static_unskewed env [StaticBytes.Bytes typdesc] in @@ -5022,10 +5032,9 @@ module MakeSerialization (Strm : Stream) = struct (* See Note [Candid subtype checks] *) let idl_sub env t2 = - let idx = List.length !(env.E.typtbl_typs) in - env.E.typtbl_typs := !(env.E.typtbl_typs) @ [t2]; + let idx = E.add_typtbl_typ env t2 in get_typtbl_idltyps env ^^ - G.i (Load {ty = I32Type; align = 0; offset = Int32.of_int (idx * 4) (*!*); sz = None}) ^^ + G.i (Load {ty = I32Type; align = 0; offset = Int32.mul idx 4l (*!*); sz = None}) ^^ Func.share_code6 env ("idl_sub") (("rel_buf", I32Type), ("typtbl1", I32Type), @@ -5962,38 +5971,46 @@ Note [Candid subtype checks] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Deserializing Candid values now requires a Candid subtype check when -deserializing reference types (actors and functions). +deserializing value of reference types (actors and functions). The subtype test is performed directly on the expected and actual -candid type tables using RTS functions `idl_sub_buf_words` and -`idl_sub_init`. One type table and vector of types is generated -statically from the list of statically known types encountered during -code generation, the other is determined dynamically by, e.g. message -payload. - -The known Motoko types are accumulated in a global list when -encountered and then encoded to global type table and sequence of type -indices in a final compilation step. The encoding is stored as static -data referenced by dedicated wasm globals so that we can generate code -that references them before their final value is known. +candid type tables using RTS functions `idl_sub_buf_words`, +`idl_sub_buf_init` and `idl_sub`. One type table and vector of types +is generated statically from the list of statically known types +encountered during code generation, the other is determined +dynamically by, e.g. message payload. The latter will vary with +each payload to decode. + +The known Motoko types are accumulated in a global list as required +and then, in a final compilation step, encoded to global type table +and sequence of type indices. The encoding is stored as static +data referenced by dedicated wasm globals so that we can generate +code that reference the globals before their final definitions are +known. Deserializing a vanilla (not extended) Candid value stack allocates a -mutable word buffer, of size determined by `idl_sub_buf_words`. The -word buffer is used to initialize and provide storage for a Rust memo -table (see bitrel.rs) memoizing the result of sub and super type tests -performed during deserialization of a given Candid value sequence. -The memo table is initialized once and shared between recursive calls -to deserialize, by threading the (possibly null) wasm address of its -word buffer as an optional argument. The word buffer is stack -allocated in generated code, not Rust, because it's size is dynamic -and Rust doesn't do dynamically sized stack allocation (AFAICT). - -Currently, we only perform Candid subtyp checks when decoding vanilla -(not extended) Candid values. Extended values are required for stable -variables only: we can omit the check, because compatibility should -already be enforced by the static signature compatibility check. We -use the null-ness of the word buffer pointer to determine whether to -omit or perform Candid subtype checks. +mutable word buffer, of size determined by `idl_sub_buf_words`. +The word buffer is used to initialize and provide storage for a +Rust memo table (see bitrel.rs) memoizing the result of sub and +super type tests performed during deserialization of a given Candid +value sequence. The memo table is initialized once, using `idl_sub_buf_init`, +then shared between recursive calls to deserialize, by threading the (possibly +null) wasm address of the word buffer as an optional argument. The +word buffer is stack allocated in generated code, not Rust, because +it's size is dynamic and Rust doesn't seem to support dynamically-sized +stack allocation. + +Currently, we only perform Candid subtype checks when decoding vanilla +(not extended) Candid values. Extended values are required for +stable variables only: we can omit the check, because compatibility +should already be enforced by the static signature compatibility +check. We use the `null`-ness of the word buffer pointer to +dynamically determine whether to omit or perform Candid subtype checks. + +NB: Extending `idl_sub` to support extended, "stable" types (with mutable, +invariant type constructors) would require extending the polarity argument +from a Boolean to a three-valued argument to efficiently check equality for +invariant type constructors in a single pass. *) end (* MakeSerialization *) From 9552dc1fa4ba14a13a886495c43f35fc8ee75607 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 12 Apr 2022 22:31:37 +0100 Subject: [PATCH 101/128] use helper leb128_decode_ptr --- rts/motoko-rts/src/idl.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 3ee45e8e94f..0c9512a8674 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -46,6 +46,10 @@ const IDL_CON_alias: i32 = 1; const IDL_PRIM_lowest: i32 = -17; +pub unsafe fn leb128_decode_ptr(buf: *mut Buf) -> (u32, *mut u8) { + (leb128_decode(buf), (*buf).ptr) +} + unsafe fn is_primitive_type(ty: i32) -> bool { ty < 0 && (ty >= IDL_PRIM_lowest || ty == IDL_REF_principal) } @@ -199,8 +203,7 @@ unsafe fn parse_idl_header( let mut last_p = core::ptr::null_mut(); for _ in 0..leb128_decode(buf) { // Name - let len = leb128_decode(buf); - let p = (*buf).ptr; + let (len, p) = leb128_decode_ptr(buf); buf.advance(len); // Method names must be valid unicode utf8_validate(p as *const _, len); @@ -288,8 +291,7 @@ unsafe fn skip_blob(buf: *mut Buf) { } unsafe fn skip_text(buf: *mut Buf) { - let len = leb128_decode(buf); - let p = (*buf).ptr; + let (len, p) = leb128_decode_ptr(buf); buf.advance(len); // advance first; does the bounds check utf8_validate(p as *const _, len); } @@ -531,8 +533,6 @@ unsafe fn is_opt_reserved(typtbl: *mut *mut u8, end: *mut u8, t: i32) -> bool { return t == IDL_CON_opt; } -// https://github.com/dfinity/candid/blob/master/rust/candid/src/types/subtype.rs#L10 -// https://github.com/dfinity/candid/blob/20b84d1c1515e2c1db353ebe02b738486f835466/spec/Candid.md // TODO: consider storing fixed args typtbl1...end2 in `rel` to use less stack. unsafe fn sub( rel: &BitRel, @@ -760,8 +760,7 @@ unsafe fn sub( if n1 == 0 { break 'return_false; }; - let len2 = leb128_decode(&mut tb2); - let p2 = tb2.ptr; + let (len2, p2) = leb128_decode_ptr(&mut tb2); Buf::advance(&mut tb2, len2); let t21 = sleb128_decode(&mut tb2); let mut len1: u32; @@ -769,8 +768,7 @@ unsafe fn sub( let mut t11: i32; let mut cmp: i32; loop { - len1 = leb128_decode(&mut tb1); - p1 = tb1.ptr; + (len1, p1) = leb128_decode_ptr(&mut tb1); Buf::advance(&mut tb1, len1); t11 = sleb128_decode(&mut tb1); n1 -= 1; From e2b020bd3c6ade4aecf53794e9f388e11eb5bde6 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 19 Apr 2022 17:43:26 -0400 Subject: [PATCH 102/128] Apply suggestions from code review Co-authored-by: Joachim Breitner --- src/codegen/compile.ml | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 6104b1aada1..bad52879337 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -4692,9 +4692,7 @@ module MakeSerialization (Strm : Stream) = struct (* See Note [Candid subtype checks] *) let set_delayed_globals (env : E.t) (set_typtbl, set_typtbl_end, set_typtbl_size, set_typtbl_idltyps) = let typdesc, offsets, idltyps = type_desc env (E.get_typtbl_typs env) in - let static_typedesc = - E.add_static_unskewed env [StaticBytes.Bytes typdesc] - in + let static_typedesc = E.add_static_unskewed env [StaticBytes.Bytes typdesc] in let static_typtbl = let bytes = StaticBytes.i32s (List.map (fun offset -> @@ -4703,9 +4701,7 @@ module MakeSerialization (Strm : Stream) = struct in E.add_static_unskewed env [bytes] in - let static_idltyps = - E.add_static_unskewed env [StaticBytes.i32s idltyps] - in + let static_idltyps = E.add_static_unskewed env [StaticBytes.i32s idltyps] in set_typtbl static_typtbl; set_typtbl_end Int32.(add static_typedesc (of_int (String.length typdesc))); set_typtbl_size (Int32.of_int (List.length offsets)); @@ -5024,8 +5020,7 @@ module MakeSerialization (Strm : Stream) = struct else get_typtbl_size1 ^^ get_typtbl_size env ^^ E.call_import env "rts" "idl_sub_buf_words" ^^ - Stack.dynamic_with_words env "rel_buf" - (fun get_ptr -> + Stack.dynamic_with_words env "rel_buf" (fun get_ptr -> get_ptr ^^ get_typtbl_size1 ^^ get_typtbl_size env ^^ E.call_import env "rts" "idl_sub_buf_init" ^^ f get_ptr) @@ -5647,15 +5642,15 @@ module MakeSerialization (Strm : Stream) = struct (* See Note [Candid subtype checks] *) get_rel_buf_opt ^^ G.if1 I32Type - (begin + begin get_rel_buf_opt ^^ get_typtbl ^^ get_typtbl_end ^^ get_typtbl_size ^^ get_idltyp ^^ idl_sub env t - end) - (compile_unboxed_const 1l) ^^ + end + (Bool.lit true) ^^ (* if we don't have a subtype memo table, assume the types are ok *) G.if1 I32Type (with_composite_typ idl_func (fun _get_typ_buf -> read_byte_tagged @@ -5670,15 +5665,15 @@ module MakeSerialization (Strm : Stream) = struct (* See Note [Candid subtype checks] *) get_rel_buf_opt ^^ G.if1 I32Type - (begin + begin get_rel_buf_opt ^^ get_typtbl ^^ get_typtbl_end ^^ get_typtbl_size ^^ get_idltyp ^^ idl_sub env t - end) - (compile_unboxed_const 1l) ^^ + end + (Bool.lit true) ^^ G.if1 I32Type (with_composite_typ idl_service (fun _get_typ_buf -> read_actor_data ())) @@ -5970,7 +5965,7 @@ To detect and preserve aliasing, these steps are taken: Note [Candid subtype checks] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Deserializing Candid values now requires a Candid subtype check when +Deserializing Candid values requires a Candid subtype check when deserializing value of reference types (actors and functions). The subtype test is performed directly on the expected and actual @@ -5988,7 +5983,7 @@ data referenced by dedicated wasm globals so that we can generate code that reference the globals before their final definitions are known. -Deserializing a vanilla (not extended) Candid value stack allocates a +Deserializing a proper (not extended) Candid value stack allocates a mutable word buffer, of size determined by `idl_sub_buf_words`. The word buffer is used to initialize and provide storage for a Rust memo table (see bitrel.rs) memoizing the result of sub and @@ -6000,7 +5995,7 @@ word buffer is stack allocated in generated code, not Rust, because it's size is dynamic and Rust doesn't seem to support dynamically-sized stack allocation. -Currently, we only perform Candid subtype checks when decoding vanilla +Currently, we only perform Candid subtype checks when decoding proper (not extended) Candid values. Extended values are required for stable variables only: we can omit the check, because compatibility should already be enforced by the static signature compatibility From 1b2ad987251f6812151790c81ffbe7ee2382f833 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 19 Apr 2022 17:44:29 -0400 Subject: [PATCH 103/128] Update src/codegen/compile.ml Co-authored-by: Joachim Breitner --- src/codegen/compile.ml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index bad52879337..e5b64e7e78e 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -5839,14 +5839,14 @@ module MakeSerialization (Strm : Stream) = struct (* Skip any extra arguments *) compile_while env (get_arg_count ^^ compile_rel_const I32Op.GtU 0l) - (begin - get_data_buf ^^ - get_typtbl_ptr ^^ load_unskewed_ptr ^^ - ReadBuf.read_sleb128 env get_main_typs_buf ^^ - compile_unboxed_const 0l ^^ - E.call_import env "rts" "skip_any" ^^ - get_arg_count ^^ compile_sub_const 1l ^^ set_arg_count - end) ^^ + begin + get_data_buf ^^ + get_typtbl_ptr ^^ load_unskewed_ptr ^^ + ReadBuf.read_sleb128 env get_main_typs_buf ^^ + compile_unboxed_const 0l ^^ + E.call_import env "rts" "skip_any" ^^ + get_arg_count ^^ compile_sub_const 1l ^^ set_arg_count + end ^^ ReadBuf.is_empty env get_data_buf ^^ E.else_trap_with env ("IDL error: left-over bytes " ^ ts_name) ^^ From 52d165b058a7c9dc9f154405d97d41d35cf0d3f6 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 19 Apr 2022 23:19:56 +0100 Subject: [PATCH 104/128] adjust test output --- test/run-drun/ok/explicit-actor-import.tc.ok | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/run-drun/ok/explicit-actor-import.tc.ok b/test/run-drun/ok/explicit-actor-import.tc.ok index 2a648f81af0..979a9876b22 100644 --- a/test/run-drun/ok/explicit-actor-import.tc.ok +++ b/test/run-drun/ok/explicit-actor-import.tc.ok @@ -1,4 +1,4 @@ explicit-actor-import.mo:10.8-10.29: type error [M0114], object pattern cannot consume actor type - actor {go : shared () -> async (actor {})} + actor {go : shared () -> async actor {}} explicit-actor-import.mo:11.8-11.29: type error [M0114], object pattern cannot consume actor type - actor {go : shared () -> async (actor {})} + actor {go : shared () -> async actor {}} From 5c7d7fb76d5e8f1307793eebb32fbc836cd38362 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 20 Apr 2022 18:40:17 -0400 Subject: [PATCH 105/128] Update src/codegen/compile.ml --- src/codegen/compile.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index e5b64e7e78e..8b4834a7fa8 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -549,6 +549,8 @@ module E = struct call_import env "rts" (gc_fn ^ "_gc") (* See Note [Candid subtype checks] *) + (* NB: we don't bother detecting duplicate registrations here because the code sharing machinery + ensures that `add_typtbl_typ t` is called at most once for any `t` with a distinct type hash *) let add_typtbl_typ (env : t) ty : Int32.t = reg env.typtbl_typs ty From 881227339001507cb1132391a16e118301db0893 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 22 Apr 2022 16:04:05 +0100 Subject: [PATCH 106/128] add variant refinement test --- test/run-drun/ok/idl-sub-variant.drun-run.ok | 6 ++++++ test/run-drun/ok/idl-sub-variant.ic-ref-run.ok | 9 +++++++++ test/run-drun/ok/idl-sub-variant.tc.ok | 4 ++++ 3 files changed, 19 insertions(+) create mode 100644 test/run-drun/ok/idl-sub-variant.drun-run.ok create mode 100644 test/run-drun/ok/idl-sub-variant.ic-ref-run.ok create mode 100644 test/run-drun/ok/idl-sub-variant.tc.ok diff --git a/test/run-drun/ok/idl-sub-variant.drun-run.ok b/test/run-drun/ok/idl-sub-variant.drun-run.ok new file mode 100644 index 00000000000..0eac0de659e --- /dev/null +++ b/test/run-drun/ok/idl-sub-variant.drun-run.ok @@ -0,0 +1,6 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: pass1 +debug.print: pass1 +debug.print: pass3: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: unexpected variant tag +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok b/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok new file mode 100644 index 00000000000..de355f1a9ba --- /dev/null +++ b/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok @@ -0,0 +1,9 @@ +→ update create_canister(record {settings = null}) +← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… +← replied: () +→ update go() +debug.print: pass1 +debug.print: pass1 +debug.print: pass3: canister did not respond +← replied: () diff --git a/test/run-drun/ok/idl-sub-variant.tc.ok b/test/run-drun/ok/idl-sub-variant.tc.ok new file mode 100644 index 00000000000..6ca7af9cf1c --- /dev/null +++ b/test/run-drun/ok/idl-sub-variant.tc.ok @@ -0,0 +1,4 @@ +idl-sub-variant.mo:29.13-29.19: warning [M0145], this pattern of type + Enum1 = {#A : Int; #B} +does not cover value + #B From afa0a1765fb022616222f1d870bcd490378ddee4 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 22 Apr 2022 16:05:40 +0100 Subject: [PATCH 107/128] add missing test --- test/run-drun/idl-sub-variant.mo | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 test/run-drun/idl-sub-variant.mo diff --git a/test/run-drun/idl-sub-variant.mo b/test/run-drun/idl-sub-variant.mo new file mode 100644 index 00000000000..e0f22614c82 --- /dev/null +++ b/test/run-drun/idl-sub-variant.mo @@ -0,0 +1,58 @@ +import Prim "mo:⛔"; + +// test candid subtype test with higher-order arguments +actor this { + + type Enum1 = { + #A : Int; + #B + }; + + type Enum2 = { + #A : Int; + }; + + public func get_A() : async Enum1 { + #A(1) + }; + + public func get_B() : async Enum1 { + #B + }; + + public func go() : async () { + + let t = debug_show (Prim.principalOfActor(this)); + + // positive tests + do { + let (#A _) : Enum1 = await this.get_A(); + Prim.debugPrint("pass1"); + }; + + do { + let this = actor (t) : actor { + get_A : () -> async Enum2; + }; + let (#A _) : Enum2 = await this.get_A(); + Prim.debugPrint("pass1"); + }; + + do { + let this = actor (t) : actor { + get_B : () -> async Enum2; + }; + try { + let _ : Enum2 = await async { await this.get_B(); }; + assert false; + } catch e { + Prim.debugPrint("pass3: " # Prim.errorMessage(e)); + }; + }; + + }; +} +//SKIP run +//SKIP run-ir +//SKIP run-low +//CALL ingress go "DIDL\x00\x00" From 77c3f13289d1afcbae240e180731374d7bd6d1f9 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 7 Jun 2022 23:49:55 +0100 Subject: [PATCH 108/128] update test output (new behaviour expected) --- test/run-drun/ok/call-raw-candid.drun-run.ok | 2 +- test/run-drun/ok/call-raw-candid.ic-ref-run.ok | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/run-drun/ok/call-raw-candid.drun-run.ok b/test/run-drun/ok/call-raw-candid.drun-run.ok index 23ba2432f33..f01abb9e600 100644 --- a/test/run-drun/ok/call-raw-candid.drun-run.ok +++ b/test/run-drun/ok/call-raw-candid.drun-run.ok @@ -4,7 +4,7 @@ debug.print: unit! debug.print: ("int", +1) debug.print: ("text", "hello") debug.print: ("text", (1, true, 'a')) -debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: too few arguments Nbc +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: unexpected IDL type when parsing Nat debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: ohoh debug.print: supercalifragilisticexpialidocious ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/call-raw-candid.ic-ref-run.ok b/test/run-drun/ok/call-raw-candid.ic-ref-run.ok index 579930c2773..d732eb408bd 100644 --- a/test/run-drun/ok/call-raw-candid.ic-ref-run.ok +++ b/test/run-drun/ok/call-raw-candid.ic-ref-run.ok @@ -7,7 +7,7 @@ debug.print: unit! debug.print: ("int", +1) debug.print: ("text", "hello") debug.print: ("text", (1, true, 'a')) -debug.print: canister trapped: EvalTrapError region:0xXXX-0xXXX "canister trapped explicitly: IDL error: too few arguments Nbc" +debug.print: canister trapped: EvalTrapError region:0xXXX-0xXXX "canister trapped explicitly: IDL error: unexpected IDL type when parsing Nat" debug.print: canister trapped: EvalTrapError region:0xXXX-0xXXX "canister trapped explicitly: ohoh" debug.print: supercalifragilisticexpialidocious ← replied: () From 6b9debcb3287b8aad2d9be5d3f51ce4b0cdf85ad Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 1 Sep 2022 13:05:19 +0100 Subject: [PATCH 109/128] Update src/codegen/compile.ml --- src/codegen/compile.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 7f60c3f98fa..009c25b701c 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -10195,7 +10195,7 @@ let compile mode rts (prog : Ir.prog) : Wasm_exts.CustomModule.extended_module = StableMem.register_globals env; (* See Note [Candid subtype checks] *) - let set_serialization_globals = Serialization.register_delayed_globals env in + let set_serialization_globals = Serialization.register_delayed_globals env in IC.system_imports env; RTS.system_imports env; From d21d5dbb80032823178fde60b37df997c0a233c1 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 1 Sep 2022 13:06:40 +0100 Subject: [PATCH 110/128] Update test/run-drun/idl-sub-opt-any.mo --- test/run-drun/idl-sub-opt-any.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/run-drun/idl-sub-opt-any.mo b/test/run-drun/idl-sub-opt-any.mo index 1d689c7007d..b614db34734 100644 --- a/test/run-drun/idl-sub-opt-any.mo +++ b/test/run-drun/idl-sub-opt-any.mo @@ -99,4 +99,4 @@ actor this { //SKIP run //SKIP run-ir //SKIP run-low -//CALL ingress go "DIDL\x00\x00" \ No newline at end of file +//CALL ingress go "DIDL\x00\x00" From 1811b37adcc873c7556728c479c3b30ea13c9a3e Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 1 Sep 2022 13:07:12 +0100 Subject: [PATCH 111/128] Update test/run-drun/idl-sub-opt-any-record.mo --- test/run-drun/idl-sub-opt-any-record.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/run-drun/idl-sub-opt-any-record.mo b/test/run-drun/idl-sub-opt-any-record.mo index be9f5effe35..47b32168d47 100644 --- a/test/run-drun/idl-sub-opt-any-record.mo +++ b/test/run-drun/idl-sub-opt-any-record.mo @@ -68,4 +68,4 @@ actor this { //SKIP run //SKIP run-ir //SKIP run-low -//CALL ingress go "DIDL\x00\x00" \ No newline at end of file +//CALL ingress go "DIDL\x00\x00" From b002bb4ed7a39677858df603fe59ecfcf56b58c5 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 13 Sep 2022 16:28:47 +0100 Subject: [PATCH 112/128] spacing --- src/codegen/compile.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 7f60c3f98fa..3b2efed388e 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -10094,7 +10094,6 @@ and conclude_module env set_serialization_globals start_fi_o = FuncDec.export_async_method env; - (* See Note [Candid subtype checks] *) Serialization.set_delayed_globals env set_serialization_globals; From c3afc65e9e5acc8fa3d430110c647edc5d7185f7 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 3 Oct 2022 16:21:05 +0100 Subject: [PATCH 113/128] update expected test out (formatting only) --- test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok | 12 ++++++------ test/run-drun/ok/idl-sub-ho.ic-ref-run.ok | 12 ++++++------ .../run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok | 12 ++++++------ test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok | 12 ++++++------ test/run-drun/ok/idl-sub-rec.ic-ref-run.ok | 12 ++++++------ test/run-drun/ok/idl-sub-variant.ic-ref-run.ok | 12 ++++++------ test/run-drun/ok/idl-sub.ic-ref-run.ok | 12 ++++++------ 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok b/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok index d22f4e9b9cc..0074223ff2a 100644 --- a/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok @@ -1,8 +1,8 @@ -→ update create_canister(record {settings = null}) -← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) -→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… -← replied: () -→ update go() +=> update create_canister(record {settings = null}) +<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... +<= replied: () +=> update go() debug.print: ok_0_1_a debug.print: ok_0_1_b debug.print: ok_0_2_a @@ -22,4 +22,4 @@ debug.print: ok 5_1_a debug.print: ok 5_1_b debug.print: ok 6_0_a debug.print: ok 6_0_b -← replied: () +<= replied: () diff --git a/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok index 65ea0b31682..6df69242e6e 100644 --- a/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok @@ -1,8 +1,8 @@ -→ update create_canister(record {settings = null}) -← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) -→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… -← replied: () -→ update go() +=> update create_canister(record {settings = null}) +<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... +<= replied: () +=> update go() debug.print: ok debug.print: ok debug.print: ok @@ -14,4 +14,4 @@ debug.print: ok debug.print: ok debug.print: ok debug.print: ok -← replied: () +<= replied: () diff --git a/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok b/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok index 7e2f3619f86..73bef836584 100644 --- a/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok @@ -1,11 +1,11 @@ -→ update create_canister(record {settings = null}) -← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) -→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… -← replied: () -→ update go() +=> update create_canister(record {settings = null}) +<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... +<= replied: () +=> update go() debug.print: ok_0_1_a debug.print: ok_0 debug.print: ok_0_1_b debug.print: ok_0 debug.print: ok_0_1_c -← replied: () +<= replied: () diff --git a/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok b/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok index b07ee86e01a..b966951dead 100644 --- a/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok @@ -1,8 +1,8 @@ -→ update create_canister(record {settings = null}) -← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) -→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… -← replied: () -→ update go() +=> update create_canister(record {settings = null}) +<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... +<= replied: () +=> update go() debug.print: ok_0_1_a debug.print: ok_0 debug.print: ok_0_1_b @@ -10,4 +10,4 @@ debug.print: ok_0 debug.print: ok_0_1_c debug.print: ok_0_1_d debug.print: ok_0_1_e -← replied: () +<= replied: () diff --git a/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok b/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok index 0aefb98889e..b14f83967a8 100644 --- a/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok @@ -1,8 +1,8 @@ -→ update create_canister(record {settings = null}) -← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) -→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… -← replied: () -→ update go() +=> update create_canister(record {settings = null}) +<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... +<= replied: () +=> update go() debug.print: ok f0 debug.print: ok_0 debug.print: ok f0 @@ -22,4 +22,4 @@ debug.print: ok_8 debug.print: ok_9canister trapped: EvalTrapError region:0xXXX-0xXXX "canister trapped explicitly: IDL error: incompatible function type" debug.print: ok f4 debug.print: ok_10 -← replied: () +<= replied: () diff --git a/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok b/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok index de355f1a9ba..9c4c01872ac 100644 --- a/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok @@ -1,9 +1,9 @@ -→ update create_canister(record {settings = null}) -← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) -→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… -← replied: () -→ update go() +=> update create_canister(record {settings = null}) +<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... +<= replied: () +=> update go() debug.print: pass1 debug.print: pass1 debug.print: pass3: canister did not respond -← replied: () +<= replied: () diff --git a/test/run-drun/ok/idl-sub.ic-ref-run.ok b/test/run-drun/ok/idl-sub.ic-ref-run.ok index c903959dc6c..7a501a64316 100644 --- a/test/run-drun/ok/idl-sub.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub.ic-ref-run.ok @@ -1,8 +1,8 @@ -→ update create_canister(record {settings = null}) -← replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) -→ update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0… -← replied: () -→ update go() +=> update create_canister(record {settings = null}) +<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... +<= replied: () +=> update go() debug.print: ok 0 debug.print: ok 1 debug.print: ok 2 @@ -19,4 +19,4 @@ debug.print: ok 12 debug.print: ok 13 debug.print: ok 14 debug.print: ok 15 -← replied: () +<= replied: () From 6d0d32d05349edf25e3a353d954785117c3a4b15 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 28 Oct 2022 17:01:21 +0100 Subject: [PATCH 114/128] Apply suggestions from code review Co-authored-by: Luc Blaeser <112870813+luc-blaeser@users.noreply.github.com> --- rts/motoko-rts/src/bitrel.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 0e6354bbdeb..d2aaa3951bc 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -87,13 +87,13 @@ impl BitRel { self.get(p, i_j, j_i, 0) } - pub(crate) unsafe fn visit(&self, p: bool, i_j: u32, j_i: u32) -> () { + pub(crate) unsafe fn visit(&self, p: bool, i_j: u32, j_i: u32) { self.set(p, i_j, j_i, 0, true) } // NB: we store related bits in negated form to avoid setting on assumption // This code is a nop in production code. - pub(crate) unsafe fn assume(&self, p: bool, i_j: u32, j_i: u32) -> () { + pub(crate) unsafe fn assume(&self, p: bool, i_j: u32, j_i: u32) { debug_assert!(!self.get(p, i_j, j_i, 1)); } @@ -101,7 +101,7 @@ impl BitRel { !self.get(p, i_j, j_i, 1) } - pub(crate) unsafe fn disprove(&self, p: bool, i_j: u32, j_i: u32) -> () { + pub(crate) unsafe fn disprove(&self, p: bool, i_j: u32, j_i: u32) { self.set(p, i_j, j_i, 1, true) } } From daa1432dec17678a67cd9398feca132bd584de3f Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 28 Oct 2022 21:00:33 +0100 Subject: [PATCH 115/128] Apply suggestions from code review Co-authored-by: Luc Blaeser <112870813+luc-blaeser@users.noreply.github.com> --- rts/motoko-rts/src/bitrel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index d2aaa3951bc..706066fbea4 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -36,7 +36,7 @@ impl BitRel { } unsafe fn locate_ptr_bit( - self: &Self, + &self p: bool, i_j: u32, j_i: u32, From a4a7e218afd3f2fe13ce6c49e6bb1c10e939c210 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 28 Oct 2022 21:52:57 +0100 Subject: [PATCH 116/128] fix syntax error and adjust check --- rts/motoko-rts/src/bitrel.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 706066fbea4..24ac056ad42 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -29,19 +29,13 @@ impl BitRel { }; let bytes = ((self.end as usize) - (self.ptr as usize)) as u32; - if (2 * self.size1 * self.size2 * BITS) > bytes * 8 { - idl_trap_with("BitRel not enough bytes"); + if bytes != BitRel::words(self.size1, self.size2) * WORD_SIZE { + idl_trap_with("BitRel missized"); }; memzero(self.ptr as usize, Words(bytes / WORD_SIZE)); } - unsafe fn locate_ptr_bit( - &self - p: bool, - i_j: u32, - j_i: u32, - bit: u32, - ) -> (*mut u32, u32) { + unsafe fn locate_ptr_bit(&self, p: bool, i_j: u32, j_i: u32, bit: u32) -> (*mut u32, u32) { let size1 = self.size1; let size2 = self.size2; let (base, i, j) = if p { From 1c089d830b7e4e83a562398755fcb4962f16971d Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Fri, 28 Oct 2022 22:16:52 +0100 Subject: [PATCH 117/128] add #[allow(dead_code)] to bitrel.rs untested functions --- rts/motoko-rts/src/bitrel.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 24ac056ad42..85d5ca17ddf 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -1,5 +1,7 @@ //! This module implements a simple subtype cache used by the compiler (in generated code) +//TODO: add unit test and remove #[allow(dead_code)] on tested functions + use crate::constants::WORD_SIZE; use crate::idl_trap_with; use crate::mem_utils::memzero; @@ -19,10 +21,12 @@ pub struct BitRel { } impl BitRel { + #[allow(dead_code)] pub(crate) fn words(size1: u32, size2: u32) -> u32 { return ((2 * size1 * size2 * BITS) + (usize::BITS - 1)) / usize::BITS; } + #[allow(dead_code)] pub(crate) unsafe fn init(&self) { if (self.end as usize) < (self.ptr as usize) { idl_trap_with("BitRel invalid fields"); @@ -35,6 +39,7 @@ impl BitRel { memzero(self.ptr as usize, Words(bytes / WORD_SIZE)); } + #[allow(dead_code)] unsafe fn locate_ptr_bit(&self, p: bool, i_j: u32, j_i: u32, bit: u32) -> (*mut u32, u32) { let size1 = self.size1; let size2 = self.size2; @@ -77,24 +82,29 @@ impl BitRel { return *ptr & mask == mask; } + #[allow(dead_code)] pub(crate) unsafe fn visited(&self, p: bool, i_j: u32, j_i: u32) -> bool { self.get(p, i_j, j_i, 0) } + #[allow(dead_code)] pub(crate) unsafe fn visit(&self, p: bool, i_j: u32, j_i: u32) { self.set(p, i_j, j_i, 0, true) } + #[allow(dead_code)] // NB: we store related bits in negated form to avoid setting on assumption // This code is a nop in production code. pub(crate) unsafe fn assume(&self, p: bool, i_j: u32, j_i: u32) { debug_assert!(!self.get(p, i_j, j_i, 1)); } + #[allow(dead_code)] pub(crate) unsafe fn related(&self, p: bool, i_j: u32, j_i: u32) -> bool { !self.get(p, i_j, j_i, 1) } + #[allow(dead_code)] pub(crate) unsafe fn disprove(&self, p: bool, i_j: u32, j_i: u32) { self.set(p, i_j, j_i, 1, true) } From e088a7ec2d3279f0c1c87ee1d1391f404613621c Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 1 Nov 2022 17:26:13 +0000 Subject: [PATCH 118/128] test: unit test `bitrel.rs`, fixing bug (#3529) * unit test for bitrel * add unit test revealing bug; fix bug * optimize locate_ptr_bit * optimize locate_ptr_bit --- rts/motoko-rts-tests/src/bitrel.rs | 57 ++++++++++++++++++++++++++++++ rts/motoko-rts-tests/src/main.rs | 2 ++ rts/motoko-rts/src/bitrel.rs | 45 +++++++---------------- rts/motoko-rts/src/lib.rs | 2 +- 4 files changed, 73 insertions(+), 33 deletions(-) create mode 100644 rts/motoko-rts-tests/src/bitrel.rs diff --git a/rts/motoko-rts-tests/src/bitrel.rs b/rts/motoko-rts-tests/src/bitrel.rs new file mode 100644 index 00000000000..53689ff4ea5 --- /dev/null +++ b/rts/motoko-rts-tests/src/bitrel.rs @@ -0,0 +1,57 @@ +use motoko_rts::bitrel::BitRel; +use motoko_rts::types::{Value, Words}; + +pub unsafe fn test() { + println!("Testing bitrel ..."); + + const K: u32 = 128; + + const N: usize = (2 * K * K * 2 / usize::BITS) as usize; + + let mut cache: [u32; N] = [0xFFFFFFF; N]; + + assert_eq!(usize::BITS, 32); + for size1 in 0..K { + for size2 in 0..K { + let w = BitRel::words(size1, size2); + let bitrel = BitRel { + ptr: &mut cache[0], + end: &mut cache[w as usize], + size1: size1, + size2: size2, + }; + bitrel.init(); + for i in 0..size1 { + for j in 0..size2 { + // initially unvisited + assert!(!bitrel.visited(true, i, j)); // co + assert!(!bitrel.visited(false, j, i)); // contra + + // initially related + assert!(bitrel.related(true, i, j)); // co + assert!(bitrel.related(false, j, i)); // contra + + // test visiting + // co + bitrel.visit(true, i, j); + assert!(bitrel.visited(true, i, j)); + // contra + bitrel.visit(false, j, i); + assert!(bitrel.visited(false, j, i)); + + // test refutation + // co + bitrel.assume(true, i, j); + assert!(bitrel.related(true, i, j)); + bitrel.disprove(true, i, j); + assert!(!bitrel.related(true, i, j)); + // contra + bitrel.assume(false, j, i); + assert!(bitrel.related(false, j, i)); + bitrel.disprove(false, j, i); + assert!(!bitrel.related(false, j, i)); + } + } + } + } +} diff --git a/rts/motoko-rts-tests/src/main.rs b/rts/motoko-rts-tests/src/main.rs index ac63a9aeabc..e7da81d36f6 100644 --- a/rts/motoko-rts-tests/src/main.rs +++ b/rts/motoko-rts-tests/src/main.rs @@ -2,6 +2,7 @@ mod bigint; mod bitmap; +mod bitrel; mod continuation_table; mod crc32; mod gc; @@ -24,6 +25,7 @@ fn main() { unsafe { bigint::test(); bitmap::test(); + bitrel::test(); continuation_table::test(); crc32::test(); gc::test(); diff --git a/rts/motoko-rts/src/bitrel.rs b/rts/motoko-rts/src/bitrel.rs index 85d5ca17ddf..ec71fcf78f6 100644 --- a/rts/motoko-rts/src/bitrel.rs +++ b/rts/motoko-rts/src/bitrel.rs @@ -1,7 +1,5 @@ //! This module implements a simple subtype cache used by the compiler (in generated code) -//TODO: add unit test and remove #[allow(dead_code)] on tested functions - use crate::constants::WORD_SIZE; use crate::idl_trap_with; use crate::mem_utils::memzero; @@ -21,13 +19,11 @@ pub struct BitRel { } impl BitRel { - #[allow(dead_code)] - pub(crate) fn words(size1: u32, size2: u32) -> u32 { + pub fn words(size1: u32, size2: u32) -> u32 { return ((2 * size1 * size2 * BITS) + (usize::BITS - 1)) / usize::BITS; } - #[allow(dead_code)] - pub(crate) unsafe fn init(&self) { + pub unsafe fn init(&self) { if (self.end as usize) < (self.ptr as usize) { idl_trap_with("BitRel invalid fields"); }; @@ -39,30 +35,19 @@ impl BitRel { memzero(self.ptr as usize, Words(bytes / WORD_SIZE)); } - #[allow(dead_code)] unsafe fn locate_ptr_bit(&self, p: bool, i_j: u32, j_i: u32, bit: u32) -> (*mut u32, u32) { let size1 = self.size1; let size2 = self.size2; - let (base, i, j) = if p { - (0, i_j, j_i) - } else { - (size1 * size2 * BITS, j_i, i_j) - }; - if i >= size1 { - idl_trap_with("BitRel i out of bounds"); - }; - if j >= size2 { - idl_trap_with("BitRel j out of bounds"); - }; - if bit >= BITS { - idl_trap_with("BitRel bit out of bounds"); - }; - let k = base + i * size2 * BITS + j + bit; + let (base, i, j) = if p { (0, i_j, j_i) } else { (size1, j_i, i_j) }; + debug_assert!(i < size1); + debug_assert!(j < size2); + debug_assert!(bit < BITS); + let k = ((base + i) * size2 + j) * BITS + bit; let word = (k / usize::BITS) as usize; let bit = (k % usize::BITS) as u32; let ptr = self.ptr.add(word); if ptr > self.end { - idl_trap_with("BitRel ptr out of bounds"); + idl_trap_with("BitRel indices out of bounds"); }; return (ptr, bit); } @@ -82,30 +67,26 @@ impl BitRel { return *ptr & mask == mask; } - #[allow(dead_code)] - pub(crate) unsafe fn visited(&self, p: bool, i_j: u32, j_i: u32) -> bool { + pub unsafe fn visited(&self, p: bool, i_j: u32, j_i: u32) -> bool { self.get(p, i_j, j_i, 0) } - #[allow(dead_code)] - pub(crate) unsafe fn visit(&self, p: bool, i_j: u32, j_i: u32) { + pub unsafe fn visit(&self, p: bool, i_j: u32, j_i: u32) { self.set(p, i_j, j_i, 0, true) } #[allow(dead_code)] // NB: we store related bits in negated form to avoid setting on assumption // This code is a nop in production code. - pub(crate) unsafe fn assume(&self, p: bool, i_j: u32, j_i: u32) { + pub unsafe fn assume(&self, p: bool, i_j: u32, j_i: u32) { debug_assert!(!self.get(p, i_j, j_i, 1)); } - #[allow(dead_code)] - pub(crate) unsafe fn related(&self, p: bool, i_j: u32, j_i: u32) -> bool { + pub unsafe fn related(&self, p: bool, i_j: u32, j_i: u32) -> bool { !self.get(p, i_j, j_i, 1) } - #[allow(dead_code)] - pub(crate) unsafe fn disprove(&self, p: bool, i_j: u32, j_i: u32) { + pub unsafe fn disprove(&self, p: bool, i_j: u32, j_i: u32) { self.set(p, i_j, j_i, 1, true) } } diff --git a/rts/motoko-rts/src/lib.rs b/rts/motoko-rts/src/lib.rs index 5b9a11acade..c8ac1db0279 100644 --- a/rts/motoko-rts/src/lib.rs +++ b/rts/motoko-rts/src/lib.rs @@ -10,7 +10,7 @@ mod print; pub mod debug; pub mod bigint; -mod bitrel; +pub mod bitrel; #[cfg(feature = "ic")] mod blob_iter; pub mod buf; From 8ddc970ca77a912ce02be9b0466e34108e33fc07 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 1 Nov 2022 17:43:45 +0000 Subject: [PATCH 119/128] Apply suggestions from code review Co-authored-by: Gabor Greif Co-authored-by: Luc Blaeser <112870813+luc-blaeser@users.noreply.github.com> --- rts/motoko-rts/src/idl.rs | 8 +++----- src/codegen/compile.ml | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 0317afdb022..a6767c5fcac 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -62,10 +62,8 @@ unsafe fn utf8_cmp(len1: u32, p1: *mut u8, len2: u32, p2: *mut u8) -> i32 { p2 as *mut libc::c_void, len as usize, ); - if cmp == -1 { - return -1; - } else if cmp == 1 { - return 1; + if cmp != 0 { + return cmp; } else if len1 > len { return 1; } else if len2 > len { @@ -813,7 +811,7 @@ unsafe extern "C" fn idl_sub_buf_init( rel_buf: *mut u32, typtbl_size1: u32, typtbl_size2: u32, -) -> () { +) { let rel = BitRel { ptr: rel_buf, end: rel_buf.add(idl_sub_buf_words(typtbl_size1, typtbl_size2) as usize), diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 5abbf50d79c..787479fc256 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -584,7 +584,7 @@ module E = struct (* See Note [Candid subtype checks] *) (* NB: we don't bother detecting duplicate registrations here because the code sharing machinery - ensures that `add_typtbl_typ t` is called at most once for any `t` with a distinct type hash *) + ensures that `add_typtbl_typ t` is called at most once for any `t` with a distinct type hash *) let add_typtbl_typ (env : t) ty : Int32.t = reg env.typtbl_typs ty @@ -6326,7 +6326,7 @@ Note [Candid subtype checks] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Deserializing Candid values requires a Candid subtype check when -deserializing value of reference types (actors and functions). +deserializing values of reference types (actors and functions). The subtype test is performed directly on the expected and actual candid type tables using RTS functions `idl_sub_buf_words`, From e08e25bc1146ebe8835eef0013884d17548bc37c Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 1 Nov 2022 17:48:47 +0000 Subject: [PATCH 120/128] use or-pattern --- rts/motoko-rts/src/idl.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index a6767c5fcac..6ca558e612a 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -599,10 +599,10 @@ unsafe fn sub( 'return_false: loop { match (u1, u2) { (_, IDL_CON_alias) | (IDL_CON_alias, _) => idl_trap_with("sub: unexpected alias"), - (_, IDL_PRIM_reserved) => return true, - (IDL_PRIM_empty, _) => return true, - (IDL_PRIM_nat, IDL_PRIM_int) => return true, - (_, IDL_CON_opt) => return true, // apparently, this is admissable + (_, IDL_PRIM_reserved) + | (IDL_PRIM_empty, _) + | (IDL_PRIM_nat, IDL_PRIM_int) + | (_, IDL_CON_opt) => return true, // apparently, this is admissable (IDL_CON_vec, IDL_CON_vec) => { let t11 = sleb128_decode(&mut tb1); let t21 = sleb128_decode(&mut tb2); @@ -807,11 +807,7 @@ unsafe extern "C" fn idl_sub_buf_words(typtbl_size1: u32, typtbl_size2: u32) -> } #[no_mangle] -unsafe extern "C" fn idl_sub_buf_init( - rel_buf: *mut u32, - typtbl_size1: u32, - typtbl_size2: u32, -) { +unsafe extern "C" fn idl_sub_buf_init(rel_buf: *mut u32, typtbl_size1: u32, typtbl_size2: u32) { let rel = BitRel { ptr: rel_buf, end: rel_buf.add(idl_sub_buf_words(typtbl_size1, typtbl_size2) as usize), From bc1951d6c69d5f9640c7b10b446711bbfad026ec Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 1 Nov 2022 17:49:41 +0000 Subject: [PATCH 121/128] Update rts/motoko-rts/src/idl.rs Co-authored-by: Gabor Greif --- rts/motoko-rts/src/idl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 6ca558e612a..16581b5e428 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -778,7 +778,7 @@ unsafe fn sub( }; break; } - if !(cmp == 0) { + if cmp != 0 { break 'return_false; }; if !sub(rel, p, typtbl1, typtbl2, end1, end2, t11, t21) { From f7abe5647664598797346e3c037e17f3ce98d540 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 1 Nov 2022 17:50:05 +0000 Subject: [PATCH 122/128] Update test/run-drun/idl-sub-ho-neg.mo --- test/run-drun/idl-sub-ho-neg.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/run-drun/idl-sub-ho-neg.mo b/test/run-drun/idl-sub-ho-neg.mo index 64ecb105e2d..f468701e391 100644 --- a/test/run-drun/idl-sub-ho-neg.mo +++ b/test/run-drun/idl-sub-ho-neg.mo @@ -419,4 +419,4 @@ actor this { //SKIP run //SKIP run-ir //SKIP run-low -//CALL ingress go "DIDL\x00\x00" \ No newline at end of file +//CALL ingress go "DIDL\x00\x00" From cdb0a8729027177a5e78c68312c75d6941293dbb Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 1 Nov 2022 17:56:30 +0000 Subject: [PATCH 123/128] typo in comment --- src/codegen/compile.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 787479fc256..6aba0a4cb2c 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -6340,7 +6340,7 @@ The known Motoko types are accumulated in a global list as required and then, in a final compilation step, encoded to global type table and sequence of type indices. The encoding is stored as static data referenced by dedicated wasm globals so that we can generate -code that reference the globals before their final definitions are +code that references the globals before their final definitions are known. Deserializing a proper (not extended) Candid value stack allocates a From a8bb5af794f3405ab6fa5e1084530510eac53b42 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 24 Jan 2023 18:01:09 +0000 Subject: [PATCH 124/128] Changelog++ --- Changelog.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Changelog.md b/Changelog.md index df1ae06c65d..6308c11951c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,16 @@ * motoko (`moc`) + * BREAKING CHANGE + + Motoko Candid de-serialization now checks that the actual type of a deserialized actor or shared function is a subtype of the expected type. + + Under an option type, failure of subtyping will cause the nearest enclosing value of optional type to be deserialized as `null`. + + Outside any option type, failure of subtyping will cause deserialization to fail with a trap, or, when using, `from_candid b`, return `null`. + + In particular, deserializing an optional variant type will succeed if the actual variant value is compatible with the expected variant type (even if the actual variant type is not a subtype of the expected type). + * BREAKING CHANGE On the IC, the act of making a call to a canister function can fail, so that the call cannot (and will not be) performed. From e905c3c8b627a0bba1d640742c3fde72058fdfab Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 25 Jan 2023 15:29:47 +0000 Subject: [PATCH 125/128] update test output --- test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok | 4 ++-- test/run-drun/ok/idl-sub-ho.ic-ref-run.ok | 4 ++-- test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok | 4 ++-- test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok | 4 ++-- test/run-drun/ok/idl-sub-rec.ic-ref-run.ok | 4 ++-- test/run-drun/ok/idl-sub-variant.ic-ref-run.ok | 6 +++--- test/run-drun/ok/idl-sub.ic-ref-run.ok | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok b/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok index 0074223ff2a..992d55fa9a6 100644 --- a/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-ho-neg.ic-ref-run.ok @@ -1,5 +1,5 @@ -=> update create_canister(record {settings = null}) -<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update provisional_create_canister_with_cycles(record {settings = null; amount = null}) +<= replied: (record {hymijyo = principal "rwlgt-iiaaa-aaaaa-aaaaa-cai"}) => update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... <= replied: () => update go() diff --git a/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok index 6df69242e6e..56cf840e251 100644 --- a/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-ho.ic-ref-run.ok @@ -1,5 +1,5 @@ -=> update create_canister(record {settings = null}) -<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update provisional_create_canister_with_cycles(record {settings = null; amount = null}) +<= replied: (record {hymijyo = principal "rwlgt-iiaaa-aaaaa-aaaaa-cai"}) => update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... <= replied: () => update go() diff --git a/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok b/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok index 73bef836584..0fc9c962cef 100644 --- a/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-opt-any-record.ic-ref-run.ok @@ -1,5 +1,5 @@ -=> update create_canister(record {settings = null}) -<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update provisional_create_canister_with_cycles(record {settings = null; amount = null}) +<= replied: (record {hymijyo = principal "rwlgt-iiaaa-aaaaa-aaaaa-cai"}) => update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... <= replied: () => update go() diff --git a/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok b/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok index b966951dead..a0db110c387 100644 --- a/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-opt-any.ic-ref-run.ok @@ -1,5 +1,5 @@ -=> update create_canister(record {settings = null}) -<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update provisional_create_canister_with_cycles(record {settings = null; amount = null}) +<= replied: (record {hymijyo = principal "rwlgt-iiaaa-aaaaa-aaaaa-cai"}) => update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... <= replied: () => update go() diff --git a/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok b/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok index b14f83967a8..07e06bc67c3 100644 --- a/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-rec.ic-ref-run.ok @@ -1,5 +1,5 @@ -=> update create_canister(record {settings = null}) -<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update provisional_create_canister_with_cycles(record {settings = null; amount = null}) +<= replied: (record {hymijyo = principal "rwlgt-iiaaa-aaaaa-aaaaa-cai"}) => update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... <= replied: () => update go() diff --git a/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok b/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok index 9c4c01872ac..676d9493fca 100644 --- a/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub-variant.ic-ref-run.ok @@ -1,9 +1,9 @@ -=> update create_canister(record {settings = null}) -<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update provisional_create_canister_with_cycles(record {settings = null; amount = null}) +<= replied: (record {hymijyo = principal "rwlgt-iiaaa-aaaaa-aaaaa-cai"}) => update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... <= replied: () => update go() debug.print: pass1 debug.print: pass1 -debug.print: pass3: canister did not respond +debug.print: pass3: canister trapped: EvalTrapError region:0xXXX-0xXXX "canister trapped explicitly: IDL error: unexpected variant tag" <= replied: () diff --git a/test/run-drun/ok/idl-sub.ic-ref-run.ok b/test/run-drun/ok/idl-sub.ic-ref-run.ok index 7a501a64316..8531556364f 100644 --- a/test/run-drun/ok/idl-sub.ic-ref-run.ok +++ b/test/run-drun/ok/idl-sub.ic-ref-run.ok @@ -1,5 +1,5 @@ -=> update create_canister(record {settings = null}) -<= replied: (record {hymijyo = principal "cvccv-qqaaq-aaaaa-aaaaa-c"}) +=> update provisional_create_canister_with_cycles(record {settings = null; amount = null}) +<= replied: (record {hymijyo = principal "rwlgt-iiaaa-aaaaa-aaaaa-cai"}) => update install_code(record {arg = blob ""; kca_xin = blob "\00asm\01\00\00\00\0... <= replied: () => update go() From 094794b6451ec6e590d6a05ebf0ae172c35aae41 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 25 Jan 2023 15:45:16 +0000 Subject: [PATCH 126/128] repoint candid dependencies to master --- nix/sources.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nix/sources.json b/nix/sources.json index a0009968740..ea79ee1a716 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -1,15 +1,15 @@ { "candid": { - "branch": "claudio/candid-subtype-check", + "branch": "master", "builtin": false, "description": "Candid Library for the Internet Computer", "homepage": "", "owner": "dfinity", "repo": "candid", - "rev": "0889e288c8c44ce36682ffa67df010c83e912a33", - "sha256": "122v440prlcr0z6zj1a7j0rjpk1a2xwpvj8vxrdbldl6ss1krbff", + "rev": "fa27eef96c96c2f774a479622996b42c7ae6c1bd", + "sha256": "18zhn0iyakq1212jizc406v9x275nivdnnwx5h2130ci10d7f1ah", "type": "tarball", - "url": "https://github.com/dfinity/candid/archive/0889e288c8c44ce36682ffa67df010c83e912a33.tar.gz", + "url": "https://github.com/dfinity/candid/archive/fa27eef96c96c2f774a479622996b42c7ae6c1bd.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "esm": { From 89b35cb0a04ccddf8152324daa7430e6840d216a Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 25 Jan 2023 16:25:55 +0000 Subject: [PATCH 127/128] Changelog++ --- Changelog.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Changelog.md b/Changelog.md index 6308c11951c..81afc15bd31 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,13 +4,16 @@ * BREAKING CHANGE - Motoko Candid de-serialization now checks that the actual type of a deserialized actor or shared function is a subtype of the expected type. + Motoko Candid de-serialization now checks that the actual type of a deserialized actor or function reference is a subtype of the expected type (#3171), + finally fully implementing Candid 1.4 (dfinity/candid#311). In summary: - Under an option type, failure of subtyping will cause the nearest enclosing value of optional type to be deserialized as `null`. + * Within an expected option type, failure of subtyping on actor or function references will cause the nearest enclosing value of optional type to be deserialized as `null`. - Outside any option type, failure of subtyping will cause deserialization to fail with a trap, or, when using, `from_candid b`, return `null`. + * Outside of any expected option type, failure of subtyping on actor or function references will cause deserialization to fail with a trap, + while deseriazing using `from_candid` will return `null`. - In particular, deserializing an optional variant type will succeed if the actual variant value is compatible with the expected variant type (even if the actual variant type is not a subtype of the expected type). + In particular (and as before), deserializing an optional variant type will succeed if the actual variant value is compatible with the expected variant type + (even if the actual variant type is not a subtype of the expected type). * BREAKING CHANGE From 5fe8d4207a0e4cce63a57e47e52468aa5410fa62 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 25 Jan 2023 18:17:24 +0000 Subject: [PATCH 128/128] less is more --- Changelog.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Changelog.md b/Changelog.md index 81afc15bd31..678815208c7 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,16 +4,13 @@ * BREAKING CHANGE - Motoko Candid de-serialization now checks that the actual type of a deserialized actor or function reference is a subtype of the expected type (#3171), - finally fully implementing Candid 1.4 (dfinity/candid#311). In summary: + Motoko now implements Candid 1.4 (dfinity/candid#311). - * Within an expected option type, failure of subtyping on actor or function references will cause the nearest enclosing value of optional type to be deserialized as `null`. + In particular, when deserializing an actor or function reference, + Motoko will now first check that the type of the deserialized reference + is a subtype of the expected type and act accordingly. - * Outside of any expected option type, failure of subtyping on actor or function references will cause deserialization to fail with a trap, - while deseriazing using `from_candid` will return `null`. - - In particular (and as before), deserializing an optional variant type will succeed if the actual variant value is compatible with the expected variant type - (even if the actual variant type is not a subtype of the expected type). + Very few users should be affected by this change in behaviour. * BREAKING CHANGE