diff --git a/Cargo.lock b/Cargo.lock index 5cf44ba5..95016946 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -690,6 +690,7 @@ version = "0.1.10" dependencies = [ "fce-wit-parser", "fluence-sdk-wit 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools", "once_cell", "serde", "serde_json", @@ -729,15 +730,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "fluence" -version = "0.2.8" -source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30" -dependencies = [ - "fluence-sdk-macro 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)", - "fluence-sdk-main 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)", -] - [[package]] name = "fluence" version = "0.2.8" @@ -748,6 +740,15 @@ dependencies = [ "fluence-sdk-main 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fluence" +version = "0.2.8" +source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30" +dependencies = [ + "fluence-sdk-macro 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)", + "fluence-sdk-main 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)", +] + [[package]] name = "fluence-app-service" version = "0.1.11" @@ -786,14 +787,6 @@ dependencies = [ "wasmer-wasi-fl", ] -[[package]] -name = "fluence-sdk-macro" -version = "0.2.8" -source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30" -dependencies = [ - "fluence-sdk-wit 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)", -] - [[package]] name = "fluence-sdk-macro" version = "0.2.8" @@ -804,13 +797,11 @@ dependencies = [ ] [[package]] -name = "fluence-sdk-main" +name = "fluence-sdk-macro" version = "0.2.8" source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30" dependencies = [ - "fluence-sdk-macro 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)", - "log", - "serde", + "fluence-sdk-wit 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)", ] [[package]] @@ -825,9 +816,20 @@ dependencies = [ ] [[package]] -name = "fluence-sdk-wit" +name = "fluence-sdk-main" version = "0.2.8" source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30" +dependencies = [ + "fluence-sdk-macro 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)", + "log", + "serde", +] + +[[package]] +name = "fluence-sdk-wit" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560baf91197ded38a99a5c94ff366a3dd971ebf33f5d987ecce31d3dedf86d17" dependencies = [ "proc-macro2", "quote", @@ -840,8 +842,7 @@ dependencies = [ [[package]] name = "fluence-sdk-wit" version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560baf91197ded38a99a5c94ff366a3dd971ebf33f5d987ecce31d3dedf86d17" +source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30" dependencies = [ "proc-macro2", "quote", @@ -2809,8 +2810,7 @@ dependencies = [ [[package]] name = "wasmer-interface-types-fl" version = "0.17.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88cf928132b7cc391adc52c47ae48aaebff01a85649b815b3e0142f8111c5529" +source = "git+https://github.com/fluencelabs/interface-types?branch=impl_refactoring#4d1d48bbbf9fdd40677474e9ee8d123803534d60" dependencies = [ "log", "nom", diff --git a/crates/wit-generator/Cargo.toml b/crates/wit-generator/Cargo.toml index 929cc852..2e1aaaa2 100644 --- a/crates/wit-generator/Cargo.toml +++ b/crates/wit-generator/Cargo.toml @@ -15,7 +15,8 @@ fce-wit-parser = { path = "../wit-parser", version = "0.1.9"} fluence-sdk-wit = "0.2.8" walrus = "0.17.0" -wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.15" } +wasmer-wit = { package = "wasmer-interface-types-fl", git = "https://github.com/fluencelabs/interface-types", branch = "impl_refactoring" } +itertools = "0.9.0" once_cell = "1.4.0" serde = { version = "1.0.110", features = ["derive"] } serde_json = "1.0.56" diff --git a/crates/wit-generator/src/default_export_api_config.rs b/crates/wit-generator/src/default_export_api_config.rs index e0dc8aee..a8ff21e3 100644 --- a/crates/wit-generator/src/default_export_api_config.rs +++ b/crates/wit-generator/src/default_export_api_config.rs @@ -14,12 +14,10 @@ * limitations under the License. */ -use wasmer_wit::ast::Interfaces; -use wasmer_wit::types::InterfaceType as IType; -use wasmer_wit::ast::FunctionArg as IFunctionArg; -use once_cell::sync::Lazy; +use crate::IType; +use crate::IFunctionArg; -use std::rc::Rc; +use once_cell::sync::Lazy; pub(crate) struct ApiExportFuncDescriptor { pub(crate) name: &'static str, @@ -28,22 +26,6 @@ pub(crate) struct ApiExportFuncDescriptor { pub(crate) output_types: Vec, } -impl ApiExportFuncDescriptor { - pub fn update_interfaces(&self, interfaces: &mut Interfaces<'_>) { - let func_type = wasmer_wit::ast::Type::Function { - arguments: Rc::new(self.arguments.clone()), - output_types: Rc::new(self.output_types.clone()), - }; - interfaces.types.push(func_type); - - let export = wasmer_wit::ast::Export { - name: self.name, - function_type: self.id, - }; - interfaces.exports.push(export); - } -} - pub(crate) static ALLOCATE_FUNC: Lazy = Lazy::new(|| ApiExportFuncDescriptor { name: "allocate", @@ -76,7 +58,7 @@ pub(crate) static GET_RESULT_SIZE_FUNC: Lazy = Lazy::new(|| ApiExportFuncDescriptor { name: "get_result_size", id: 2, - arguments: vec![], + arguments: Vec::::new(), output_types: vec![IType::I32], }); @@ -84,7 +66,7 @@ pub(crate) static GET_RESULT_PTR_FUNC: Lazy = Lazy::new(|| ApiExportFuncDescriptor { name: "get_result_ptr", id: 3, - arguments: vec![], + arguments: Vec::::new(), output_types: vec![IType::I32], }); diff --git a/crates/wit-generator/src/instructions_generator.rs b/crates/wit-generator/src/instructions_generator.rs index 8c3888b3..30598b24 100644 --- a/crates/wit-generator/src/instructions_generator.rs +++ b/crates/wit-generator/src/instructions_generator.rs @@ -19,24 +19,25 @@ mod foreign_mod_instructions; mod record_instructions; mod utils; -use crate::Result; +pub(crate) use utils::add_function_type; -use wasmer_wit::types::InterfaceType as IType; -use wasmer_wit::ast::Interfaces; -use wasmer_wit::types::RecordType; +use crate::*; +use crate::default_export_api_config::ApiExportFuncDescriptor; use std::rc::Rc; +use std::collections::HashMap; #[derive(PartialEq, Debug, Default)] pub(crate) struct WITResolver<'a> { - types: std::collections::HashMap, - pub(crate) interfaces: Interfaces<'a>, - not_resolved_types_count: usize, + record_types: HashMap, + unresolved_types_count: usize, + function_types: HashMap, + interfaces: Interfaces<'a>, } impl<'a> WITResolver<'a> { pub(crate) fn get_record_type_id(&self, record_name: &str) -> Result { - match self.types.get(record_name) { + match self.record_types.get(record_name) { Some(type_index) => Ok(*type_index), None => Err(crate::errors::WITGeneratorError::CorruptedRecord(format!( "Can't find record with name='{}', don't you forget to wrap it with #[fce]", @@ -47,27 +48,22 @@ impl<'a> WITResolver<'a> { // adds a stub for type with such a name if it wasn't found pub(crate) fn get_record_type_id_unchecked(&mut self, record_name: &str) -> usize { - use wasmer_wit::ast::Type; - - match self.types.get(record_name) { + match self.record_types.get(record_name) { Some(type_index) => *type_index, None => { - self.types + self.record_types .insert(record_name.to_string(), self.interfaces.types.len()); self.interfaces .types - .push(Type::Record(Rc::new(RecordType::default()))); + .push(AstType::Record(Rc::new(IRecordType::default()))); - self.not_resolved_types_count += 1; + self.unresolved_types_count += 1; self.interfaces.types.len() } } } - pub(crate) fn get_record_type( - &self, - record_type_id: u64, - ) -> Result<&wasmer_wit::types::RecordType> { + pub(crate) fn get_record_type(&self, record_type_id: u64) -> Result<&IRecordType> { if record_type_id >= self.interfaces.types.len() as u64 { return Err(crate::errors::WITGeneratorError::CorruptedRecord(format!( "Can't find record with id {}, don't you forget to wrap it with #[fce]", @@ -76,35 +72,158 @@ impl<'a> WITResolver<'a> { } match &self.interfaces.types[record_type_id as usize] { - wasmer_wit::ast::Type::Function { .. } => { + AstType::Function { .. } => { panic!("internal error inside WITResolver: interfaces AST type should be record not record") } - wasmer_wit::ast::Type::Record(record_type) => Ok(record_type), + AstType::Record(record_type) => Ok(record_type), } } - pub(crate) fn insert_record_type(&mut self, record: RecordType) { - use wasmer_wit::ast::Type; - - match self.types.get(&record.name) { + pub(crate) fn insert_record_type(&mut self, record: IRecordType) { + match self.record_types.get(&record.name) { Some(pos) => { - self.interfaces.types[*pos] = Type::Record(Rc::new(record)); - self.not_resolved_types_count -= 1; + self.interfaces.types[*pos] = AstType::Record(Rc::new(record)); + self.unresolved_types_count -= 1; } None => { - self.types + self.record_types .insert(record.name.clone(), self.interfaces.types.len()); - self.interfaces.types.push(Type::Record(Rc::new(record))); + self.interfaces.types.push(AstType::Record(Rc::new(record))); } } } - pub(crate) fn unresolved_types_count(&self) -> usize { - self.not_resolved_types_count + pub(crate) fn validate_records(&self) -> Result<()> { + use crate::errors::WITGeneratorError::CorruptedRecord; + const TYPE_RESOLVE_RECURSION_LIMIT: u32 = 1024; + + fn validate_record_type( + record_type: &IRecordType, + recursion_level: u32, + wit_resolver: &WITResolver<'_>, + ) -> Result<()> { + if recursion_level >= TYPE_RESOLVE_RECURSION_LIMIT { + return Err(CorruptedRecord(String::from( + "too many inner structures level", + ))); + } + + for field in record_type.fields.iter() { + match &field.ty { + wasmer_wit::types::InterfaceType::Record(record_type_id) => { + let inner_record_type = wit_resolver.get_record_type(*record_type_id)?; + validate_record_type( + &inner_record_type, + recursion_level + 1, + wit_resolver, + )?; + } + _ => continue, + } + } + + Ok(()) + } + + if self.unresolved_types_count != 0 { + return Err(CorruptedRecord(format!( + "{} types unresolved", + self.unresolved_types_count + ))); + } + + for ty in self.interfaces.types.iter() { + let record_type = match ty { + wasmer_wit::ast::Type::Record(ty) => ty, + _ => continue, + }; + + validate_record_type(record_type, 0, self)?; + } + + Ok(()) + } + + pub(crate) fn insert_default_api(&mut self, function_descriptor: &ApiExportFuncDescriptor) { + let function_type = IFunctionType { + arguments: function_descriptor.arguments.clone(), + output_types: function_descriptor.output_types.clone(), + }; + self.interfaces + .types + .push(AstType::Function(Rc::new(function_type))); + + let export = AstExport { + name: function_descriptor.name, + function_type: function_descriptor.id, + }; + self.interfaces.exports.push(export); + } + + /// Insert a new function type if there is no one already, + /// return already inserted otherwise. + pub(crate) fn insert_function_type(&mut self, function_type: IFunctionType) -> u32 { + use std::collections::hash_map::Entry::*; + + let next_id = (self.interfaces.types.len() + self.function_types.len()) as u32; + match self.function_types.entry(function_type) { + Occupied(entry) => *entry.get(), + Vacant(entry) => { + entry.insert(next_id); + next_id + } + } + } + + /// Insert a new adapter, returns its id. + pub(crate) fn insert_adapter(&mut self, adapter: AstAdapter) -> u32 { + self.interfaces.adapters.push(adapter); + + (self.interfaces.adapters.len() - 1) as u32 + } + + /// Insert a new implementation. + pub(crate) fn insert_implementation(&mut self, implementation: AstImplementation) -> u32 { + self.interfaces.implementations.push(implementation); + + (self.interfaces.implementations.len() - 1) as u32 + } + + /// Insert a new export type and returns its id, that uniquely identifies its + /// and could be used in a call-core instruction. + pub(crate) fn insert_export_type(&mut self, export: AstExport<'a>) -> u32 { + let interfaces = &mut self.interfaces; + interfaces.exports.push(export); + + (interfaces.exports.len() - 1) as u32 + } + + /// Insert a new import type and returns its id, that uniquely identifies its + /// and could be used in a call-core instruction. + pub(crate) fn insert_import_type(&mut self, import: AstImport<'a>) -> u32 { + let interfaces = &mut self.interfaces; + interfaces.imports.push(import); + + (interfaces.imports.len() + interfaces.exports.len() - 1) as u32 + } + + /// Prepares types by insert collected function types and return resulted Interfaces. + pub(crate) fn finalize(mut self) -> Interfaces<'a> { + use itertools::Itertools; + + let function_types: Vec<_> = self + .function_types + .into_iter() + .sorted_by(|(_, v1), (_, v2)| v1.cmp(&v2)) + .map(|(function_type, _)| AstType::Function(Rc::new(function_type))) + .collect(); + self.interfaces.types.extend(function_types); + + self.interfaces } } pub(crate) trait WITGenerator { - fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()>; + fn generate_wit<'ast_type, 'resolver>(&'ast_type self, wit_resolver: &'resolver mut WITResolver<'ast_type>) -> Result<()>; } diff --git a/crates/wit-generator/src/instructions_generator/fn_instructions.rs b/crates/wit-generator/src/instructions_generator/fn_instructions.rs index 1018c1a2..d8c8fdcd 100644 --- a/crates/wit-generator/src/instructions_generator/fn_instructions.rs +++ b/crates/wit-generator/src/instructions_generator/fn_instructions.rs @@ -14,107 +14,82 @@ * limitations under the License. */ +use super::add_function_type; use super::WITGenerator; use super::WITResolver; use super::utils::ptype_to_itype_checked; use crate::default_export_api_config::*; +use crate::AstExport; use crate::Result; use fluence_sdk_wit::AstFunctionItem; use fluence_sdk_wit::ParsedType; use wasmer_wit::interpreter::Instruction; -use wasmer_wit::ast::FunctionArg as IFunctionArg; - -use std::rc::Rc; impl WITGenerator for AstFunctionItem { - fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()> { - use wasmer_wit::ast::Type; - use wasmer_wit::ast::Adapter; + fn generate_wit<'ast_type, 'resolver>(&'ast_type self, wit_resolver: &'resolver mut WITResolver<'ast_type>) -> Result<()> { + let arguments = &self.signature.arguments; + let output_type = &self.signature.output_type; - let arguments = self - .signature - .arguments - .iter() - .map(|(arg_name, arg_type)| -> Result { - Ok(IFunctionArg { - name: arg_name.clone(), - ty: ptype_to_itype_checked(arg_type, wit_resolver)?, - }) - }) - .collect::>>()?; - - let arguments = Rc::new(arguments); - - let output_types = match self.signature.output_type { - Some(ref output_type) => vec![ptype_to_itype_checked(output_type, wit_resolver)?], - None => vec![], - }; - let output_types = Rc::new(output_types); - - let interfaces = &mut wit_resolver.interfaces; - interfaces.types.push(Type::Function { - arguments: arguments.clone(), - output_types: output_types.clone(), - }); - - // TODO: replace with Wasm types - interfaces.types.push(Type::Function { - arguments, - output_types, - }); - - let adapter_idx = (interfaces.types.len() - 2) as u32; - let export_idx = (interfaces.types.len() - 1) as u32; - - interfaces.exports.push(wasmer_wit::ast::Export { + let function_type_id = add_function_type(arguments, output_type, wit_resolver)?; + let export_type = AstExport { name: &self.signature.name, - function_type: export_idx, - }); - - let mut instructions = self - .signature - .arguments - .iter() - .enumerate() - .try_fold::<_, _, Result<_>>( - Vec::new(), - |mut instructions, (arg_id, (_, input_type))| { - let mut new_instructions = input_type - .generate_instructions_for_input_type(arg_id as _, wit_resolver)?; - - instructions.append(&mut new_instructions); - Ok(instructions) - }, - )?; - - let export_function_index = (wit_resolver.interfaces.exports.len() - 1) as u32; - instructions.push(Instruction::CallCore { - function_index: export_function_index, - }); - - instructions.extend(match &self.signature.output_type { - Some(output_type) => output_type.generate_instructions_for_output_type(wit_resolver)?, - None => vec![], - }); - - let adapter = Adapter { - function_type: adapter_idx, - instructions, + function_type: function_type_id, }; + let export_function_id = wit_resolver.insert_export_type(export_type); - wit_resolver.interfaces.adapters.push(adapter); + let adapter_instructions = generate_export_adapter_instructions( + arguments, + output_type, + wit_resolver, + export_function_id, + )?; - let implementation = wasmer_wit::ast::Implementation { - core_function_type: export_idx, - adapter_function_type: adapter_idx, + let adapter = crate::AstAdapter { + function_type: function_type_id, + instructions: adapter_instructions, }; - wit_resolver.interfaces.implementations.push(implementation); + let adapter_id = wit_resolver.insert_adapter(adapter); + + let implementation = crate::AstImplementation { + core_function_id: export_function_id, + adapter_function_id: adapter_id, + }; + wit_resolver.insert_implementation(implementation); Ok(()) } } +fn generate_export_adapter_instructions( + arguments: &[(String, ParsedType)], + output_type: &Option, + wit_resolver: &mut WITResolver<'_>, + export_function_id: u32, +) -> Result> { + let mut instructions = arguments.iter().enumerate().try_fold::<_, _, Result<_>>( + Vec::with_capacity(arguments.len()), + |mut instructions, (arg_id, (_, input_type))| { + let mut new_instructions = + input_type.generate_instructions_for_input_type(arg_id as _, wit_resolver)?; + + instructions.append(&mut new_instructions); + Ok(instructions) + }, + )?; + + instructions.push(Instruction::CallCore { + function_index: export_function_id, + }); + + instructions.extend(match output_type { + Some(output_type) => output_type.generate_instructions_for_output_type(wit_resolver)?, + None => vec![], + }); + + Ok(instructions) +} + /// Generate WIT instructions for a function. trait FnInstructionGenerator { fn generate_instructions_for_input_type<'a>( diff --git a/crates/wit-generator/src/instructions_generator/foreign_mod_instructions.rs b/crates/wit-generator/src/instructions_generator/foreign_mod_instructions.rs index 1d0f405e..d574f518 100644 --- a/crates/wit-generator/src/instructions_generator/foreign_mod_instructions.rs +++ b/crates/wit-generator/src/instructions_generator/foreign_mod_instructions.rs @@ -14,25 +14,22 @@ * limitations under the License. */ +use super::add_function_type; use super::WITGenerator; use super::WITResolver; use super::utils::ptype_to_itype_checked; +use crate::*; use crate::default_export_api_config::*; -use crate::Result; use fluence_sdk_wit::AstExternModItem; use fluence_sdk_wit::AstExternFnItem; use fluence_sdk_wit::ParsedType; -use wasmer_wit::ast::FunctionArg as IFunctionArg; use wasmer_wit::interpreter::Instruction; -use crate::instructions_generator::utils::wtype_to_itype; - -use std::rc::Rc; const HOST_NAMESPACE_NAME: &str = "host"; impl WITGenerator for AstExternModItem { - fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()> { + fn generate_wit<'ast_type, 'resolver>(&'ast_type self, wit_resolver: &'resolver mut WITResolver<'ast_type>) -> Result<()> { // host imports should be left as is if self.namespace == HOST_NAMESPACE_NAME { return Ok(()); @@ -51,86 +48,51 @@ fn generate_wit_for_import<'a>( namespace: &'a str, wit_resolver: &mut WITResolver<'a>, ) -> Result<()> { - use wasmer_wit::ast::Type; - use wasmer_wit::ast::Adapter; + let arguments = &import.signature.arguments; + let output_type = &import.signature.output_type; - let arguments = import - .signature - .arguments - .iter() - .map(|(arg_name, arg_type)| -> Result { - Ok(IFunctionArg { - name: arg_name.clone(), - ty: ptype_to_itype_checked(arg_type, wit_resolver)?, - }) - }) - .collect::>>()?; - let arguments = Rc::new(arguments); - - let output_types = match import.signature.output_type { - Some(ref output_type) => vec![ptype_to_itype_checked(output_type, wit_resolver)?], - None => vec![], - }; - let output_types = Rc::new(output_types); - - let interfaces = &mut wit_resolver.interfaces; - interfaces.types.push(Type::Function { - arguments, - output_types, - }); - - let raw_inputs = import - .signature - .arguments - .iter() - .map(to_raw_input_types) - .flatten() - .collect::>(); - let raw_inputs = Rc::new(raw_inputs); - - let raw_outputs = match import.signature.output_type { - Some(ref output_type) => to_raw_output_type(output_type) - .iter() - .map(wtype_to_itype) - .collect(), - None => vec![], - }; - let raw_outputs = Rc::new(raw_outputs); - - interfaces.types.push(Type::Function { - arguments: raw_inputs.clone(), - output_types: raw_outputs.clone(), - }); - - interfaces.types.push(Type::Function { - arguments: raw_inputs, - output_types: raw_outputs, - }); - - let adapter_idx = (interfaces.types.len() - 2) as u32; - let import_idx = (interfaces.types.len() - 3) as u32; - let raw_import_idx = (interfaces.types.len() - 1) as u32; + let function_type_id = add_function_type(arguments, output_type, wit_resolver)?; let link_name = match &import.link_name { Some(link_name) => link_name, None => &import.signature.name, }; - - interfaces.imports.push(wasmer_wit::ast::Import { - namespace: &namespace, + let import_type = AstImport { name: link_name, - function_type: import_idx, - }); + namespace, + function_type: function_type_id, + }; + let import_function_id = wit_resolver.insert_import_type(import_type); - interfaces.imports.push(wasmer_wit::ast::Import { - namespace: &namespace, - name: link_name, - function_type: raw_import_idx, - }); + let adapter_instructions = generate_import_adapter_instructions( + arguments, + output_type, + wit_resolver, + import_function_id, + )?; - let mut instructions = import - .signature - .arguments + let adapter = crate::AstAdapter { + function_type: function_type_id, + instructions: adapter_instructions, + }; + let adapter_id = wit_resolver.insert_adapter(adapter); + + let implementation = crate::AstImplementation { + core_function_id: import_function_id, + adapter_function_id: adapter_id, + }; + wit_resolver.insert_implementation(implementation); + + Ok(()) +} + +fn generate_import_adapter_instructions( + arguments: &[(String, ParsedType)], + output_type: &Option, + wit_resolver: &mut WITResolver<'_>, + import_function_id: u32, +) -> Result> { + let mut instructions = arguments .iter() .try_fold::<_, _, Result<_>>( (0, Vec::new()), @@ -144,32 +106,16 @@ fn generate_wit_for_import<'a>( )? .1; - // TODO: refactor - let import_function_index = (wit_resolver.interfaces.exports.len() - + wit_resolver.interfaces.imports.len() / 2 - - 1) as u32; instructions.push(Instruction::CallCore { - function_index: import_function_index, + function_index: import_function_id, }); - instructions.extend(match &import.signature.output_type { + instructions.extend(match output_type { Some(output_type) => output_type.generate_instructions_for_output_type(wit_resolver)?, None => vec![], }); - let adapter = Adapter { - function_type: adapter_idx, - instructions, - }; - wit_resolver.interfaces.adapters.push(adapter); - - let implementation = wasmer_wit::ast::Implementation { - core_function_type: raw_import_idx, - adapter_function_type: adapter_idx, - }; - wit_resolver.interfaces.implementations.push(implementation); - - Ok(()) + Ok(instructions) } /// Generate WIT instructions for a foreign mod. @@ -277,60 +223,3 @@ impl ForeignModInstructionGenerator for ParsedType { Ok(instructions) } } - -use fluence_sdk_wit::RustType; -use wasmer_wit::types::InterfaceType as IType; - -pub fn to_raw_input_types(arg: &(String, ParsedType)) -> Vec { - match arg.1 { - ParsedType::Boolean - | ParsedType::I8 - | ParsedType::I16 - | ParsedType::I32 - | ParsedType::U8 - | ParsedType::U16 - | ParsedType::U32 - | ParsedType::Record(_) => vec![IFunctionArg { - name: arg.0.clone(), - ty: IType::I32, - }], - ParsedType::I64 | ParsedType::U64 => vec![IFunctionArg { - name: arg.0.clone(), - ty: IType::I64, - }], - ParsedType::F32 => vec![IFunctionArg { - name: arg.0.clone(), - ty: IType::F32, - }], - ParsedType::F64 => vec![IFunctionArg { - name: arg.0.clone(), - ty: IType::F64, - }], - ParsedType::Utf8String | ParsedType::Vector(_) => vec![ - IFunctionArg { - name: format!("{}_ptr", arg.0), - ty: IType::I32, - }, - IFunctionArg { - name: format!("{}_ptr", arg.0), - ty: IType::I32, - }, - ], - } -} - -pub fn to_raw_output_type(ty: &ParsedType) -> Vec { - match ty { - ParsedType::Boolean - | ParsedType::I8 - | ParsedType::I16 - | ParsedType::I32 - | ParsedType::U8 - | ParsedType::U16 - | ParsedType::U32 => vec![RustType::I32], - ParsedType::I64 | ParsedType::U64 => vec![RustType::I64], - ParsedType::F32 => vec![RustType::F32], - ParsedType::F64 => vec![RustType::F64], - ParsedType::Utf8String | ParsedType::Vector(_) | ParsedType::Record(_) => vec![], - } -} diff --git a/crates/wit-generator/src/instructions_generator/record_instructions.rs b/crates/wit-generator/src/instructions_generator/record_instructions.rs index 76217dc4..18f0c250 100644 --- a/crates/wit-generator/src/instructions_generator/record_instructions.rs +++ b/crates/wit-generator/src/instructions_generator/record_instructions.rs @@ -25,13 +25,15 @@ use wasmer_wit::types::RecordType; use wasmer_wit::vec1::Vec1; impl WITGenerator for AstRecordItem { - fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()> { + fn generate_wit<'ast_type, 'resolver>(&'ast_type self, wit_resolver: &'resolver mut WITResolver<'ast_type>) -> Result<()> { + use super::utils::ptype_to_itype_unchecked; + let fields = self .fields .iter() .map(|field| IRecordFieldType { name: field.name.clone().unwrap_or_default(), - ty: super::utils::ptype_to_itype_unchecked(&field.ty, wit_resolver), + ty: ptype_to_itype_unchecked(&field.ty, wit_resolver), }) .collect::>(); diff --git a/crates/wit-generator/src/instructions_generator/utils.rs b/crates/wit-generator/src/instructions_generator/utils.rs index 10863a27..2c8681bc 100644 --- a/crates/wit-generator/src/instructions_generator/utils.rs +++ b/crates/wit-generator/src/instructions_generator/utils.rs @@ -14,12 +14,13 @@ * limitations under the License. */ -use super::IType; +use crate::IType; +use crate::IFunctionArg; +use crate::IFunctionType; use crate::instructions_generator::WITResolver; use crate::Result; use fluence_sdk_wit::ParsedType; -use fluence_sdk_wit::RustType; // return error if there is no record with such name pub(crate) fn ptype_to_itype_checked( @@ -78,17 +79,30 @@ pub(crate) fn ptype_to_itype_unchecked( } } -pub(crate) fn wtype_to_itype(pty: &RustType) -> IType { - match pty { - RustType::I8 => IType::S8, - RustType::I16 => IType::S16, - RustType::I32 => IType::S32, - RustType::I64 => IType::S64, - RustType::U8 => IType::U8, - RustType::U16 => IType::U16, - RustType::U32 => IType::U32, - RustType::U64 => IType::U64, - RustType::F32 => IType::F32, - RustType::F64 => IType::F64, - } +pub(crate) fn add_function_type( + arguments: &Vec<(String, ParsedType)>, + output_type: &Option, + wit_resolver: &mut WITResolver<'_>, +) -> Result { + let arguments = arguments + .iter() + .map(|(arg_name, arg_type)| -> Result { + Ok(IFunctionArg { + name: arg_name.clone(), + ty: ptype_to_itype_checked(&arg_type, wit_resolver)?, + }) + }) + .collect::>>()?; + + let output_types = match output_type { + Some(output_type) => vec![ptype_to_itype_checked(output_type, wit_resolver)?], + None => vec![], + }; + + let function_type = IFunctionType { + arguments, + output_types, + }; + + Ok(wit_resolver.insert_function_type(function_type)) } diff --git a/crates/wit-generator/src/interface_generator.rs b/crates/wit-generator/src/interface_generator.rs index 8dd96082..fbc1ab01 100644 --- a/crates/wit-generator/src/interface_generator.rs +++ b/crates/wit-generator/src/interface_generator.rs @@ -20,9 +20,6 @@ use crate::instructions_generator::WITGenerator; use crate::instructions_generator::WITResolver; use crate::Result; -pub use fluence_sdk_wit::FCEAst; -use wasmer_wit::ast::Interfaces; - /// Parse generated by rust-sdk AST types, generate instructions and embed them to Wasm file. pub fn embed_wit(path: std::path::PathBuf) -> Result<()> { let wasm_module = walrus::ModuleConfig::new() @@ -30,9 +27,12 @@ pub fn embed_wit(path: std::path::PathBuf) -> Result<()> { .map_err(|e| WITGeneratorError::IOError(format!("{:?} can't be parsed: {:?}", path, e)))?; let module_ast = wasm_ast_extractor(&wasm_module)?; - let interfaces = generate_interfaces(&module_ast)?; + let mut wit_resolver = WITResolver::default(); + generate_interfaces(&module_ast, &mut wit_resolver)?; let wasm_module = fce_wit_parser::delete_wit_section(wasm_module); + + let interfaces = wit_resolver.finalize(); let mut wasm_module = fce_wit_parser::embed_wit(wasm_module, &interfaces); wasm_module.emit_wasm_file(path).map_err(|e| { @@ -55,13 +55,15 @@ fn wasm_ast_extractor(wasm_module: &walrus::Module) -> Result { let mut extern_mods: Vec = Vec::new(); // consider only sections name of that starts with GENERATED_SECTION_PREFIX - for custom_module in wasm_module.customs.iter().filter(|(_, section)| { + let custom_sections = wasm_module.customs.iter().filter(|(_, section)| { section .name() .starts_with(fluence_sdk_wit::GENERATED_SECTION_PREFIX) - }) { + }); + + for custom_section in custom_sections { let default_ids = walrus::IdsToIndices::default(); - let raw_data = custom_module.1.data(&default_ids); + let raw_data = custom_section.1.data(&default_ids); let decoded_json: FCEAst = serde_json::from_slice(&raw_data)?; match decoded_json { FCEAst::Record(record) => records.push(record), @@ -77,77 +79,33 @@ fn wasm_ast_extractor(wasm_module: &walrus::Module) -> Result { }) } -fn generate_interfaces(module_ast: &ModuleAST) -> Result> { - let mut wit_resolver = WITResolver::default(); - generate_default_export_api(&mut wit_resolver.interfaces); +fn generate_interfaces<'ast, 'wit_resolver>( + module_ast: &'ast ModuleAST, + wit_resolver: &'wit_resolver mut WITResolver<'ast>, +) -> Result<()> { + generate_default_export_api(wit_resolver); for record in &module_ast.records { - record.generate_wit(&mut wit_resolver)?; + record.generate_wit(wit_resolver)?; } - validate_records(&wit_resolver)?; + wit_resolver.validate_records()?; for function in &module_ast.functions { - function.generate_wit(&mut wit_resolver)?; + function.generate_wit(wit_resolver)?; } for extern_mod in &module_ast.extern_mods { - extern_mod.generate_wit(&mut wit_resolver)?; - } - - Ok(wit_resolver.interfaces) -} - -fn generate_default_export_api(interfaces: &mut Interfaces<'_>) { - // TODO: the order is matter - ALLOCATE_FUNC.update_interfaces(interfaces); - DEALLOCATE_FUNC.update_interfaces(interfaces); - GET_RESULT_SIZE_FUNC.update_interfaces(interfaces); - GET_RESULT_PTR_FUNC.update_interfaces(interfaces); - SET_RESULT_SIZE_FUNC.update_interfaces(interfaces); - SET_RESULT_PTR_FUNC.update_interfaces(interfaces); -} - -fn validate_records(wit_resolver: &WITResolver<'_>) -> Result<()> { - const TYPE_RESOLVE_RECURSION_LIMIT: u32 = 1024; - - fn validate_record_type( - record_type: &wasmer_wit::types::RecordType, - recursion_level: u32, - wit_resolver: &WITResolver<'_>, - ) -> Result<()> { - if recursion_level >= TYPE_RESOLVE_RECURSION_LIMIT { - return Err(WITGeneratorError::CorruptedRecord(String::from( - "too many inner structures level", - ))); - } - - for field in record_type.fields.iter() { - match &field.ty { - wasmer_wit::types::InterfaceType::Record(record_type_id) => { - let inner_record_type = wit_resolver.get_record_type(*record_type_id)?; - validate_record_type(&inner_record_type, recursion_level + 1, wit_resolver)?; - } - _ => continue, - } - } - - Ok(()) - } - - if wit_resolver.unresolved_types_count() != 0 { - return Err(WITGeneratorError::CorruptedRecord(format!( - "{} types unresolved", - wit_resolver.unresolved_types_count() - ))); - } - - for ty in wit_resolver.interfaces.types.iter() { - let record_type = match ty { - wasmer_wit::ast::Type::Record(ty) => ty, - _ => continue, - }; - - validate_record_type(record_type, 0, wit_resolver)?; + extern_mod.generate_wit(wit_resolver)?; } Ok(()) } + +fn generate_default_export_api(wit_resolver: &mut WITResolver<'_>) { + // TODO: the order is matter + wit_resolver.insert_default_api(&ALLOCATE_FUNC); + wit_resolver.insert_default_api(&DEALLOCATE_FUNC); + wit_resolver.insert_default_api(&GET_RESULT_SIZE_FUNC); + wit_resolver.insert_default_api(&GET_RESULT_PTR_FUNC); + wit_resolver.insert_default_api(&SET_RESULT_SIZE_FUNC); + wit_resolver.insert_default_api(&SET_RESULT_PTR_FUNC); +} diff --git a/crates/wit-generator/src/lib.rs b/crates/wit-generator/src/lib.rs index ea9ac39c..a3849d9d 100644 --- a/crates/wit-generator/src/lib.rs +++ b/crates/wit-generator/src/lib.rs @@ -34,3 +34,14 @@ pub use interface_generator::embed_wit; pub use errors::WITGeneratorError; pub(crate) type Result = std::result::Result; + +pub(crate) use wasmer_wit::ast::Interfaces; +pub(crate) use wasmer_wit::ast::Adapter as AstAdapter; +pub(crate) use wasmer_wit::ast::Type as AstType; +pub(crate) use wasmer_wit::ast::Export as AstExport; +pub(crate) use wasmer_wit::ast::Import as AstImport; +pub(crate) use wasmer_wit::ast::Implementation as AstImplementation; +pub(crate) use wasmer_wit::types::InterfaceType as IType; +pub(crate) use wasmer_wit::types::RecordType as IRecordType; +pub(crate) use wasmer_wit::types::FunctionArg as IFunctionArg; +pub(crate) use wasmer_wit::types::FunctionType as IFunctionType; diff --git a/crates/wit-interfaces/Cargo.toml b/crates/wit-interfaces/Cargo.toml index 15b67033..545eb521 100644 --- a/crates/wit-interfaces/Cargo.toml +++ b/crates/wit-interfaces/Cargo.toml @@ -11,5 +11,5 @@ name = "fce_wit_interfaces" path = "src/lib.rs" [dependencies] -wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.15" } +wasmer-wit = { package = "wasmer-interface-types-fl", git = "https://github.com/fluencelabs/interface-types", branch = "impl_refactoring" } multimap = "0.8.1" diff --git a/crates/wit-interfaces/src/fce_wit_interfaces.rs b/crates/wit-interfaces/src/fce_wit_interfaces.rs index b0ff3e71..ebdf2122 100644 --- a/crates/wit-interfaces/src/fce_wit_interfaces.rs +++ b/crates/wit-interfaces/src/fce_wit_interfaces.rs @@ -77,8 +77,8 @@ impl<'a> FCEWITInterfaces<'a> { .iter() .map(|implementation| { ( - implementation.adapter_function_type, - implementation.core_function_type, + implementation.adapter_function_id, + implementation.core_function_id, ) }) .collect::>(); @@ -88,8 +88,8 @@ impl<'a> FCEWITInterfaces<'a> { .iter() .map(|implementation| { ( - implementation.core_function_type, - implementation.adapter_function_type, + implementation.core_function_id, + implementation.adapter_function_id, ) }) .collect::>(); @@ -189,15 +189,15 @@ impl<'a> FCEWITInterfaces<'a> { pub fn adapter_types_by_core_type( &self, - core_function_type: CoreFunctionType, + core_function_id: CoreFunctionType, ) -> Option<&Vec> { - self.core_type_to_adapter.get_vec(&core_function_type) + self.core_type_to_adapter.get_vec(&core_function_id) } pub fn core_types_by_adapter_type( &self, - adapter_function_type: AdapterFunctionType, + adapter_function_id: AdapterFunctionType, ) -> Option<&Vec> { - self.adapter_type_to_core.get_vec(&adapter_function_type) + self.adapter_type_to_core.get_vec(&adapter_function_id) } } diff --git a/crates/wit-parser/Cargo.toml b/crates/wit-parser/Cargo.toml index dd448c31..87b8f2e9 100644 --- a/crates/wit-parser/Cargo.toml +++ b/crates/wit-parser/Cargo.toml @@ -16,4 +16,4 @@ fce-wit-interfaces = { path = "../wit-interfaces", version = "0.1.7" } anyhow = "1.0.31" walrus = "0.17.0" wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0"} -wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.15" } +wasmer-wit = { package = "wasmer-interface-types-fl", git = "https://github.com/fluencelabs/interface-types", branch = "impl_refactoring" } diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 4a0f8af5..03a02bb5 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -18,7 +18,7 @@ fce-utils = { path = "../crates/utils", version = "0.1.0" } wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" } # dynamicfunc-fat-closures allows using state inside DynamicFunc wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0", features = ["dynamicfunc-fat-closures"] } -wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.15" } +wasmer-wit = { package = "wasmer-interface-types-fl", git = "https://github.com/fluencelabs/interface-types", branch = "impl_refactoring" } wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.0" } multimap = "0.8.1" diff --git a/engine/src/module/fce_module.rs b/engine/src/module/fce_module.rs index a21c5eaa..d88f8501 100644 --- a/engine/src/module/fce_module.rs +++ b/engine/src/module/fce_module.rs @@ -249,24 +249,24 @@ impl FCEModule { use fce_wit_interfaces::WITAstType; wit.implementations() - .filter_map(|(adapter_function_type, core_function_type)| { - match wit.exports_by_type(*core_function_type) { + .filter_map(|(adapter_function_id, core_function_id)| { + match wit.exports_by_type(*core_function_id) { Some(export_function_name) => { - Some((adapter_function_type, export_function_name)) + Some((adapter_function_id, export_function_name)) } // pass functions that aren't export None => None, } }) - .map(|(adapter_function_type, export_function_names)| { + .map(|(adapter_function_id, export_function_names)| { export_function_names .iter() - .map(move |export_function_name| (*adapter_function_type, export_function_name)) + .map(move |export_function_name| (*adapter_function_id, export_function_name)) }) .flatten() - .map(|(adapter_function_type, export_function_name)| { - let adapter_instructions = wit.adapter_by_type_r(adapter_function_type)?; - let wit_type = wit.type_by_idx_r(adapter_function_type)?; + .map(|(adapter_function_id, export_function_name)| { + let adapter_instructions = wit.adapter_by_type_r(adapter_function_id)?; + let wit_type = wit.type_by_idx_r(adapter_function_id)?; match wit_type { WITAstType::Function { @@ -291,7 +291,7 @@ impl FCEModule { } _ => Err(FCEError::IncorrectWIT(format!( "type with idx = {} isn't a function type", - adapter_function_type + adapter_function_id ))), } }) @@ -373,22 +373,22 @@ impl FCEModule { let wit_import_funcs = wit .implementations() - .filter_map(|(adapter_function_type, core_function_type)| { - match wit.imports_by_type(*core_function_type) { - Some(import) => Some((adapter_function_type, import)), + .filter_map(|(adapter_function_id, core_function_id)| { + match wit.imports_by_type(*core_function_id) { + Some(import) => Some((adapter_function_id, import)), // skip functions that aren't import None => None, } }) - .map(|(adapter_function_type, import_function_names)| { + .map(|(adapter_function_id, import_function_names)| { import_function_names .iter() - .map(move |import_function_name| (*adapter_function_type, import_function_name)) + .map(move |import_function_name| (*adapter_function_id, import_function_name)) }) .flatten() - .map(|(adapter_function_type, (import_namespace, import_name))| { - let adapter_instructions = wit.adapter_by_type_r(adapter_function_type)?; - let wit_type = wit.type_by_idx_r(adapter_function_type)?; + .map(|(adapter_function_id, (import_namespace, import_name))| { + let adapter_instructions = wit.adapter_by_type_r(adapter_function_id)?; + let wit_type = wit.type_by_idx_r(adapter_function_id)?; match wit_type { WITAstType::Function { @@ -415,7 +415,7 @@ impl FCEModule { } _ => Err(FCEError::IncorrectWIT(format!( "type with idx = {} isn't a function type", - adapter_function_type + adapter_function_id ))), } }) diff --git a/engine/src/module/wit_instance.rs b/engine/src/module/wit_instance.rs index a09dd147..5de6c7fd 100644 --- a/engine/src/module/wit_instance.rs +++ b/engine/src/module/wit_instance.rs @@ -79,7 +79,7 @@ impl WITInstance { let export_func = module_exports.get(export.name)?; unsafe { // TODO: refactor this with new Wasmer API when it is ready - // here it is safe because dyn func is never lives WITInstance + // here it is safe because dyn func is never leaves WITInstance let export_func = std::mem::transmute::, DynFunc<'static>>(export_func); Ok(( diff --git a/fluence-faas/Cargo.toml b/fluence-faas/Cargo.toml index 750809ef..96058802 100644 --- a/fluence-faas/Cargo.toml +++ b/fluence-faas/Cargo.toml @@ -15,7 +15,7 @@ wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" } # dynamicfunc-fat-closures allows using state inside DynamicFunc wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0", features = ["dynamicfunc-fat-closures"] } wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.0" } -wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.15" } +wasmer-wit = { package = "wasmer-interface-types-fl", git = "https://github.com/fluencelabs/interface-types", branch = "impl_refactoring" } toml = "0.5.6" serde = { version = "1.0.111", features = ["derive"] }