From c51b5982d6797d4291884c820eb5614560a05297 Mon Sep 17 00:00:00 2001 From: Mike Voronov Date: Wed, 19 May 2021 18:58:24 +0300 Subject: [PATCH] Fix IT generation (#87) --- .circleci/config.yml | 2 +- Cargo.lock | 20 +- crates/it-generator/Cargo.toml | 4 +- .../src/instructions_generator.rs | 71 ++++ .../instructions_generator/fn_instructions.rs | 254 +++---------- .../fn_instructions/args_it_generator.rs | 82 +++++ .../output_type_it_generator.rs | 82 +++++ .../foreign_mod_instructions.rs | 280 ++++----------- .../args_it_generator.rs | 86 +++++ .../output_type_it_generator.rs | 85 +++++ .../record_instructions.rs | 8 +- .../src/instructions_generator/tests.rs | 334 ++++++++++++++++++ .../src/instructions_generator/utils.rs | 38 ++ crates/module-info-parser/Cargo.toml | 2 +- examples/call_parameters/Cargo.toml | 2 +- examples/greeting/Cargo.toml | 2 +- examples/records/effector/Cargo.toml | 2 +- examples/records/pure/Cargo.toml | 2 +- examples/records/test-record/Cargo.toml | 2 +- examples/sqlite/Cargo.toml | 2 +- fluence-faas/Cargo.toml | 2 +- .../wasm_tests/arrays_passing/Cargo.toml | 2 +- .../wasm_tests/records_passing/Cargo.toml | 2 +- tools/cli/Cargo.toml | 2 +- tools/repl/Cargo.toml | 2 +- 25 files changed, 938 insertions(+), 432 deletions(-) create mode 100644 crates/it-generator/src/instructions_generator/fn_instructions/args_it_generator.rs create mode 100644 crates/it-generator/src/instructions_generator/fn_instructions/output_type_it_generator.rs create mode 100644 crates/it-generator/src/instructions_generator/foreign_mod_instructions/args_it_generator.rs create mode 100644 crates/it-generator/src/instructions_generator/foreign_mod_instructions/output_type_it_generator.rs create mode 100644 crates/it-generator/src/instructions_generator/tests.rs diff --git a/.circleci/config.yml b/.circleci/config.yml index 644af746..59d03cad 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -29,7 +29,7 @@ jobs: (cd ./examples; ./build.sh) (cd ./fluence-faas/tests/wasm_tests; ./build.sh) - cargo test --release -v --all-features -p marine-runtime -p fluence-faas -p fluence-app-service -p marine -p mrepl + cargo test --release -v --all-features -p marine-it-generator -p marine-runtime -p fluence-faas -p fluence-app-service -p marine -p mrepl cargo clippy -v -p marine-runtime -p fluence-faas -p fluence-app-service -p marine -p mrepl - save_cache: diff --git a/Cargo.lock b/Cargo.lock index 08408092..408641ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -700,9 +700,9 @@ dependencies = [ [[package]] name = "fluence" -version = "0.6.5" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd1f159a4da6aef89e8e4a0bf061a8031d669d03d9928266942581a52df03f56" +checksum = "88b09e1cd11a51ba4d169db347d009fe41ece2714eef4d5df720343733a1d5a6" dependencies = [ "fluence-sdk-main", "marine-macro", @@ -805,9 +805,9 @@ dependencies = [ [[package]] name = "fluence-sdk-main" -version = "0.6.4" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a5d1ca20ada064379d959a9a82f9c006e4d9388533cf06010186fef6dd583b" +checksum = "68d93cde99e1494e11755a39b93863333397245c9959c774fe3bebd9e4143879" dependencies = [ "log", "marine-macro", @@ -1549,18 +1549,18 @@ dependencies = [ [[package]] name = "marine-macro" -version = "0.6.4" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1652b6ac1bbdde9a66c16c8a2f9cd34d005a1f1b211a538c5b28764faa6ef4" +checksum = "f63d927851847cc3dd9e3bd0f10bdeb313859d4822d5b5f650d9d34d461ed419" dependencies = [ "marine-macro-impl", ] [[package]] name = "marine-macro-impl" -version = "0.6.4" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fee75eaf1a97ee9fe2d382c0537c06a79e5d7ab9d81bda6cb263fb8fd1a15a" +checksum = "fb504be4a90e229ab453c7369cc8a9063acec819f3397802eea719cd0a232be1" dependencies = [ "proc-macro2", "quote", @@ -1699,9 +1699,9 @@ dependencies = [ [[package]] name = "marine-timestamp-macro" -version = "0.6.2" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6feb612ccd3fd39ec3d50c9a1a96885e1fd32d36a92cf674a0fbe6f7c452613" +checksum = "5994c7db5567d21609f2a2e5a40d9d4564f86c17ca35b2d77007152619b9d7fc" dependencies = [ "chrono", "quote", diff --git a/crates/it-generator/Cargo.toml b/crates/it-generator/Cargo.toml index 375e4611..d55e889d 100644 --- a/crates/it-generator/Cargo.toml +++ b/crates/it-generator/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "marine-it-generator" description = "Fluence Marine interface types generator" -version = "0.5.1" +version = "0.5.2" authors = ["Fluence Labs"] license = "Apache-2.0" edition = "2018" @@ -12,7 +12,7 @@ path = "src/lib.rs" [dependencies] marine-it-parser = { path = "../it-parser", version = "0.6.0"} -marine-macro-impl = "0.6.4" +marine-macro-impl = "0.6.9" wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.0" } it-lilo = "0.1.0" diff --git a/crates/it-generator/src/instructions_generator.rs b/crates/it-generator/src/instructions_generator.rs index 90857e5e..a9613130 100644 --- a/crates/it-generator/src/instructions_generator.rs +++ b/crates/it-generator/src/instructions_generator.rs @@ -17,6 +17,8 @@ mod fn_instructions; mod foreign_mod_instructions; mod record_instructions; +#[cfg(test)] +mod tests; mod utils; use crate::Result; @@ -102,6 +104,75 @@ impl<'a> ITResolver<'a> { } } +impl<'a> ITResolver<'a> { + pub(crate) fn add_adapter( + &mut self, + function_type: u32, + instructions: Vec, + ) { + let adapter = wasmer_it::ast::Adapter { + function_type, + instructions, + }; + + self.interfaces.adapters.push(adapter); + } + + pub(crate) fn add_implementation( + &mut self, + core_function_type: u32, + adapter_function_type: u32, + ) { + let implementation = wasmer_it::ast::Implementation { + core_function_type, + adapter_function_type, + }; + + self.interfaces.implementations.push(implementation); + } + + pub(crate) fn add_export(&mut self, name: &'a str, function_type: u32) { + let export = wasmer_it::ast::Export { + name, + function_type, + }; + + self.interfaces.exports.push(export); + } + + pub(crate) fn add_import(&mut self, namespace: &'a str, name: &'a str, function_type: u32) { + let import = wasmer_it::ast::Import { + namespace, + name, + function_type, + }; + + self.interfaces.imports.push(import); + } + + pub(crate) fn add_fn_type( + &mut self, + arguments: Rc>, + output_types: Rc>, + ) { + let fn_type = wasmer_it::ast::Type::Function { + arguments, + output_types, + }; + + self.interfaces.types.push(fn_type); + } + + pub(crate) fn add_record_type( + &mut self, + name: String, + fields: wasmer_it::NEVec, + ) { + let record = wasmer_it::IRecordType { name, fields }; + self.insert_record_type(record); + } +} + pub(crate) trait ITGenerator { fn generate_it<'a>(&'a self, it_resolver: &mut ITResolver<'a>) -> Result<()>; } diff --git a/crates/it-generator/src/instructions_generator/fn_instructions.rs b/crates/it-generator/src/instructions_generator/fn_instructions.rs index 2accf7d7..edc8e6bb 100644 --- a/crates/it-generator/src/instructions_generator/fn_instructions.rs +++ b/crates/it-generator/src/instructions_generator/fn_instructions.rs @@ -14,225 +14,87 @@ * limitations under the License. */ +mod args_it_generator; +mod output_type_it_generator; + use super::ITGenerator; use super::ITResolver; -use super::utils::ptype_to_itype_checked; -use crate::default_export_api_config::*; +use super::utils::*; use crate::Result; +use crate::default_export_api_config::RELEASE_OBJECTS; use marine_macro_impl::FnType; -use marine_macro_impl::ParsedType; use wasmer_it::interpreter::Instruction; -use wasmer_it::ast::FunctionArg as IFunctionArg; -use wasmer_it::IType; - -use std::rc::Rc; impl ITGenerator for FnType { fn generate_it<'a>(&'a self, it_resolver: &mut ITResolver<'a>) -> Result<()> { - use wasmer_it::ast::Type; - use wasmer_it::ast::Adapter; + generate_it_types(self, it_resolver)?; + generate_instructions(self, it_resolver) + } +} - let arguments = self - .signature - .arguments - .iter() - .map(|arg| -> Result { - Ok(IFunctionArg { - name: arg.name.clone(), - ty: ptype_to_itype_checked(&arg.ty, it_resolver)?, - }) - }) - .collect::>>()?; +fn generate_it_types<'f>(fn_type: &'f FnType, it_resolver: &mut ITResolver<'f>) -> Result<()> { + let arguments = generate_it_args(&fn_type.signature, it_resolver)?; + let output_types = generate_it_output_type(&fn_type.signature, it_resolver)?; - let arguments = Rc::new(arguments); + it_resolver.add_fn_type(arguments.clone(), output_types.clone()); + // TODO: replace with Wasm types + it_resolver.add_fn_type(arguments, output_types); - let output_types = self - .signature - .output_types - .iter() - .map(|ty| ptype_to_itype_checked(ty, it_resolver)) - .collect::>>()?; - let output_types = Rc::new(output_types); + let export_idx = (it_resolver.interfaces.types.len() - 1) as u32; + it_resolver.add_export(&fn_type.signature.name, export_idx); - let interfaces = &mut it_resolver.interfaces; - interfaces.types.push(Type::Function { - arguments: arguments.clone(), - output_types: output_types.clone(), - }); + Ok(()) +} - // TODO: replace with Wasm types - interfaces.types.push(Type::Function { - arguments, - output_types, - }); +fn generate_instructions<'f>(fn_type: &'f FnType, it_resolver: &mut ITResolver<'f>) -> Result<()> { + use args_it_generator::ArgumentITGenerator; + use output_type_it_generator::OutputITGenerator; - let adapter_idx = (interfaces.types.len() - 2) as u32; - let export_idx = (interfaces.types.len() - 1) as u32; + let mut instructions = fn_type + .signature + .arguments + .iter() + .enumerate() + .try_fold::<_, _, Result<_>>(Vec::new(), |mut instructions, (arg_id, arg)| { + let new_instructions = arg + .ty + .generate_instructions_for_arg(arg_id as _, it_resolver)?; - interfaces.exports.push(wasmer_it::ast::Export { - name: &self.signature.name, - function_type: export_idx, - }); + instructions.extend(new_instructions); + Ok(instructions) + })?; - let mut instructions = self - .signature - .arguments - .iter() - .enumerate() - .try_fold::<_, _, Result<_>>(Vec::new(), |mut instructions, (arg_id, arg)| { - let new_instructions = arg - .ty - .generate_instructions_for_input_type(arg_id as _, it_resolver)?; + let export_function_index = (it_resolver.interfaces.exports.len() - 1) as u32; + instructions.push(Instruction::CallCore { + function_index: export_function_index, + }); - instructions.extend(new_instructions); - Ok(instructions) - })?; + let mut should_generate_release = false; + let mut instructions = fn_type + .signature + .output_types + .iter() + .try_fold::<_, _, Result<_>>(instructions, |mut instructions, ty| { + let new_instructions = ty.generate_instructions_for_output_type(it_resolver)?; + instructions.extend(new_instructions); - let export_function_index = (it_resolver.interfaces.exports.len() - 1) as u32; + should_generate_release |= ty.is_complex_type(); + Ok(instructions) + })?; + + if should_generate_release { instructions.push(Instruction::CallCore { - function_index: export_function_index, + function_index: RELEASE_OBJECTS.id, }); - - let instructions = self - .signature - .output_types - .iter() - .try_fold::<_, _, Result<_>>(instructions, |mut instructions, ty| { - let new_instructions = ty.generate_instructions_for_output_type(it_resolver)?; - - instructions.extend(new_instructions); - Ok(instructions) - })?; - - let adapter = Adapter { - function_type: adapter_idx, - instructions, - }; - - it_resolver.interfaces.adapters.push(adapter); - - let implementation = wasmer_it::ast::Implementation { - core_function_type: export_idx, - adapter_function_type: adapter_idx, - }; - it_resolver.interfaces.implementations.push(implementation); - - Ok(()) - } -} - -/// Generate IT instructions for a function. -trait FnInstructionGenerator { - fn generate_instructions_for_input_type<'a>( - &self, - arg_id: u32, - it_resolver: &mut ITResolver<'a>, - ) -> Result>; - - fn generate_instructions_for_output_type<'a>( - &self, - it_resolver: &mut ITResolver<'a>, - ) -> Result>; -} - -impl FnInstructionGenerator for ParsedType { - #[rustfmt::skip] - fn generate_instructions_for_input_type<'a>(&self, index: u32, it_resolver: &mut ITResolver<'a>) -> Result> { - let instructions = match self { - ParsedType::Boolean(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromBool], - ParsedType::I8(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS8], - ParsedType::I16(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS16], - ParsedType::I32(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS32], - ParsedType::I64(_) => vec![Instruction::ArgumentGet { index }, Instruction::I64FromS64], - ParsedType::U8(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU8], - ParsedType::U16(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU16], - ParsedType::U32(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU32], - ParsedType::U64(_) => vec![Instruction::ArgumentGet { index }, Instruction::I64FromU64], - ParsedType::F32(_) => vec![Instruction::ArgumentGet { index }], - ParsedType::F64(_) => vec![Instruction::ArgumentGet { index }], - ParsedType::Utf8Str(_) | ParsedType::Utf8String(_) => { - let type_tag = it_lilo::utils::ser_type_size(&IType::U8) as i32; - vec![ - Instruction::ArgumentGet { index }, - Instruction::StringSize, - Instruction::PushI32 { value: type_tag }, - Instruction::CallCore { function_index: ALLOCATE_FUNC.id }, - Instruction::ArgumentGet { index }, - Instruction::StringLowerMemory, - ] - }, - ParsedType::Vector(value_type, _) => { - let value_type = ptype_to_itype_checked(value_type, it_resolver)?; - vec![ - Instruction::ArgumentGet { index }, - Instruction::ArrayLowerMemory { - value_type - }, - ] - }, - ParsedType::Record(record_name, _) => { - let record_type_id = it_resolver.get_record_type_id(record_name)? as u32; - - vec! [ - Instruction::ArgumentGet { index }, - Instruction::RecordLowerMemory { record_type_id }, - ] - }, - }; - - Ok(instructions) } - #[rustfmt::skip] - fn generate_instructions_for_output_type<'a>(&self, it_resolver: &mut ITResolver<'a>) -> Result> { - let instructions = match self { - ParsedType::Boolean(_) => vec![Instruction::BoolFromI32], - ParsedType::I8(_) => vec![Instruction::S8FromI32], - ParsedType::I16(_) => vec![Instruction::S16FromI32], - ParsedType::I32(_) => vec![Instruction::S32FromI32], - ParsedType::I64(_) => vec![Instruction::S64FromI64], - ParsedType::U8(_) => vec![Instruction::U8FromI32], - ParsedType::U16(_) => vec![Instruction::U16FromI32], - ParsedType::U32(_) => vec![Instruction::U32FromI32], - ParsedType::U64(_) => vec![Instruction::U64FromI64], - ParsedType::F32(_) => vec![], - ParsedType::F64(_) => vec![], - ParsedType::Utf8Str(_) | ParsedType::Utf8String(_) => vec![ - Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, - Instruction::CallCore { function_index: GET_RESULT_SIZE_FUNC.id }, - Instruction::StringLiftMemory, - Instruction::CallCore { function_index: RELEASE_OBJECTS.id }, - ], - ParsedType::Vector(value_type, _) => { - let value_type = ptype_to_itype_checked(value_type, it_resolver)?; - if let IType::U8 = value_type { - vec![ - Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, - Instruction::CallCore { function_index: GET_RESULT_SIZE_FUNC.id }, - Instruction::ByteArrayLiftMemory, - Instruction::CallCore { function_index: RELEASE_OBJECTS.id }, - ] - } else { - vec![ - Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, - Instruction::CallCore { function_index: GET_RESULT_SIZE_FUNC.id }, - Instruction::ArrayLiftMemory { value_type }, - Instruction::CallCore { function_index: RELEASE_OBJECTS.id }, - ] - } - }, - ParsedType::Record(record_name, _) => { - let record_type_id = it_resolver.get_record_type_id(record_name)? as u32; + let types_count = it_resolver.interfaces.types.len() as u32; + let adapter_idx = types_count - 2; + let export_idx = types_count - 1; - vec! [ - Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, - Instruction::RecordLiftMemory { record_type_id }, - Instruction::CallCore { function_index: RELEASE_OBJECTS.id }, - ] - }, - }; + it_resolver.add_adapter(adapter_idx, instructions); + it_resolver.add_implementation(export_idx, adapter_idx); - Ok(instructions) - } + Ok(()) } diff --git a/crates/it-generator/src/instructions_generator/fn_instructions/args_it_generator.rs b/crates/it-generator/src/instructions_generator/fn_instructions/args_it_generator.rs new file mode 100644 index 00000000..8065fe18 --- /dev/null +++ b/crates/it-generator/src/instructions_generator/fn_instructions/args_it_generator.rs @@ -0,0 +1,82 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::ITResolver; +use super::ptype_to_itype_checked; +use crate::default_export_api_config::*; +use crate::Result; + +use marine_macro_impl::ParsedType; +use wasmer_it::interpreter::Instruction; +use wasmer_it::IType; + +/// Generates IT instructions for a argument of an export function. +pub(super) trait ArgumentITGenerator { + fn generate_instructions_for_arg<'a>( + &self, + arg_id: u32, + it_resolver: &mut ITResolver<'a>, + ) -> Result>; +} + +impl ArgumentITGenerator for ParsedType { + #[rustfmt::skip] + fn generate_instructions_for_arg<'a>(&self, index: u32, it_resolver: &mut ITResolver<'a>) -> Result> { + let instructions = match self { + ParsedType::Boolean(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromBool], + ParsedType::I8(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS8], + ParsedType::I16(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS16], + ParsedType::I32(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS32], + ParsedType::I64(_) => vec![Instruction::ArgumentGet { index }, Instruction::I64FromS64], + ParsedType::U8(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU8], + ParsedType::U16(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU16], + ParsedType::U32(_) => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU32], + ParsedType::U64(_) => vec![Instruction::ArgumentGet { index }, Instruction::I64FromU64], + ParsedType::F32(_) => vec![Instruction::ArgumentGet { index }], + ParsedType::F64(_) => vec![Instruction::ArgumentGet { index }], + ParsedType::Utf8Str(_) | ParsedType::Utf8String(_) => { + let type_tag = it_lilo::utils::ser_type_size(&IType::U8) as i32; + vec![ + Instruction::ArgumentGet { index }, + Instruction::StringSize, + Instruction::PushI32 { value: type_tag }, + Instruction::CallCore { function_index: ALLOCATE_FUNC.id }, + Instruction::ArgumentGet { index }, + Instruction::StringLowerMemory, + ] + }, + ParsedType::Vector(value_type, _) => { + let value_type = ptype_to_itype_checked(value_type, it_resolver)?; + vec![ + Instruction::ArgumentGet { index }, + Instruction::ArrayLowerMemory { + value_type + }, + ] + }, + ParsedType::Record(record_name, _) => { + let record_type_id = it_resolver.get_record_type_id(record_name)? as u32; + + vec! [ + Instruction::ArgumentGet { index }, + Instruction::RecordLowerMemory { record_type_id }, + ] + }, + }; + + Ok(instructions) + } +} diff --git a/crates/it-generator/src/instructions_generator/fn_instructions/output_type_it_generator.rs b/crates/it-generator/src/instructions_generator/fn_instructions/output_type_it_generator.rs new file mode 100644 index 00000000..eca5b4b7 --- /dev/null +++ b/crates/it-generator/src/instructions_generator/fn_instructions/output_type_it_generator.rs @@ -0,0 +1,82 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::ITResolver; +use super::ptype_to_itype_checked; +use crate::default_export_api_config::*; +use crate::Result; + +use marine_macro_impl::ParsedType; +use wasmer_it::interpreter::Instruction; +use wasmer_it::IType; + +/// Generates IT instructions for a output type of an export function. +pub(super) trait OutputITGenerator { + fn generate_instructions_for_output_type<'a>( + &self, + it_resolver: &mut ITResolver<'a>, + ) -> Result>; +} + +impl OutputITGenerator for ParsedType { + #[rustfmt::skip] + fn generate_instructions_for_output_type<'a>(&self, it_resolver: &mut ITResolver<'a>) -> Result> { + let instructions = match self { + ParsedType::Boolean(_) => vec![Instruction::BoolFromI32], + ParsedType::I8(_) => vec![Instruction::S8FromI32], + ParsedType::I16(_) => vec![Instruction::S16FromI32], + ParsedType::I32(_) => vec![Instruction::S32FromI32], + ParsedType::I64(_) => vec![Instruction::S64FromI64], + ParsedType::U8(_) => vec![Instruction::U8FromI32], + ParsedType::U16(_) => vec![Instruction::U16FromI32], + ParsedType::U32(_) => vec![Instruction::U32FromI32], + ParsedType::U64(_) => vec![Instruction::U64FromI64], + ParsedType::F32(_) => vec![], + ParsedType::F64(_) => vec![], + ParsedType::Utf8Str(_) | ParsedType::Utf8String(_) => vec![ + Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, + Instruction::CallCore { function_index: GET_RESULT_SIZE_FUNC.id }, + Instruction::StringLiftMemory, + ], + ParsedType::Vector(value_type, _) => { + let value_type = ptype_to_itype_checked(value_type, it_resolver)?; + if let IType::U8 = value_type { + vec![ + Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, + Instruction::CallCore { function_index: GET_RESULT_SIZE_FUNC.id }, + Instruction::ByteArrayLiftMemory, + ] + } else { + vec![ + Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, + Instruction::CallCore { function_index: GET_RESULT_SIZE_FUNC.id }, + Instruction::ArrayLiftMemory { value_type }, + ] + } + }, + ParsedType::Record(record_name, _) => { + let record_type_id = it_resolver.get_record_type_id(record_name)? as u32; + + vec! [ + Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, + Instruction::RecordLiftMemory { record_type_id }, + ] + }, + }; + + Ok(instructions) + } +} diff --git a/crates/it-generator/src/instructions_generator/foreign_mod_instructions.rs b/crates/it-generator/src/instructions_generator/foreign_mod_instructions.rs index 01fdd599..418115c8 100644 --- a/crates/it-generator/src/instructions_generator/foreign_mod_instructions.rs +++ b/crates/it-generator/src/instructions_generator/foreign_mod_instructions.rs @@ -14,17 +14,21 @@ * limitations under the License. */ +mod args_it_generator; +mod output_type_it_generator; + use super::ITGenerator; use super::ITResolver; -use super::utils::ptype_to_itype_checked; +use super::utils::*; use crate::Result; -use crate::default_export_api_config::*; +use crate::default_export_api_config::RELEASE_OBJECTS; use crate::instructions_generator::utils::wtype_to_itype; use marine_macro_impl::ExternModType; use marine_macro_impl::ExternFnType; use marine_macro_impl::ParsedType; use marine_macro_impl::FnArgument; +use marine_macro_impl::FnSignature; use wasmer_it::ast::FunctionArg as IFunctionArg; use wasmer_it::interpreter::Instruction; use wasmer_it::IType; @@ -49,108 +53,76 @@ impl ITGenerator for ExternModType { } fn generate_it_for_import<'a>( - import: &'a ExternFnType, + fn_type: &'a ExternFnType, namespace: &'a str, it_resolver: &mut ITResolver<'a>, ) -> Result<()> { - use wasmer_it::ast::Type; - use wasmer_it::ast::Adapter; + generate_it_types(fn_type, namespace, it_resolver)?; + generate_it_instructions(fn_type, it_resolver) +} - let arguments = import - .signature - .arguments - .iter() - .map(|arg| -> Result { - Ok(IFunctionArg { - name: arg.name.clone(), - ty: ptype_to_itype_checked(&arg.ty, it_resolver)?, - }) - }) - .collect::>>()?; - let arguments = Rc::new(arguments); +fn generate_it_types<'f>( + fn_type: &'f ExternFnType, + namespace: &'f str, + it_resolver: &mut ITResolver<'f>, +) -> Result<()> { + let arguments = generate_it_args(&fn_type.signature, it_resolver)?; + let output_types = generate_it_output_type(&fn_type.signature, it_resolver)?; + it_resolver.add_fn_type(arguments, output_types); - let output_types = import - .signature - .output_types - .iter() - .map(|ty| ptype_to_itype_checked(ty, it_resolver)) - .collect::>>()?; - let output_types = Rc::new(output_types); + let raw_arguments = generate_raw_args(&fn_type.signature); + let raw_output_types = generate_raw_output_type(&fn_type.signature); + it_resolver.add_fn_type(raw_arguments.clone(), raw_output_types.clone()); + it_resolver.add_fn_type(raw_arguments, raw_output_types); - let interfaces = &mut it_resolver.interfaces; - interfaces.types.push(Type::Function { - arguments, - output_types, - }); + let types_count = it_resolver.interfaces.types.len() as u32; + let import_idx = types_count - 3; + let raw_import_idx = types_count - 1; - let raw_inputs = import - .signature - .arguments - .iter() - .map(to_raw_input_types) - .flatten() - .collect::>(); - let raw_inputs = Rc::new(raw_inputs); - - let raw_outputs = import - .signature - .output_types - .iter() - .map(|ty| { - to_raw_output_type(ty) - .iter() - .map(wtype_to_itype) - .collect::>() - }) - .flatten() - .collect::>(); - 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 link_name = match &import.link_name { + let link_name = match &fn_type.link_name { Some(link_name) => link_name, - None => &import.signature.name, + None => &fn_type.signature.name, }; - interfaces.imports.push(wasmer_it::ast::Import { - namespace: &namespace, - name: link_name, - function_type: import_idx, - }); + it_resolver.add_import(namespace, link_name, import_idx); + it_resolver.add_import(namespace, link_name, raw_import_idx); - interfaces.imports.push(wasmer_it::ast::Import { - namespace: &namespace, - name: link_name, - function_type: raw_import_idx, - }); + Ok(()) +} - let mut instructions = import +fn generate_it_instructions<'f>( + fn_type: &'f ExternFnType, + it_resolver: &mut ITResolver<'f>, +) -> Result<()> { + use args_it_generator::ArgumentITGenerator; + use output_type_it_generator::OutputITGenerator; + + let adapter_idx = (it_resolver.interfaces.types.len() - 2) as u32; + let raw_import_idx = (it_resolver.interfaces.types.len() - 1) as u32; + + let mut should_generate_release = false; + let mut instructions = fn_type .signature .arguments .iter() .try_fold::<_, _, Result<_>>((0, Vec::new()), |(arg_id, mut instructions), arg| { let (new_instructions, shift) = arg .ty - .generate_instructions_for_input_type(arg_id as _, it_resolver)?; + .generate_instructions_for_arg(arg_id as _, it_resolver)?; + + should_generate_release |= arg.ty.is_complex_type(); instructions.extend(new_instructions); Ok((arg_id + shift, instructions)) })? .1; + if should_generate_release { + instructions.push(Instruction::CallCore { + function_index: RELEASE_OBJECTS.id, + }); + } + // TODO: refactor let import_function_index = (it_resolver.interfaces.exports.len() + it_resolver.interfaces.imports.len() / 2 @@ -159,7 +131,7 @@ fn generate_it_for_import<'a>( function_index: import_function_index, }); - let instructions = import + let instructions = fn_type .signature .output_types .iter() @@ -170,137 +142,37 @@ fn generate_it_for_import<'a>( Ok(instructions) })?; - let adapter = Adapter { - function_type: adapter_idx, - instructions, - }; - it_resolver.interfaces.adapters.push(adapter); - - let implementation = wasmer_it::ast::Implementation { - core_function_type: raw_import_idx, - adapter_function_type: adapter_idx, - }; - it_resolver.interfaces.implementations.push(implementation); + it_resolver.add_adapter(adapter_idx, instructions); + it_resolver.add_implementation(raw_import_idx, adapter_idx); Ok(()) } -/// Generate IT instructions for a foreign mod. -trait ForeignModInstructionGenerator { - fn generate_instructions_for_input_type<'a>( - &self, - arg_id: u32, - it_resolver: &mut ITResolver<'a>, - ) -> Result<(Vec, u32)>; +pub(crate) fn generate_raw_args<'f>(signature: &FnSignature) -> Rc> { + let raw_inputs = signature + .arguments + .iter() + .map(to_raw_input_types) + .flatten() + .collect::>(); - fn generate_instructions_for_output_type<'a>( - &self, - it_resolver: &mut ITResolver<'a>, - ) -> Result>; + Rc::new(raw_inputs) } -#[rustfmt::skip] -impl ForeignModInstructionGenerator for ParsedType { - fn generate_instructions_for_input_type<'a>( - &self, - index: u32, - it_resolver: &mut ITResolver<'a>, - ) -> Result<(Vec, u32)> { - let instructions = match self { - ParsedType::Boolean(_) => (vec![Instruction::ArgumentGet { index }, Instruction::BoolFromI32], 1), - ParsedType::I8(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S8FromI32], 1), - ParsedType::I16(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S16FromI32], 1), - ParsedType::I32(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S32FromI32], 1), - ParsedType::I64(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S64FromI64], 1), - ParsedType::U8(_) => (vec![Instruction::ArgumentGet { index }, Instruction::U8FromI32], 1), - ParsedType::U16(_) => (vec![Instruction::ArgumentGet { index }, Instruction::U16FromI32], 1), - ParsedType::U32(_) => (vec![Instruction::ArgumentGet { index }, Instruction::U32FromI32], 1), - ParsedType::U64(_) => (vec![Instruction::ArgumentGet { index }, Instruction::U64FromI64], 1), - ParsedType::F32(_) => (vec![Instruction::ArgumentGet { index }], 1), - ParsedType::F64(_) => (vec![Instruction::ArgumentGet { index }], 1), - ParsedType::Utf8Str(_) | ParsedType::Utf8String(_) => (vec![ - Instruction::ArgumentGet { index }, - Instruction::ArgumentGet { index: index + 1 }, - Instruction::StringLiftMemory, - ], 2), - ParsedType::Vector(value_type, _) => { - let value_type = ptype_to_itype_checked(value_type, it_resolver)?; - if let IType::U8 = value_type { - (vec![ - Instruction::ArgumentGet { index }, - Instruction::ArgumentGet { index: index + 1 }, - Instruction::ByteArrayLiftMemory, - ], 2) - } else { - (vec![ - Instruction::ArgumentGet { index }, - Instruction::ArgumentGet { index: index + 1 }, - Instruction::ArrayLiftMemory { value_type }, - ], 2) - } - }, - ParsedType::Record(record_name, _) => { - let record_type_id = it_resolver.get_record_type_id(record_name)? as u32; +pub(crate) fn generate_raw_output_type<'f>(signature: &FnSignature) -> Rc> { + let raw_outputs = signature + .output_types + .iter() + .map(|ty| { + to_raw_output_type(ty) + .iter() + .map(wtype_to_itype) + .collect::>() + }) + .flatten() + .collect::>(); - (vec![ - Instruction::ArgumentGet { index }, - Instruction::RecordLiftMemory { record_type_id }, - ], 1) - } - }; - - Ok(instructions) - } - - #[rustfmt::skip] - fn generate_instructions_for_output_type<'a>(&self, it_resolver: &mut ITResolver<'a>) -> Result> { - let instructions = match self { - ParsedType::Boolean(_) => vec![Instruction::I32FromBool], - ParsedType::I8(_) => vec![Instruction::I32FromS8], - ParsedType::I16(_) => vec![Instruction::I32FromS16], - ParsedType::I32(_) => vec![Instruction::I32FromS32], - ParsedType::I64(_) => vec![Instruction::I64FromS64], - ParsedType::U8(_) => vec![Instruction::I32FromU8], - ParsedType::U16(_) => vec![Instruction::I32FromU16], - ParsedType::U32(_) => vec![Instruction::I32FromU32], - ParsedType::U64(_) => vec![Instruction::I64FromU64], - ParsedType::F32(_) => vec![], - ParsedType::F64(_) => vec![], - ParsedType::Utf8Str(_) | ParsedType::Utf8String(_) => { - let type_tag = it_lilo::utils::ser_type_size(&IType::U8) as i32; - - vec![ - Instruction::Dup, - Instruction::StringSize, - Instruction::PushI32 { value: type_tag }, - Instruction::CallCore { function_index: ALLOCATE_FUNC.id }, - Instruction::Swap2, - Instruction::StringLowerMemory, - Instruction::CallCore { function_index: SET_RESULT_SIZE_FUNC.id }, - Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id }, - ] - }, - ParsedType::Vector(value_type, _) => { - let value_type = ptype_to_itype_checked(value_type, it_resolver)?; - - vec![ - Instruction::ArrayLowerMemory { value_type }, - Instruction::CallCore { function_index: SET_RESULT_SIZE_FUNC.id }, - Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id }, - ] - }, - ParsedType::Record(record_name, _) => { - let record_type_id = it_resolver.get_record_type_id(record_name)? as u32; - - vec![ - Instruction::RecordLowerMemory { record_type_id }, - Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id }, - ] - }, - }; - - Ok(instructions) - } + Rc::new(raw_outputs) } use marine_macro_impl::RustType; diff --git a/crates/it-generator/src/instructions_generator/foreign_mod_instructions/args_it_generator.rs b/crates/it-generator/src/instructions_generator/foreign_mod_instructions/args_it_generator.rs new file mode 100644 index 00000000..55853cb0 --- /dev/null +++ b/crates/it-generator/src/instructions_generator/foreign_mod_instructions/args_it_generator.rs @@ -0,0 +1,86 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::ITResolver; +use super::ptype_to_itype_checked; +use crate::Result; + +use marine_macro_impl::ParsedType; +use wasmer_it::interpreter::Instruction; +use wasmer_it::IType; + +/// Generate IT instructions for a foreign mod. +pub(super) trait ArgumentITGenerator { + fn generate_instructions_for_arg<'a>( + &self, + arg_id: u32, + it_resolver: &mut ITResolver<'a>, + ) -> Result<(Vec, u32)>; +} + +#[rustfmt::skip] +impl ArgumentITGenerator for ParsedType { + fn generate_instructions_for_arg<'a>( + &self, + index: u32, + it_resolver: &mut ITResolver<'a>, + ) -> Result<(Vec, u32)> { + let instructions = match self { + ParsedType::Boolean(_) => (vec![Instruction::ArgumentGet { index }, Instruction::BoolFromI32], 1), + ParsedType::I8(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S8FromI32], 1), + ParsedType::I16(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S16FromI32], 1), + ParsedType::I32(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S32FromI32], 1), + ParsedType::I64(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S64FromI64], 1), + ParsedType::U8(_) => (vec![Instruction::ArgumentGet { index }, Instruction::U8FromI32], 1), + ParsedType::U16(_) => (vec![Instruction::ArgumentGet { index }, Instruction::U16FromI32], 1), + ParsedType::U32(_) => (vec![Instruction::ArgumentGet { index }, Instruction::U32FromI32], 1), + ParsedType::U64(_) => (vec![Instruction::ArgumentGet { index }, Instruction::U64FromI64], 1), + ParsedType::F32(_) => (vec![Instruction::ArgumentGet { index }], 1), + ParsedType::F64(_) => (vec![Instruction::ArgumentGet { index }], 1), + ParsedType::Utf8Str(_) | ParsedType::Utf8String(_) => (vec![ + Instruction::ArgumentGet { index }, + Instruction::ArgumentGet { index: index + 1 }, + Instruction::StringLiftMemory, + ], 2), + ParsedType::Vector(value_type, _) => { + let value_type = ptype_to_itype_checked(value_type, it_resolver)?; + if let IType::U8 = value_type { + (vec![ + Instruction::ArgumentGet { index }, + Instruction::ArgumentGet { index: index + 1 }, + Instruction::ByteArrayLiftMemory, + ], 2) + } else { + (vec![ + Instruction::ArgumentGet { index }, + Instruction::ArgumentGet { index: index + 1 }, + Instruction::ArrayLiftMemory { value_type }, + ], 2) + } + }, + ParsedType::Record(record_name, _) => { + let record_type_id = it_resolver.get_record_type_id(record_name)? as u32; + + (vec![ + Instruction::ArgumentGet { index }, + Instruction::RecordLiftMemory { record_type_id }, + ], 1) + } + }; + + Ok(instructions) + } +} diff --git a/crates/it-generator/src/instructions_generator/foreign_mod_instructions/output_type_it_generator.rs b/crates/it-generator/src/instructions_generator/foreign_mod_instructions/output_type_it_generator.rs new file mode 100644 index 00000000..db4bafdc --- /dev/null +++ b/crates/it-generator/src/instructions_generator/foreign_mod_instructions/output_type_it_generator.rs @@ -0,0 +1,85 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::ITResolver; +use super::ptype_to_itype_checked; +use crate::Result; +use crate::default_export_api_config::*; + +use marine_macro_impl::ParsedType; +use wasmer_it::interpreter::Instruction; +use wasmer_it::IType; + +/// Generate IT instructions for a foreign mod. +pub(super) trait OutputITGenerator { + fn generate_instructions_for_output_type<'a>( + &self, + it_resolver: &mut ITResolver<'a>, + ) -> Result>; +} + +#[rustfmt::skip] +impl OutputITGenerator for ParsedType { + #[rustfmt::skip] + fn generate_instructions_for_output_type<'a>(&self, it_resolver: &mut ITResolver<'a>) -> Result> { + let instructions = match self { + ParsedType::Boolean(_) => vec![Instruction::I32FromBool], + ParsedType::I8(_) => vec![Instruction::I32FromS8], + ParsedType::I16(_) => vec![Instruction::I32FromS16], + ParsedType::I32(_) => vec![Instruction::I32FromS32], + ParsedType::I64(_) => vec![Instruction::I64FromS64], + ParsedType::U8(_) => vec![Instruction::I32FromU8], + ParsedType::U16(_) => vec![Instruction::I32FromU16], + ParsedType::U32(_) => vec![Instruction::I32FromU32], + ParsedType::U64(_) => vec![Instruction::I64FromU64], + ParsedType::F32(_) => vec![], + ParsedType::F64(_) => vec![], + ParsedType::Utf8Str(_) | ParsedType::Utf8String(_) => { + let type_tag = it_lilo::utils::ser_type_size(&IType::U8) as i32; + + vec![ + Instruction::Dup, + Instruction::StringSize, + Instruction::PushI32 { value: type_tag }, + Instruction::CallCore { function_index: ALLOCATE_FUNC.id }, + Instruction::Swap2, + Instruction::StringLowerMemory, + Instruction::CallCore { function_index: SET_RESULT_SIZE_FUNC.id }, + Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id }, + ] + }, + ParsedType::Vector(value_type, _) => { + let value_type = ptype_to_itype_checked(value_type, it_resolver)?; + + vec![ + Instruction::ArrayLowerMemory { value_type }, + Instruction::CallCore { function_index: SET_RESULT_SIZE_FUNC.id }, + Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id }, + ] + }, + ParsedType::Record(record_name, _) => { + let record_type_id = it_resolver.get_record_type_id(record_name)? as u32; + + vec![ + Instruction::RecordLowerMemory { record_type_id }, + Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id }, + ] + }, + }; + + Ok(instructions) + } +} diff --git a/crates/it-generator/src/instructions_generator/record_instructions.rs b/crates/it-generator/src/instructions_generator/record_instructions.rs index e477a676..2ff40a62 100644 --- a/crates/it-generator/src/instructions_generator/record_instructions.rs +++ b/crates/it-generator/src/instructions_generator/record_instructions.rs @@ -22,7 +22,6 @@ use marine_macro_impl::RecordType; use marine_macro_impl::RecordFields; use wasmer_it::IRecordFieldType; -use wasmer_it::IRecordType; use wasmer_it::NEVec; impl ITGenerator for RecordType { @@ -48,12 +47,7 @@ impl ITGenerator for RecordType { )) })?; - let new_record_type = IRecordType { - name: self.name.clone(), - fields, - }; - - it_resolver.insert_record_type(new_record_type); + it_resolver.add_record_type(self.name.clone(), fields); Ok(()) } diff --git a/crates/it-generator/src/instructions_generator/tests.rs b/crates/it-generator/src/instructions_generator/tests.rs new file mode 100644 index 00000000..68b3f119 --- /dev/null +++ b/crates/it-generator/src/instructions_generator/tests.rs @@ -0,0 +1,334 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::ITGenerator; +use crate::default_export_api_config::RELEASE_OBJECTS; +use crate::instructions_generator::ITResolver; + +use marine_macro_impl::*; +use wasmer_it::interpreter::Instruction; +use wasmer_it::IType; + +fn generate_export_fn(args: Vec, output: Option) -> FnType { + let name = String::from("some_fn_name"); + + let arguments = args + .into_iter() + .map(|ty| FnArgument { + name: String::from("arg_name"), + ty, + }) + .collect::>(); + + let output_types = match output { + Some(output) => vec![output], + None => vec![], + }; + + let signature = FnSignature { + name, + arguments, + output_types, + }; + + FnType { signature } +} + +fn generate_import_mod(args: Vec, output: Option) -> ExternModType { + let name = String::from("some_fn_name"); + + let arguments = args + .into_iter() + .map(|ty| FnArgument { + name: String::from("arg_name"), + ty, + }) + .collect::>(); + + let output_types = match output { + Some(output) => vec![output], + None => vec![], + }; + + let signature = FnSignature { + name, + arguments, + output_types, + }; + + let extern_fn_type = ExternFnType { + link_name: None, + signature, + }; + + ExternModType { + namespace: String::from("some namespace"), + imports: vec![extern_fn_type], + } +} + +#[test] +fn simple_arg_types_in_export() { + let args = vec![ + ParsedType::I8(PassingStyle::ByValue), + ParsedType::I16(PassingStyle::ByValue), + ParsedType::I32(PassingStyle::ByValue), + ParsedType::I64(PassingStyle::ByValue), + ParsedType::U8(PassingStyle::ByValue), + ParsedType::U16(PassingStyle::ByValue), + ParsedType::U32(PassingStyle::ByValue), + ParsedType::U64(PassingStyle::ByValue), + ParsedType::F32(PassingStyle::ByValue), + ParsedType::F64(PassingStyle::ByValue), + ]; + + let outputs = Some(ParsedType::I32(PassingStyle::ByValue)); + let fn_type = generate_export_fn(args, outputs); + + let mut it_resolver = ITResolver::default(); + fn_type + .generate_it(&mut it_resolver) + .expect("IT generation succeeded"); + + let interfaces = it_resolver.interfaces; + + let actual_instruction = &interfaces.adapters[0].instructions; + + let expected_instruction = vec![ + Instruction::ArgumentGet { index: 0 }, + Instruction::I32FromS8, + Instruction::ArgumentGet { index: 1 }, + Instruction::I32FromS16, + Instruction::ArgumentGet { index: 2 }, + Instruction::I32FromS32, + Instruction::ArgumentGet { index: 3 }, + Instruction::I64FromS64, + Instruction::ArgumentGet { index: 4 }, + Instruction::I32FromU8, + Instruction::ArgumentGet { index: 5 }, + Instruction::I32FromU16, + Instruction::ArgumentGet { index: 6 }, + Instruction::I32FromU32, + Instruction::ArgumentGet { index: 7 }, + Instruction::I64FromU64, + Instruction::ArgumentGet { index: 8 }, + Instruction::ArgumentGet { index: 9 }, + Instruction::CallCore { function_index: 0 }, + Instruction::S32FromI32, + ]; + + assert_eq!(actual_instruction, &expected_instruction); +} + +#[test] +fn complex_arg_types_in_export() { + let args = vec![ + ParsedType::I8(PassingStyle::ByValue), + ParsedType::I16(PassingStyle::ByValue), + ParsedType::I32(PassingStyle::ByValue), + ParsedType::I64(PassingStyle::ByValue), + ParsedType::U8(PassingStyle::ByValue), + ParsedType::U16(PassingStyle::ByValue), + ParsedType::U32(PassingStyle::ByValue), + ParsedType::U64(PassingStyle::ByValue), + ParsedType::F32(PassingStyle::ByValue), + ParsedType::F64(PassingStyle::ByValue), + ParsedType::Utf8String(PassingStyle::ByValue), + ParsedType::Vector( + Box::new(ParsedType::U8(PassingStyle::ByValue)), + PassingStyle::ByValue, + ), + ]; + + let outputs = Some(ParsedType::Utf8String(PassingStyle::ByValue)); + let fn_type = generate_export_fn(args, outputs); + + let mut it_resolver = ITResolver::default(); + fn_type + .generate_it(&mut it_resolver) + .expect("IT generation succeeded"); + + let interfaces = it_resolver.interfaces; + + let actual_instruction = &interfaces.adapters[0].instructions; + + let expected_instruction = vec![ + Instruction::ArgumentGet { index: 0 }, + Instruction::I32FromS8, + Instruction::ArgumentGet { index: 1 }, + Instruction::I32FromS16, + Instruction::ArgumentGet { index: 2 }, + Instruction::I32FromS32, + Instruction::ArgumentGet { index: 3 }, + Instruction::I64FromS64, + Instruction::ArgumentGet { index: 4 }, + Instruction::I32FromU8, + Instruction::ArgumentGet { index: 5 }, + Instruction::I32FromU16, + Instruction::ArgumentGet { index: 6 }, + Instruction::I32FromU32, + Instruction::ArgumentGet { index: 7 }, + Instruction::I64FromU64, + Instruction::ArgumentGet { index: 8 }, + Instruction::ArgumentGet { index: 9 }, + Instruction::ArgumentGet { index: 10 }, + Instruction::StringSize, + Instruction::PushI32 { value: 1 }, + Instruction::CallCore { function_index: 0 }, + Instruction::ArgumentGet { index: 10 }, + Instruction::StringLowerMemory, + Instruction::ArgumentGet { index: 11 }, + Instruction::ArrayLowerMemory { + value_type: IType::U8, + }, + Instruction::CallCore { function_index: 0 }, + Instruction::CallCore { function_index: 3 }, + Instruction::CallCore { function_index: 2 }, + Instruction::StringLiftMemory, + Instruction::CallCore { + function_index: RELEASE_OBJECTS.id, + }, + ]; + + assert_eq!(actual_instruction, &expected_instruction); +} + +#[test] +fn simple_arg_types_in_import() { + let args = vec![ + ParsedType::I8(PassingStyle::ByValue), + ParsedType::I16(PassingStyle::ByValue), + ParsedType::I32(PassingStyle::ByValue), + ParsedType::I64(PassingStyle::ByValue), + ParsedType::U8(PassingStyle::ByValue), + ParsedType::U16(PassingStyle::ByValue), + ParsedType::U32(PassingStyle::ByValue), + ParsedType::U64(PassingStyle::ByValue), + ParsedType::F32(PassingStyle::ByValue), + ParsedType::F64(PassingStyle::ByValue), + ]; + + let outputs = Some(ParsedType::I32(PassingStyle::ByValue)); + let import_fn_type = generate_import_mod(args, outputs); + + let mut it_resolver = ITResolver::default(); + import_fn_type + .generate_it(&mut it_resolver) + .expect("IT generation succeeded"); + + let interfaces = it_resolver.interfaces; + + let actual_instruction = &interfaces.adapters[0].instructions; + + let expected_instruction = vec![ + Instruction::ArgumentGet { index: 0 }, + Instruction::S8FromI32, + Instruction::ArgumentGet { index: 1 }, + Instruction::S16FromI32, + Instruction::ArgumentGet { index: 2 }, + Instruction::S32FromI32, + Instruction::ArgumentGet { index: 3 }, + Instruction::S64FromI64, + Instruction::ArgumentGet { index: 4 }, + Instruction::U8FromI32, + Instruction::ArgumentGet { index: 5 }, + Instruction::U16FromI32, + Instruction::ArgumentGet { index: 6 }, + Instruction::U32FromI32, + Instruction::ArgumentGet { index: 7 }, + Instruction::U64FromI64, + Instruction::ArgumentGet { index: 8 }, + Instruction::ArgumentGet { index: 9 }, + Instruction::CallCore { function_index: 0 }, + Instruction::I32FromS32, + ]; + + assert_eq!(actual_instruction, &expected_instruction); +} + +#[test] +fn complex_arg_types_in_import() { + let args = vec![ + ParsedType::I8(PassingStyle::ByValue), + ParsedType::I16(PassingStyle::ByValue), + ParsedType::I32(PassingStyle::ByValue), + ParsedType::I64(PassingStyle::ByValue), + ParsedType::U8(PassingStyle::ByValue), + ParsedType::U16(PassingStyle::ByValue), + ParsedType::U32(PassingStyle::ByValue), + ParsedType::U64(PassingStyle::ByValue), + ParsedType::F32(PassingStyle::ByValue), + ParsedType::F64(PassingStyle::ByValue), + ParsedType::Utf8String(PassingStyle::ByValue), + ParsedType::Vector( + Box::new(ParsedType::U8(PassingStyle::ByValue)), + PassingStyle::ByValue, + ), + ]; + + let outputs = Some(ParsedType::Utf8String(PassingStyle::ByValue)); + let fn_type = generate_import_mod(args, outputs); + + let mut it_resolver = ITResolver::default(); + fn_type + .generate_it(&mut it_resolver) + .expect("IT generation succeeded"); + + let interfaces = it_resolver.interfaces; + + let actual_instruction = &interfaces.adapters[0].instructions; + + let expected_instruction = vec![ + Instruction::ArgumentGet { index: 0 }, + Instruction::S8FromI32, + Instruction::ArgumentGet { index: 1 }, + Instruction::S16FromI32, + Instruction::ArgumentGet { index: 2 }, + Instruction::S32FromI32, + Instruction::ArgumentGet { index: 3 }, + Instruction::S64FromI64, + Instruction::ArgumentGet { index: 4 }, + Instruction::U8FromI32, + Instruction::ArgumentGet { index: 5 }, + Instruction::U16FromI32, + Instruction::ArgumentGet { index: 6 }, + Instruction::U32FromI32, + Instruction::ArgumentGet { index: 7 }, + Instruction::U64FromI64, + Instruction::ArgumentGet { index: 8 }, + Instruction::ArgumentGet { index: 9 }, + Instruction::ArgumentGet { index: 10 }, + Instruction::ArgumentGet { index: 11 }, + Instruction::StringLiftMemory, + Instruction::ArgumentGet { index: 12 }, + Instruction::ArgumentGet { index: 13 }, + Instruction::ByteArrayLiftMemory, + Instruction::CallCore { + function_index: RELEASE_OBJECTS.id, + }, + Instruction::CallCore { function_index: 0 }, + Instruction::Dup, + Instruction::StringSize, + Instruction::PushI32 { value: 1 }, + Instruction::CallCore { function_index: 0 }, + Instruction::Swap2, + Instruction::StringLowerMemory, + Instruction::CallCore { function_index: 4 }, + Instruction::CallCore { function_index: 5 }, + ]; + + assert_eq!(actual_instruction, &expected_instruction); +} diff --git a/crates/it-generator/src/instructions_generator/utils.rs b/crates/it-generator/src/instructions_generator/utils.rs index 592e4eb6..adf5d492 100644 --- a/crates/it-generator/src/instructions_generator/utils.rs +++ b/crates/it-generator/src/instructions_generator/utils.rs @@ -18,8 +18,12 @@ use super::IType; use crate::instructions_generator::ITResolver; use crate::Result; +use marine_macro_impl::FnSignature; use marine_macro_impl::ParsedType; use marine_macro_impl::RustType; +use wasmer_it::ast::FunctionArg as IFunctionArg; + +use std::rc::Rc; // return error if there is no record with such name pub(crate) fn ptype_to_itype_checked( @@ -102,3 +106,37 @@ pub(crate) fn wtype_to_itype(pty: &RustType) -> IType { RustType::F64 => IType::F64, } } + +pub(crate) fn generate_it_args<'f>( + signature: &FnSignature, + it_resolver: &mut ITResolver<'f>, +) -> Result>> { + let arguments = signature + .arguments + .iter() + .map(|arg| -> Result { + Ok(IFunctionArg { + name: arg.name.clone(), + ty: ptype_to_itype_checked(&arg.ty, it_resolver)?, + }) + }) + .collect::>>()?; + + let arguments = Rc::new(arguments); + Ok(arguments) +} + +pub(crate) fn generate_it_output_type<'f>( + signature: &FnSignature, + it_resolver: &mut ITResolver<'f>, +) -> Result>> { + let output_types = signature + .output_types + .iter() + .map(|ty| ptype_to_itype_checked(ty, it_resolver)) + .collect::>>()?; + + let output_types = Rc::new(output_types); + + Ok(output_types) +} diff --git a/crates/module-info-parser/Cargo.toml b/crates/module-info-parser/Cargo.toml index 3a5a01e7..727d6044 100644 --- a/crates/module-info-parser/Cargo.toml +++ b/crates/module-info-parser/Cargo.toml @@ -11,7 +11,7 @@ name = "marine_module_info_parser" path = "src/lib.rs" [dependencies] -fluence-sdk-main = "0.6.3" +fluence-sdk-main = "0.6.9" wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0" } diff --git a/examples/call_parameters/Cargo.toml b/examples/call_parameters/Cargo.toml index 4e688e52..be063ba2 100644 --- a/examples/call_parameters/Cargo.toml +++ b/examples/call_parameters/Cargo.toml @@ -10,7 +10,7 @@ name = "call_parameters" path = "src/main.rs" [dependencies] -fluence = "0.6.4" +fluence = "0.6.9" [dev-dependencies] fluence-test = "0.1.7" diff --git a/examples/greeting/Cargo.toml b/examples/greeting/Cargo.toml index 05776e45..045b1e2c 100644 --- a/examples/greeting/Cargo.toml +++ b/examples/greeting/Cargo.toml @@ -12,7 +12,7 @@ name = "greeting" path = "src/main.rs" [dependencies] -fluence = "0.6.4" +fluence = "0.6.9" [dev-dependencies] fluence-test = "0.1.7" diff --git a/examples/records/effector/Cargo.toml b/examples/records/effector/Cargo.toml index cf025d54..2333f44f 100644 --- a/examples/records/effector/Cargo.toml +++ b/examples/records/effector/Cargo.toml @@ -10,5 +10,5 @@ name = "records_effector" path = "src/main.rs" [dependencies] -fluence = "0.6.4" +fluence = "0.6.9" test-record = { path = "../test-record" } diff --git a/examples/records/pure/Cargo.toml b/examples/records/pure/Cargo.toml index 3b93a42e..e4724034 100644 --- a/examples/records/pure/Cargo.toml +++ b/examples/records/pure/Cargo.toml @@ -10,5 +10,5 @@ name = "records_pure" path = "src/main.rs" [dependencies] -fluence = "0.6.4" +fluence = "0.6.9" test-record = { path = "../test-record" } diff --git a/examples/records/test-record/Cargo.toml b/examples/records/test-record/Cargo.toml index 563f0642..31bd1495 100644 --- a/examples/records/test-record/Cargo.toml +++ b/examples/records/test-record/Cargo.toml @@ -10,4 +10,4 @@ name = "test_record" path = "src/test_record.rs" [dependencies] -fluence = "0.6.4" +fluence = "0.6.9" diff --git a/examples/sqlite/Cargo.toml b/examples/sqlite/Cargo.toml index 74d6c65f..e3b10c1f 100644 --- a/examples/sqlite/Cargo.toml +++ b/examples/sqlite/Cargo.toml @@ -10,5 +10,5 @@ name = "sqlite_test" path = "src/main.rs" [dependencies] -fluence = "0.6.4" +fluence = "0.6.9" marine-sqlite-connector = "0.4.0" diff --git a/fluence-faas/Cargo.toml b/fluence-faas/Cargo.toml index 3fde2f7b..9821bc1f 100644 --- a/fluence-faas/Cargo.toml +++ b/fluence-faas/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] marine-runtime = { path = "../runtime", version = "0.5.0" } marine-utils = { path = "../crates/utils", version = "0.2.0" } -fluence-sdk-main = { version = "0.6.3", features = ["logger"] } +fluence-sdk-main = { version = "0.6.9", features = ["logger"] } fluence = { version = "0.6.3", features = ["logger"] } wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" } diff --git a/fluence-faas/tests/wasm_tests/arrays_passing/Cargo.toml b/fluence-faas/tests/wasm_tests/arrays_passing/Cargo.toml index 98f8a9ac..f885489f 100644 --- a/fluence-faas/tests/wasm_tests/arrays_passing/Cargo.toml +++ b/fluence-faas/tests/wasm_tests/arrays_passing/Cargo.toml @@ -14,5 +14,5 @@ name = "arrays_passing_effector" path = "src/effector.rs" [dependencies] -fluence = "0.6.4" +fluence = "0.6.9" safe-transmute = "0.11.0" diff --git a/fluence-faas/tests/wasm_tests/records_passing/Cargo.toml b/fluence-faas/tests/wasm_tests/records_passing/Cargo.toml index c9f0ae03..5cc99f8f 100644 --- a/fluence-faas/tests/wasm_tests/records_passing/Cargo.toml +++ b/fluence-faas/tests/wasm_tests/records_passing/Cargo.toml @@ -14,5 +14,5 @@ name = "records_passing_pure" path = "src/pure.rs" [dependencies] -fluence = "0.6.4" +fluence = "0.6.9" safe-transmute = "0.11.0" diff --git a/tools/cli/Cargo.toml b/tools/cli/Cargo.toml index 604eb91e..4a5cca4f 100644 --- a/tools/cli/Cargo.toml +++ b/tools/cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "marine" description = "Fluence Marine command line tool" -version = "0.6.1" +version = "0.6.2" authors = ["Fluence Labs"] repository = "https://github.com/fluencelabs/marine/tools/cli" license = "Apache-2.0" diff --git a/tools/repl/Cargo.toml b/tools/repl/Cargo.toml index 4f96e42a..94f91f08 100644 --- a/tools/repl/Cargo.toml +++ b/tools/repl/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" [dependencies] fluence-app-service = { path = "../../fluence-app-service", version = "0.7.1", features = ["raw-module-api"] } -fluence-sdk-main = { version = "0.6.3", features = ["logger"] } +fluence-sdk-main = { version = "0.6.9", features = ["logger"] } anyhow = "1.0.31" clap = "2.33.1"