Skip to content

More support to dynamic field - Sui framework compilation #73

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions external-crates/move/crates/move-model/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2259,6 +2259,19 @@ impl<'env> StructEnv<'env> {
}
}
}

/// Printing fields of the structure to a String
pub fn print_to_string(&self) -> String {
let mut out = String::new();
let s_full_name = self.get_full_name_str();
out.push_str(&format!("Struct {}\n", s_full_name));
for (ii, field) in self.get_fields().enumerate() {
let f_name = field.get_name().display(self.symbol_pool()).to_string();
let ty = field.get_type();
out.push_str(&format!(" field {ii} name \'{}\' type {:#?}\n", f_name, ty));
}
out
}
}

// =================================================================================================
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
; ModuleID = '0x1__dynamic_structure'
source_filename = "tests/failure-tests/dynamic-struct-example.move"
target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
target triple = "sbf-solana-solana"

%__move_rt_type = type { { ptr, i64 }, i64, ptr }
%struct.dynamic_structure__Inner_u64.u64_ = type { i64, i64 }
%struct.dynamic_structure__DynamicStruct_dynamic_structure__Inner_u64.u64__ = type { i64, %struct.dynamic_structure__Inner_u64.u64_ }

@__move_rttydesc_signer = private unnamed_addr constant %__move_rt_type { { ptr, i64 } { ptr @__move_rttydesc_signer_name, i64 6 }, i64 9, ptr @__move_rttydesc_NOTHING_info }
@__move_rttydesc_signer_name = private unnamed_addr constant [6 x i8] c"signer"
@__move_rttydesc_NOTHING_info = private unnamed_addr constant i8 -1

declare i32 @memcmp(ptr, ptr, i64)

define void @"0000000000000001_dynamic_structu_unit_test_poiso_EmvQWiAB3EnqkA"() {
entry:
%local_0 = alloca i64, align 8
%local_1 = alloca { ptr, i64, i64 }, align 8
store i64 0, ptr %local_0, align 8
%loaded_alloca = load i64, ptr %local_0, align 8
%retval = call { ptr, i64, i64 } @move_native_unit_test_create_signers_for_testing(i64 %loaded_alloca)
store { ptr, i64, i64 } %retval, ptr %local_1, align 8
call void @move_rt_vec_destroy(ptr @__move_rttydesc_signer, ptr %local_1)
ret void
}

declare { ptr, i64, i64 } @move_native_unit_test_create_signers_for_testing(i64)

define void @"0000000000000001_dynamic_structu_test_fail_Fz3ntiKYooMYAv"() {
entry:
%local_0 = alloca i64, align 8
%local_1 = alloca i64, align 8
%local_2 = alloca i64, align 8
store i64 44, ptr %local_0, align 8
store i64 1, ptr %local_1, align 8
store i64 2, ptr %local_2, align 8
%call_arg_0 = load i64, ptr %local_0, align 8
%call_arg_1 = load i64, ptr %local_1, align 8
%call_arg_2 = load i64, ptr %local_2, align 8
call void @"0000000000000001_dynamic_structu_dynamic_struct_7V7jBxBPWFRsaZ"(i64 %call_arg_0, i64 %call_arg_1, i64 %call_arg_2)
ret void
}

define private void @"0000000000000001_dynamic_structu_dynamic_struct_7V7jBxBPWFRsaZ"(i64 %0, i64 %1, i64 %2) {
entry:
%local_0 = alloca i64, align 8
%local_1 = alloca i64, align 8
%local_2 = alloca i64, align 8
%local_3__id = alloca i64, align 8
%local_4__key = alloca i64, align 8
%local_5__val = alloca i64, align 8
%local_6__s = alloca %struct.dynamic_structure__Inner_u64.u64_, align 8
%local_7 = alloca %struct.dynamic_structure__DynamicStruct_dynamic_structure__Inner_u64.u64__, align 8
store i64 %0, ptr %local_0, align 8
store i64 %1, ptr %local_1, align 8
store i64 %2, ptr %local_2, align 8
%load_store_tmp = load i64, ptr %local_0, align 8
store i64 %load_store_tmp, ptr %local_3__id, align 8
%load_store_tmp1 = load i64, ptr %local_1, align 8
store i64 %load_store_tmp1, ptr %local_4__key, align 8
%load_store_tmp2 = load i64, ptr %local_2, align 8
store i64 %load_store_tmp2, ptr %local_5__val, align 8
%fv.0 = load i64, ptr %local_4__key, align 8
%fv.1 = load i64, ptr %local_5__val, align 8
%insert_0 = insertvalue %struct.dynamic_structure__Inner_u64.u64_ undef, i64 %fv.0, 0
%insert_1 = insertvalue %struct.dynamic_structure__Inner_u64.u64_ %insert_0, i64 %fv.1, 1
store %struct.dynamic_structure__Inner_u64.u64_ %insert_1, ptr %local_6__s, align 8
%fv.03 = load i64, ptr %local_3__id, align 8
%fv.14 = load %struct.dynamic_structure__Inner_u64.u64_, ptr %local_6__s, align 8
%insert_05 = insertvalue %struct.dynamic_structure__DynamicStruct_dynamic_structure__Inner_u64.u64__ undef, i64 %fv.03, 0
%insert_16 = insertvalue %struct.dynamic_structure__DynamicStruct_dynamic_structure__Inner_u64.u64__ %insert_05, %struct.dynamic_structure__Inner_u64.u64_ %fv.14, 1
store %struct.dynamic_structure__DynamicStruct_dynamic_structure__Inner_u64.u64__ %insert_16, ptr %local_7, align 8
ret void
}

declare void @move_rt_vec_destroy(ptr nonnull readonly dereferenceable(32), ptr)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
; ModuleID = '0x1__unit_test'
source_filename = "../../crates/move-stdlib/sources/unit_test.move"
target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
target triple = "sbf-solana-solana"

%__move_rt_type = type { { ptr, i64 }, i64, ptr }

@__move_rttydesc_signer = private unnamed_addr constant %__move_rt_type { { ptr, i64 } { ptr @__move_rttydesc_signer_name, i64 6 }, i64 9, ptr @__move_rttydesc_NOTHING_info }
@__move_rttydesc_signer_name = private unnamed_addr constant [6 x i8] c"signer"
@__move_rttydesc_NOTHING_info = private unnamed_addr constant i8 -1

declare i32 @memcmp(ptr, ptr, i64)

declare { ptr, i64, i64 } @move_native_unit_test_create_signers_for_testing(i64)

declare void @move_native_unit_test_poison()

define void @"0000000000000001_unit_test_unit_test_poiso_4afD3MScT99fc9"() {
entry:
%local_0 = alloca i64, align 8
%local_1 = alloca { ptr, i64, i64 }, align 8
store i64 0, ptr %local_0, align 8
%loaded_alloca = load i64, ptr %local_0, align 8
%retval = call { ptr, i64, i64 } @move_native_unit_test_create_signers_for_testing(i64 %loaded_alloca)
store { ptr, i64, i64 } %retval, ptr %local_1, align 8
call void @move_rt_vec_destroy(ptr @__move_rttydesc_signer, ptr %local_1)
ret void
}

declare void @move_rt_vec_destroy(ptr nonnull readonly dereferenceable(32), ptr)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module 0x1::dynamic_structure {
struct Inner<K, V> has copy, drop, store {
key: K,
val: V,
}

struct DynamicStruct<S: drop> has copy, drop, store {
id: u64,
s: S,
}

public fun dynamic_struct<K: drop, V: drop>(id: u64, key: K, val: V) {
DynamicStruct {
id,
s: Inner { key, val },
};
}
public fun test_fail() {
// If code is open then `dynamic_struct` is instantiated explicitly and
// `dynamic_struct` call below will not fail.
// DynamicStruct {
// id: 44,
// s: Inner { key: 1, val: 2 },
// };

// this was failing before commit `061824-fixing-dynamic-fields`
dynamic_struct(44, 1, 2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ impl<'mm, 'up> EntrypointGenerator<'mm, 'up> {
self.llvm_builder.build_cond_br(condition, then_bb, else_bb);
self.llvm_builder.position_at_end(then_bb);
let fn_name = fun.llvm_symbol_name(&[]);
debug!(target: "debug", "add_entries: function {fn_name}");
let fn_decls = self.fn_decls.borrow();
let ll_fun = fn_decls.get(&fn_name).unwrap();
let params = self.emit_entry_arguments(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ pub impl TypeExt for mty::Type {
Type::Reference(_, _) => 64,
Type::Vector(_) => 8 * MOVE_UNTYPED_VEC_DESC_SIZE,
Type::Struct(_m, _s, ref tys) => tys.iter().fold(0, |acc, ty| acc + ty.get_bitwidth()),
Type::Fun(v, _r) => {
let mut sz: u64 = 64; // Adding size of pointer in Box, it should be the same as for Reference
for i in 0..v.len() {
sz += v[i].get_bitwidth();
}
sz
}
Type::TypeParameter(_x) => 16,
_ => {
todo!("{self:?}")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
fn declare_structs(&mut self) {
use move_binary_format::{access::ModuleAccess, views::StructHandleView};
let m_env = &self.env;
let mod_name = &m_env.get_full_name_str();
let g_env = &m_env.env;

// Collect all the externally defined structures (transitively) used within this module.
Expand Down Expand Up @@ -135,7 +136,7 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
all_structs.append(&mut local_structs);

debug!(target: "structs",
"Combined list of all structs{}",
"Module {mod_name} combined list of all structs{}",
self.dump_all_structs(&all_structs, false),
);

Expand Down Expand Up @@ -179,7 +180,10 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
for s_def_inst in cm.struct_instantiations() {
let tys = m_env.get_type_actuals(Some(s_def_inst.type_parameters));
let s_env = m_env.get_struct_by_def_idx(s_def_inst.def);
let s_name = s_env.ll_struct_name_from_raw_name(&tys);
debug!(target: "structs", "Module {mod_name} trying to create opaque named structure for {s_name}, case struct");
if create_opaque_named_struct(&s_env, &tys) {
debug!(target: "structs", "Module {mod_name} created opaque named structure for {s_name}, case struct");
all_structs.push((s_env, tys));
}
}
Expand All @@ -189,7 +193,10 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
let fld_handle = cm.field_handle_at(f_inst.handle);
let tys = m_env.get_type_actuals(Some(f_inst.type_parameters));
let s_env = m_env.get_struct_by_def_idx(fld_handle.owner);
let s_name = s_env.ll_struct_name_from_raw_name(&tys);
debug!(target: "structs", "Module {mod_name} trying to create opaque named structure for {s_name}, case field");
if create_opaque_named_struct(&s_env, &tys) {
debug!(target: "structs", "Module {mod_name} created opaque named structure for {s_name}, case field");
all_structs.push((s_env, tys));
}
}
Expand All @@ -214,7 +221,7 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
}

debug!(target: "structs",
"Structs after visiting the signature table{}",
"Module {mod_name} structs after visiting the signature table{}",
self.dump_all_structs(&all_structs, false),
);

Expand All @@ -239,7 +246,7 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {

debug!(
target: "structs",
"Structs after translation{}",
"Module {mod_name} structs after translation{}",
self.dump_all_structs(&all_structs, true),
);
}
Expand All @@ -250,23 +257,30 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
// are mixed in the nesting of type parameters,
// e.g. Struct_A<Vector<Struct_B<T>>>, where T is substituted by a
// concrete type, won't be declared correctly.
fn translate_struct(&self, s_env: &mm::StructEnv<'mm>, tyvec: &[mty::Type]) {
pub fn translate_struct(&self, s_env: &mm::StructEnv<'mm>, tyvec: &[mty::Type]) -> crate::stackless::StructType {
let ll_name = s_env.ll_struct_name_from_raw_name(tyvec);
debug!(target: "structs", "translating struct {}", s_env.struct_raw_type_name(tyvec));
debug!(target: "structs", "translating struct {}", ll_name);
let g_env = self.env.env;
// Visit each field in this struct, collecting field types.
let mut ll_field_tys = Vec::with_capacity(s_env.get_field_count() + 1);
for fld_env in s_env.get_fields() {
debug!(target: "structs", "translating field {:?}", &fld_env.get_type());
if let mty::Type::Struct(_m, _s, _tys) = &fld_env.get_type() {
if let mty::Type::Struct(mod_id, s_id, tys) = &fld_env.get_type() {
let mod_env = &g_env.get_module(*mod_id);
let struct_env = mod_env.get_struct(*s_id);
let struct_name = struct_env.ll_struct_name_from_raw_name(&tys);
debug!(target: "debug", "translate_struct: case 1 param is a structure {struct_name}");
let new_sty = &fld_env.get_type().instantiate(tyvec);
if let mty::Type::Struct(m, s, tys) = new_sty {
let g_env = &self.env.env;
let s_env = g_env.get_module(*m).into_struct(*s);
self.translate_struct(&s_env, tys);
}
} else if let mty::Type::TypeParameter(x) = &fld_env.get_type() {
if let mty::Type::Struct(m, s, tys) = &tyvec[*x as usize] {
let g_env = &self.env.env;
let mod_env = &g_env.get_module(*m);
let struct_env = mod_env.get_struct(*s);
let struct_name = struct_env.ll_struct_name_from_raw_name(&tys);
debug!(target: "debug", "translate_struct: case 2 param is a structure {struct_name}");
let s_env = g_env.get_module(*m).into_struct(*s);
self.translate_struct(&s_env, tys);
}
Expand All @@ -289,6 +303,10 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
.named_struct_type(&ll_name)
.expect("no struct type");
ll_sty.set_struct_body(&ll_field_tys);
let dump = ll_sty.dump_to_string();
debug!(target: "debug", "Dumping translated structure {ll_name} {}", dump);
assert!(!self.llvm_cx.named_struct_type(&ll_name).is_none(), "At this point struct {} should already get some type", &ll_name);
ll_sty
}

// This method is used to declare structs found when function
Expand Down Expand Up @@ -681,31 +699,42 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
None
}
}
Type::Struct(_mid, _sid, _tys) => {
Type::Struct(_mid, _sid, ttys) => {
// First substitute any generic type parameters occuring in _tys.
let new_sty = mty.instantiate(tyvec);
let mod_name = &self.env.get_full_name_str();
if Self::is_generic_struct(ttys) {
debug!(target: "debug", "Module {mod_name} generic struct {:#?}", new_sty);
}

debug!(
target: "structs",
"Instantiated struct {}",
"Instantiated struct {}, Type {:#?}",
new_sty
.get_struct(self.env.env)
.unwrap()
.0
.struct_raw_type_name(tyvec)
.struct_raw_type_name(tyvec),
new_sty
);
// Then process the (possibly type-substituted) struct.
if let Type::Struct(declaring_module_id, struct_id, tys) = new_sty {
let global_env = &self.env.env;
let struct_env = global_env
.get_module(declaring_module_id)
.into_struct(struct_id);
let decl_mod_name = global_env.get_module(declaring_module_id).get_full_name_str();
let struct_name = struct_env.ll_struct_name_from_raw_name(&tys);
debug!(target: "debug", "Module {decl_mod_name} structure {struct_name}");
if Self::is_generic_struct(&tys) {
debug!(target: "debug", "Module {decl_mod_name} generic struct {:#?}", struct_name);
}
if let Some(stype) = self.llvm_cx.named_struct_type(&struct_name) {
Some(stype.as_any_type())
} else {
debug!(target: "structs", "struct type for '{}' not found", &struct_name);
None
debug!(target: "structs", "struct type for '{}' not found, cretae it now", &struct_name);
let stype = self.translate_struct(&struct_env, &tys);
Some(stype.as_any_type())
}
} else {
unreachable!("")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,11 @@ impl<'mm, 'up> RttyContext<'mm, 'up> {
_ => unreachable!(),
};

debug!(target: "debug", "s_env {:#?}", &s_env);
if let Some(f_env) = &self.f_env {
let f_name = f_env.get_full_name_str();
debug!(target: "rtty", "f_name {:#?}", &f_name);
}


// Look up the corresponding LLVM struct type constructed earlier in the translation.
// Use it to collect field offsets, struct size, and struct alignment as computed by LLVM.
Expand Down
Loading
Loading