Skip to content

Commit

Permalink
Collect logged types and include them in the JSON ABI + __log intri…
Browse files Browse the repository at this point in the history
…nsic (FuelLabs#2689)
  • Loading branch information
mohammadfawaz authored Sep 5, 2022
1 parent b91bb84 commit a989e6c
Show file tree
Hide file tree
Showing 190 changed files with 1,048 additions and 136 deletions.
10 changes: 9 additions & 1 deletion forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1634,7 +1634,7 @@ pub fn compile(
let mut types = vec![];
let json_abi_program = time_expr!(
"generate JSON ABI program",
typed_program.kind.generate_json_abi_program(&mut types)
typed_program.generate_json_abi_program(&mut types)
);

let storage_slots = typed_program.storage_slots.clone();
Expand Down Expand Up @@ -1914,6 +1914,7 @@ pub fn build(plan: &BuildPlan, profile: &BuildProfile) -> anyhow::Result<(Compil
let mut json_abi_program = JsonABIProgram {
types: vec![],
functions: vec![],
logged_types: vec![],
};
let mut storage_slots = vec![];
let mut bytecode = vec![];
Expand Down Expand Up @@ -1942,6 +1943,9 @@ pub fn build(plan: &BuildPlan, profile: &BuildProfile) -> anyhow::Result<(Compil
json_abi_program
.functions
.extend(compiled.json_abi_program.functions);
json_abi_program
.logged_types
.extend(compiled.json_abi_program.logged_types);
storage_slots.extend(compiled.storage_slots);
bytecode = compiled.bytecode;
tree_type = Some(compiled.tree_type);
Expand Down Expand Up @@ -2038,6 +2042,10 @@ fn update_all_types(json_abi_program: &mut JsonABIProgram, old_to_new_id: &HashM
for decl in json_abi_program.types.iter_mut() {
update_json_type_declaration(decl, old_to_new_id);
}

for logged_type in json_abi_program.logged_types.iter_mut() {
update_json_type_application(&mut logged_type.logged_type, old_to_new_id);
}
}

/// Recursively updates the type IDs used in a `JsonTypeApplication` given a HashMap from old to
Expand Down
3 changes: 3 additions & 0 deletions sway-ast/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub enum Intrinsic {
StateStoreWord,
StateLoadQuad,
StateStoreQuad,
Log,
}

impl fmt::Display for Intrinsic {
Expand All @@ -29,6 +30,7 @@ impl fmt::Display for Intrinsic {
Intrinsic::StateStoreWord => "state_store_word",
Intrinsic::StateLoadQuad => "state_load_quad",
Intrinsic::StateStoreQuad => "state_store_quad",
Intrinsic::Log => "log",
};
write!(f, "{}", s)
}
Expand All @@ -49,6 +51,7 @@ impl Intrinsic {
"__state_store_word" => StateStoreWord,
"__state_load_quad" => StateLoadQuad,
"__state_store_quad" => StateStoreQuad,
"__log" => Log,
_ => return None,
})
}
Expand Down
49 changes: 49 additions & 0 deletions sway-core/src/asm_generation/from_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,11 @@ impl<'ir> AsmBuilder<'ir> {
warnings,
errors
),
Instruction::Log {
log_val,
log_ty,
log_id,
} => self.compile_log(instr_val, log_val, log_ty, log_id),
Instruction::Nop => (),
Instruction::Phi(_) => (), // Managing the phi value is done in br and cbr compilation.
Instruction::ReadRegister(reg) => self.compile_read_register(instr_val, reg),
Expand Down Expand Up @@ -1532,6 +1537,50 @@ impl<'ir> AsmBuilder<'ir> {
ok((), Vec::new(), Vec::new())
}

fn compile_log(&mut self, instr_val: &Value, log_val: &Value, log_ty: &Type, log_id: &Value) {
let owning_span = self.md_mgr.val_to_span(self.context, *instr_val);
let log_val_reg = self.value_to_register(log_val);
let log_id_reg = self.value_to_register(log_id);

if log_ty.is_copy_type() {
self.bytecode.push(Op {
owning_span,
opcode: Either::Left(VirtualOp::LOG(
log_val_reg,
log_id_reg,
VirtualRegister::Constant(ConstantRegister::Zero),
VirtualRegister::Constant(ConstantRegister::Zero),
)),
comment: "".into(),
});
} else {
// If the type not a reference type then we use LOGD to log the data. First put the
// size into the data section, then add a LW to get it, then add a LOGD which uses
// it.
let size_reg = self.reg_seqr.next();
let size_in_bytes = ir_type_size_in_bytes(self.context, log_ty);
let size_data_id = self
.data_section
.insert_data_value(&Literal::U64(size_in_bytes));

self.bytecode.push(Op {
opcode: Either::Left(VirtualOp::LWDataId(size_reg.clone(), size_data_id)),
owning_span: owning_span.clone(),
comment: "loading size for LOGD".into(),
});
self.bytecode.push(Op {
owning_span,
opcode: Either::Left(VirtualOp::LOGD(
VirtualRegister::Constant(ConstantRegister::Zero),
log_id_reg,
log_val_reg,
size_reg,
)),
comment: "".into(),
});
}
}

fn compile_read_register(&mut self, instr_val: &Value, reg: &sway_ir::Register) {
let instr_reg = self.reg_seqr.next();
self.bytecode.push(Op {
Expand Down
25 changes: 25 additions & 0 deletions sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,31 @@ impl FnCompiler {
_ => unreachable!(),
}
}
Intrinsic::Log => {
// The log value and the log ID are just Value.
let log_val = self.compile_expression(context, md_mgr, arguments[0].clone())?;
let log_id = convert_literal_to_value(
context,
&Literal::U64(*arguments[0].return_type as u64),
);

match log_val.get_stripped_ptr_type(context) {
None => Err(CompileError::Internal(
"Unable to determine type for return statement expression.",
span,
)),
Some(log_ty) => {
let span_md_idx = md_mgr.span_to_md(context, &span);

// The `log` instruction
Ok(self
.current_block
.ins(context)
.log(log_val, log_ty, log_id)
.add_metadatum(context, span_md_idx))
}
}
}
}
}

Expand Down
45 changes: 36 additions & 9 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub use crate::parse_tree::{

pub use error::{CompileError, CompileResult, CompileWarning};
use sway_types::{ident::Ident, span, Spanned};
pub use type_system::TypeInfo;
pub use type_system::*;

/// Given an input `Arc<str>` and an optional [BuildConfig], parse the input into a [SwayParseTree].
///
Expand Down Expand Up @@ -246,7 +246,7 @@ pub fn parsed_to_ast(
} = TypedProgram::type_check(parse_program, initial_namespace);
warnings.extend(new_warnings);
errors.extend(new_errors);
let typed_program = match typed_program_result {
let mut typed_program = match typed_program_result {
Some(typed_program) => typed_program,
None => {
errors = dedup_unsorted(errors);
Expand All @@ -255,6 +255,20 @@ pub fn parsed_to_ast(
}
};

// Collect information about the types used in this program
let types_metadata = typed_program.collect_types_metadata();

// Collect all the types of logged values. These are required when generating the JSON ABI.
typed_program.logged_types.extend(
types_metadata
.iter()
.filter_map(|m| match m {
TypeMetadata::LoggedType(type_id) => Some(*type_id),
_ => None,
})
.collect::<Vec<_>>(),
);

let mut cfa_res = perform_control_flow_analysis(&typed_program);

errors.append(&mut cfa_res.errors);
Expand Down Expand Up @@ -304,6 +318,26 @@ pub fn parsed_to_ast(
}
};

// All unresolved types lead to compile errors
let unresolved_types_errors = types_metadata
.iter()
.filter_map(|m| match m {
TypeMetadata::UnresolvedType {
name,
span_override,
} => Some(CompileError::UnableToInferGeneric {
ty: name.as_str().to_string(),
span: span_override.clone().unwrap_or_else(|| name.span()),
}),
_ => None,
})
.collect::<Vec<_>>();
errors.extend(unresolved_types_errors);
if !errors.is_empty() {
errors = dedup_unsorted(errors);
return CompileAstResult::Failure { errors, warnings };
}

CompileAstResult::Success {
typed_program: Box::new(typed_program_with_storage_slots),
warnings,
Expand Down Expand Up @@ -427,13 +461,6 @@ pub(crate) fn compile_ast_to_ir_to_asm(
// errors and then hold as a runtime invariant that none of the types will be unresolved in the
// IR phase.

check!(
program.finalize_types(),
return err(warnings, errors),
warnings,
errors
);

let tree_type = program.kind.tree_type();
let mut ir = match ir_generation::compile_program(program) {
Ok(ir) => ir,
Expand Down
20 changes: 10 additions & 10 deletions sway-core/src/semantic_analysis/ast_node/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,44 +133,44 @@ impl fmt::Display for TypedDeclaration {
}
}

impl UnresolvedTypeCheck for TypedDeclaration {
impl CollectTypesMetadata for TypedDeclaration {
// this is only run on entry nodes, which must have all well-formed types
fn check_for_unresolved_types(&self) -> Vec<CompileError> {
fn collect_types_metadata(&self) -> Vec<TypeMetadata> {
use TypedDeclaration::*;
match self {
VariableDeclaration(decl) => {
let mut body = decl.body.check_for_unresolved_types();
body.append(&mut decl.type_ascription.check_for_unresolved_types());
let mut body = decl.body.collect_types_metadata();
body.append(&mut decl.type_ascription.collect_types_metadata());
body
}
FunctionDeclaration(decl) => {
let mut body: Vec<CompileError> = decl
let mut body: Vec<TypeMetadata> = decl
.body
.contents
.iter()
.flat_map(UnresolvedTypeCheck::check_for_unresolved_types)
.flat_map(CollectTypesMetadata::collect_types_metadata)
.collect();
body.append(&mut decl.return_type.check_for_unresolved_types());
body.append(&mut decl.return_type.collect_types_metadata());
body.append(
&mut decl
.type_parameters
.iter()
.map(|x| &x.type_id)
.flat_map(UnresolvedTypeCheck::check_for_unresolved_types)
.flat_map(CollectTypesMetadata::collect_types_metadata)
.collect(),
);
body.append(
&mut decl
.parameters
.iter()
.map(|x| &x.type_id)
.flat_map(UnresolvedTypeCheck::check_for_unresolved_types)
.flat_map(CollectTypesMetadata::collect_types_metadata)
.collect(),
);
body
}
ConstantDeclaration(TypedConstantDeclaration { value, .. }) => {
value.check_for_unresolved_types()
value.collect_types_metadata()
}
ErrorRecovery
| StorageDeclaration(_)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,24 @@ impl DeterministicallyAborts for TypedIntrinsicFunctionKind {
}
}

impl UnresolvedTypeCheck for TypedIntrinsicFunctionKind {
fn check_for_unresolved_types(&self) -> Vec<CompileError> {
self.type_arguments
impl CollectTypesMetadata for TypedIntrinsicFunctionKind {
fn collect_types_metadata(&self) -> Vec<TypeMetadata> {
let mut types_metadata = self
.type_arguments
.iter()
.flat_map(|targ| targ.type_id.check_for_unresolved_types())
.flat_map(|targ| targ.type_id.collect_types_metadata())
.chain(
self.arguments
.iter()
.flat_map(UnresolvedTypeCheck::check_for_unresolved_types),
.flat_map(CollectTypesMetadata::collect_types_metadata),
)
.collect()
.collect::<Vec<_>>();

if matches!(self.kind, Intrinsic::Log) {
types_metadata.push(TypeMetadata::LoggedType(self.arguments[0].return_type));
}

types_metadata
}
}

Expand Down Expand Up @@ -497,6 +504,34 @@ impl TypedIntrinsicFunctionKind {
let return_type = insert_type(TypeInfo::Tuple(vec![]));
(intrinsic_function, return_type)
}
Intrinsic::Log => {
if arguments.len() != 1 {
errors.push(CompileError::IntrinsicIncorrectNumArgs {
name: kind.to_string(),
expected: 1,
span,
});
return err(warnings, errors);
}
let ctx = ctx
.by_ref()
.with_help_text("")
.with_type_annotation(insert_type(TypeInfo::Unknown));
let exp = check!(
TypedExpression::type_check(ctx, arguments[0].clone()),
return err(warnings, errors),
warnings,
errors
);
let intrinsic_function = TypedIntrinsicFunctionKind {
kind,
arguments: vec![exp],
type_arguments: vec![],
span,
};
let return_type = insert_type(TypeInfo::Tuple(vec![]));
(intrinsic_function, return_type)
}
};
ok((intrinsic_function, return_type), warnings, errors)
}
Expand Down
Loading

0 comments on commit a989e6c

Please sign in to comment.