Fix IT generation (#87)

This commit is contained in:
Mike Voronov 2021-05-19 18:58:24 +03:00 committed by GitHub
parent fa38bc4025
commit c51b5982d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 938 additions and 432 deletions

View File

@ -29,7 +29,7 @@ jobs:
(cd ./examples; ./build.sh) (cd ./examples; ./build.sh)
(cd ./fluence-faas/tests/wasm_tests; ./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 cargo clippy -v -p marine-runtime -p fluence-faas -p fluence-app-service -p marine -p mrepl
- save_cache: - save_cache:

20
Cargo.lock generated
View File

@ -700,9 +700,9 @@ dependencies = [
[[package]] [[package]]
name = "fluence" name = "fluence"
version = "0.6.5" version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd1f159a4da6aef89e8e4a0bf061a8031d669d03d9928266942581a52df03f56" checksum = "88b09e1cd11a51ba4d169db347d009fe41ece2714eef4d5df720343733a1d5a6"
dependencies = [ dependencies = [
"fluence-sdk-main", "fluence-sdk-main",
"marine-macro", "marine-macro",
@ -805,9 +805,9 @@ dependencies = [
[[package]] [[package]]
name = "fluence-sdk-main" name = "fluence-sdk-main"
version = "0.6.4" version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a5d1ca20ada064379d959a9a82f9c006e4d9388533cf06010186fef6dd583b" checksum = "68d93cde99e1494e11755a39b93863333397245c9959c774fe3bebd9e4143879"
dependencies = [ dependencies = [
"log", "log",
"marine-macro", "marine-macro",
@ -1549,18 +1549,18 @@ dependencies = [
[[package]] [[package]]
name = "marine-macro" name = "marine-macro"
version = "0.6.4" version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c1652b6ac1bbdde9a66c16c8a2f9cd34d005a1f1b211a538c5b28764faa6ef4" checksum = "f63d927851847cc3dd9e3bd0f10bdeb313859d4822d5b5f650d9d34d461ed419"
dependencies = [ dependencies = [
"marine-macro-impl", "marine-macro-impl",
] ]
[[package]] [[package]]
name = "marine-macro-impl" name = "marine-macro-impl"
version = "0.6.4" version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80fee75eaf1a97ee9fe2d382c0537c06a79e5d7ab9d81bda6cb263fb8fd1a15a" checksum = "fb504be4a90e229ab453c7369cc8a9063acec819f3397802eea719cd0a232be1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1699,9 +1699,9 @@ dependencies = [
[[package]] [[package]]
name = "marine-timestamp-macro" name = "marine-timestamp-macro"
version = "0.6.2" version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6feb612ccd3fd39ec3d50c9a1a96885e1fd32d36a92cf674a0fbe6f7c452613" checksum = "5994c7db5567d21609f2a2e5a40d9d4564f86c17ca35b2d77007152619b9d7fc"
dependencies = [ dependencies = [
"chrono", "chrono",
"quote", "quote",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine-it-generator" name = "marine-it-generator"
description = "Fluence Marine interface types generator" description = "Fluence Marine interface types generator"
version = "0.5.1" version = "0.5.2"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
@ -12,7 +12,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
marine-it-parser = { path = "../it-parser", version = "0.6.0"} 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" } wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.0" }
it-lilo = "0.1.0" it-lilo = "0.1.0"

View File

@ -17,6 +17,8 @@
mod fn_instructions; mod fn_instructions;
mod foreign_mod_instructions; mod foreign_mod_instructions;
mod record_instructions; mod record_instructions;
#[cfg(test)]
mod tests;
mod utils; mod utils;
use crate::Result; 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<wasmer_it::interpreter::Instruction>,
) {
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<Vec<wasmer_it::ast::FunctionArg>>,
output_types: Rc<Vec<IType>>,
) {
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<wasmer_it::IRecordFieldType>,
) {
let record = wasmer_it::IRecordType { name, fields };
self.insert_record_type(record);
}
}
pub(crate) trait ITGenerator { pub(crate) trait ITGenerator {
fn generate_it<'a>(&'a self, it_resolver: &mut ITResolver<'a>) -> Result<()>; fn generate_it<'a>(&'a self, it_resolver: &mut ITResolver<'a>) -> Result<()>;
} }

View File

@ -14,225 +14,87 @@
* limitations under the License. * limitations under the License.
*/ */
mod args_it_generator;
mod output_type_it_generator;
use super::ITGenerator; use super::ITGenerator;
use super::ITResolver; use super::ITResolver;
use super::utils::ptype_to_itype_checked; use super::utils::*;
use crate::default_export_api_config::*;
use crate::Result; use crate::Result;
use crate::default_export_api_config::RELEASE_OBJECTS;
use marine_macro_impl::FnType; use marine_macro_impl::FnType;
use marine_macro_impl::ParsedType;
use wasmer_it::interpreter::Instruction; use wasmer_it::interpreter::Instruction;
use wasmer_it::ast::FunctionArg as IFunctionArg;
use wasmer_it::IType;
use std::rc::Rc;
impl ITGenerator for FnType { impl ITGenerator for FnType {
fn generate_it<'a>(&'a self, it_resolver: &mut ITResolver<'a>) -> Result<()> { fn generate_it<'a>(&'a self, it_resolver: &mut ITResolver<'a>) -> Result<()> {
use wasmer_it::ast::Type; generate_it_types(self, it_resolver)?;
use wasmer_it::ast::Adapter; generate_instructions(self, it_resolver)
}
}
let arguments = self fn generate_it_types<'f>(fn_type: &'f FnType, it_resolver: &mut ITResolver<'f>) -> Result<()> {
.signature let arguments = generate_it_args(&fn_type.signature, it_resolver)?;
.arguments let output_types = generate_it_output_type(&fn_type.signature, it_resolver)?;
.iter()
.map(|arg| -> Result<IFunctionArg> {
Ok(IFunctionArg {
name: arg.name.clone(),
ty: ptype_to_itype_checked(&arg.ty, it_resolver)?,
})
})
.collect::<Result<Vec<_>>>()?;
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 let export_idx = (it_resolver.interfaces.types.len() - 1) as u32;
.signature it_resolver.add_export(&fn_type.signature.name, export_idx);
.output_types
.iter()
.map(|ty| ptype_to_itype_checked(ty, it_resolver))
.collect::<Result<Vec<_>>>()?;
let output_types = Rc::new(output_types);
let interfaces = &mut it_resolver.interfaces; Ok(())
interfaces.types.push(Type::Function { }
arguments: arguments.clone(),
output_types: output_types.clone(),
});
// TODO: replace with Wasm types fn generate_instructions<'f>(fn_type: &'f FnType, it_resolver: &mut ITResolver<'f>) -> Result<()> {
interfaces.types.push(Type::Function { use args_it_generator::ArgumentITGenerator;
arguments, use output_type_it_generator::OutputITGenerator;
output_types,
});
let adapter_idx = (interfaces.types.len() - 2) as u32; let mut instructions = fn_type
let export_idx = (interfaces.types.len() - 1) as u32; .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 { instructions.extend(new_instructions);
name: &self.signature.name, Ok(instructions)
function_type: export_idx, })?;
});
let mut instructions = self let export_function_index = (it_resolver.interfaces.exports.len() - 1) as u32;
.signature instructions.push(Instruction::CallCore {
.arguments function_index: export_function_index,
.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)?;
instructions.extend(new_instructions); let mut should_generate_release = false;
Ok(instructions) 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 { 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<Vec<Instruction>>;
fn generate_instructions_for_output_type<'a>(
&self,
it_resolver: &mut ITResolver<'a>,
) -> Result<Vec<Instruction>>;
}
impl FnInstructionGenerator for ParsedType {
#[rustfmt::skip]
fn generate_instructions_for_input_type<'a>(&self, index: u32, it_resolver: &mut ITResolver<'a>) -> Result<Vec<Instruction>> {
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] let types_count = it_resolver.interfaces.types.len() as u32;
fn generate_instructions_for_output_type<'a>(&self, it_resolver: &mut ITResolver<'a>) -> Result<Vec<Instruction>> { let adapter_idx = types_count - 2;
let instructions = match self { let export_idx = types_count - 1;
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;
vec! [ it_resolver.add_adapter(adapter_idx, instructions);
Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, it_resolver.add_implementation(export_idx, adapter_idx);
Instruction::RecordLiftMemory { record_type_id },
Instruction::CallCore { function_index: RELEASE_OBJECTS.id },
]
},
};
Ok(instructions) Ok(())
}
} }

View File

@ -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<Vec<Instruction>>;
}
impl ArgumentITGenerator for ParsedType {
#[rustfmt::skip]
fn generate_instructions_for_arg<'a>(&self, index: u32, it_resolver: &mut ITResolver<'a>) -> Result<Vec<Instruction>> {
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)
}
}

View File

@ -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<Vec<Instruction>>;
}
impl OutputITGenerator for ParsedType {
#[rustfmt::skip]
fn generate_instructions_for_output_type<'a>(&self, it_resolver: &mut ITResolver<'a>) -> Result<Vec<Instruction>> {
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)
}
}

View File

@ -14,17 +14,21 @@
* limitations under the License. * limitations under the License.
*/ */
mod args_it_generator;
mod output_type_it_generator;
use super::ITGenerator; use super::ITGenerator;
use super::ITResolver; use super::ITResolver;
use super::utils::ptype_to_itype_checked; use super::utils::*;
use crate::Result; 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 crate::instructions_generator::utils::wtype_to_itype;
use marine_macro_impl::ExternModType; use marine_macro_impl::ExternModType;
use marine_macro_impl::ExternFnType; use marine_macro_impl::ExternFnType;
use marine_macro_impl::ParsedType; use marine_macro_impl::ParsedType;
use marine_macro_impl::FnArgument; use marine_macro_impl::FnArgument;
use marine_macro_impl::FnSignature;
use wasmer_it::ast::FunctionArg as IFunctionArg; use wasmer_it::ast::FunctionArg as IFunctionArg;
use wasmer_it::interpreter::Instruction; use wasmer_it::interpreter::Instruction;
use wasmer_it::IType; use wasmer_it::IType;
@ -49,108 +53,76 @@ impl ITGenerator for ExternModType {
} }
fn generate_it_for_import<'a>( fn generate_it_for_import<'a>(
import: &'a ExternFnType, fn_type: &'a ExternFnType,
namespace: &'a str, namespace: &'a str,
it_resolver: &mut ITResolver<'a>, it_resolver: &mut ITResolver<'a>,
) -> Result<()> { ) -> Result<()> {
use wasmer_it::ast::Type; generate_it_types(fn_type, namespace, it_resolver)?;
use wasmer_it::ast::Adapter; generate_it_instructions(fn_type, it_resolver)
}
let arguments = import fn generate_it_types<'f>(
.signature fn_type: &'f ExternFnType,
.arguments namespace: &'f str,
.iter() it_resolver: &mut ITResolver<'f>,
.map(|arg| -> Result<IFunctionArg> { ) -> Result<()> {
Ok(IFunctionArg { let arguments = generate_it_args(&fn_type.signature, it_resolver)?;
name: arg.name.clone(), let output_types = generate_it_output_type(&fn_type.signature, it_resolver)?;
ty: ptype_to_itype_checked(&arg.ty, it_resolver)?, it_resolver.add_fn_type(arguments, output_types);
})
})
.collect::<Result<Vec<_>>>()?;
let arguments = Rc::new(arguments);
let output_types = import let raw_arguments = generate_raw_args(&fn_type.signature);
.signature let raw_output_types = generate_raw_output_type(&fn_type.signature);
.output_types it_resolver.add_fn_type(raw_arguments.clone(), raw_output_types.clone());
.iter() it_resolver.add_fn_type(raw_arguments, raw_output_types);
.map(|ty| ptype_to_itype_checked(ty, it_resolver))
.collect::<Result<Vec<_>>>()?;
let output_types = Rc::new(output_types);
let interfaces = &mut it_resolver.interfaces; let types_count = it_resolver.interfaces.types.len() as u32;
interfaces.types.push(Type::Function { let import_idx = types_count - 3;
arguments, let raw_import_idx = types_count - 1;
output_types,
});
let raw_inputs = import let link_name = match &fn_type.link_name {
.signature
.arguments
.iter()
.map(to_raw_input_types)
.flatten()
.collect::<Vec<_>>();
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::<Vec<_>>()
})
.flatten()
.collect::<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 link_name = match &import.link_name {
Some(link_name) => link_name, Some(link_name) => link_name,
None => &import.signature.name, None => &fn_type.signature.name,
}; };
interfaces.imports.push(wasmer_it::ast::Import { it_resolver.add_import(namespace, link_name, import_idx);
namespace: &namespace, it_resolver.add_import(namespace, link_name, raw_import_idx);
name: link_name,
function_type: import_idx,
});
interfaces.imports.push(wasmer_it::ast::Import { Ok(())
namespace: &namespace, }
name: link_name,
function_type: raw_import_idx,
});
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 .signature
.arguments .arguments
.iter() .iter()
.try_fold::<_, _, Result<_>>((0, Vec::new()), |(arg_id, mut instructions), arg| { .try_fold::<_, _, Result<_>>((0, Vec::new()), |(arg_id, mut instructions), arg| {
let (new_instructions, shift) = arg let (new_instructions, shift) = arg
.ty .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); instructions.extend(new_instructions);
Ok((arg_id + shift, instructions)) Ok((arg_id + shift, instructions))
})? })?
.1; .1;
if should_generate_release {
instructions.push(Instruction::CallCore {
function_index: RELEASE_OBJECTS.id,
});
}
// TODO: refactor // TODO: refactor
let import_function_index = (it_resolver.interfaces.exports.len() let import_function_index = (it_resolver.interfaces.exports.len()
+ it_resolver.interfaces.imports.len() / 2 + it_resolver.interfaces.imports.len() / 2
@ -159,7 +131,7 @@ fn generate_it_for_import<'a>(
function_index: import_function_index, function_index: import_function_index,
}); });
let instructions = import let instructions = fn_type
.signature .signature
.output_types .output_types
.iter() .iter()
@ -170,137 +142,37 @@ fn generate_it_for_import<'a>(
Ok(instructions) Ok(instructions)
})?; })?;
let adapter = Adapter { it_resolver.add_adapter(adapter_idx, instructions);
function_type: adapter_idx, it_resolver.add_implementation(raw_import_idx, 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);
Ok(()) Ok(())
} }
/// Generate IT instructions for a foreign mod. pub(crate) fn generate_raw_args<'f>(signature: &FnSignature) -> Rc<Vec<IFunctionArg>> {
trait ForeignModInstructionGenerator { let raw_inputs = signature
fn generate_instructions_for_input_type<'a>( .arguments
&self, .iter()
arg_id: u32, .map(to_raw_input_types)
it_resolver: &mut ITResolver<'a>, .flatten()
) -> Result<(Vec<Instruction>, u32)>; .collect::<Vec<_>>();
fn generate_instructions_for_output_type<'a>( Rc::new(raw_inputs)
&self,
it_resolver: &mut ITResolver<'a>,
) -> Result<Vec<Instruction>>;
} }
#[rustfmt::skip] pub(crate) fn generate_raw_output_type<'f>(signature: &FnSignature) -> Rc<Vec<IType>> {
impl ForeignModInstructionGenerator for ParsedType { let raw_outputs = signature
fn generate_instructions_for_input_type<'a>( .output_types
&self, .iter()
index: u32, .map(|ty| {
it_resolver: &mut ITResolver<'a>, to_raw_output_type(ty)
) -> Result<(Vec<Instruction>, u32)> { .iter()
let instructions = match self { .map(wtype_to_itype)
ParsedType::Boolean(_) => (vec![Instruction::ArgumentGet { index }, Instruction::BoolFromI32], 1), .collect::<Vec<_>>()
ParsedType::I8(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S8FromI32], 1), })
ParsedType::I16(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S16FromI32], 1), .flatten()
ParsedType::I32(_) => (vec![Instruction::ArgumentGet { index }, Instruction::S32FromI32], 1), .collect::<Vec<_>>();
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![ Rc::new(raw_outputs)
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<Vec<Instruction>> {
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)
}
} }
use marine_macro_impl::RustType; use marine_macro_impl::RustType;

View File

@ -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<Instruction>, u32)>;
}
#[rustfmt::skip]
impl ArgumentITGenerator for ParsedType {
fn generate_instructions_for_arg<'a>(
&self,
index: u32,
it_resolver: &mut ITResolver<'a>,
) -> Result<(Vec<Instruction>, 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)
}
}

View File

@ -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<Vec<Instruction>>;
}
#[rustfmt::skip]
impl OutputITGenerator for ParsedType {
#[rustfmt::skip]
fn generate_instructions_for_output_type<'a>(&self, it_resolver: &mut ITResolver<'a>) -> Result<Vec<Instruction>> {
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)
}
}

View File

@ -22,7 +22,6 @@ use marine_macro_impl::RecordType;
use marine_macro_impl::RecordFields; use marine_macro_impl::RecordFields;
use wasmer_it::IRecordFieldType; use wasmer_it::IRecordFieldType;
use wasmer_it::IRecordType;
use wasmer_it::NEVec; use wasmer_it::NEVec;
impl ITGenerator for RecordType { impl ITGenerator for RecordType {
@ -48,12 +47,7 @@ impl ITGenerator for RecordType {
)) ))
})?; })?;
let new_record_type = IRecordType { it_resolver.add_record_type(self.name.clone(), fields);
name: self.name.clone(),
fields,
};
it_resolver.insert_record_type(new_record_type);
Ok(()) Ok(())
} }

View File

@ -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<ParsedType>, output: Option<ParsedType>) -> FnType {
let name = String::from("some_fn_name");
let arguments = args
.into_iter()
.map(|ty| FnArgument {
name: String::from("arg_name"),
ty,
})
.collect::<Vec<_>>();
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<ParsedType>, output: Option<ParsedType>) -> ExternModType {
let name = String::from("some_fn_name");
let arguments = args
.into_iter()
.map(|ty| FnArgument {
name: String::from("arg_name"),
ty,
})
.collect::<Vec<_>>();
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);
}

View File

@ -18,8 +18,12 @@ use super::IType;
use crate::instructions_generator::ITResolver; use crate::instructions_generator::ITResolver;
use crate::Result; use crate::Result;
use marine_macro_impl::FnSignature;
use marine_macro_impl::ParsedType; use marine_macro_impl::ParsedType;
use marine_macro_impl::RustType; 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 // return error if there is no record with such name
pub(crate) fn ptype_to_itype_checked( pub(crate) fn ptype_to_itype_checked(
@ -102,3 +106,37 @@ pub(crate) fn wtype_to_itype(pty: &RustType) -> IType {
RustType::F64 => IType::F64, RustType::F64 => IType::F64,
} }
} }
pub(crate) fn generate_it_args<'f>(
signature: &FnSignature,
it_resolver: &mut ITResolver<'f>,
) -> Result<Rc<Vec<IFunctionArg>>> {
let arguments = signature
.arguments
.iter()
.map(|arg| -> Result<IFunctionArg> {
Ok(IFunctionArg {
name: arg.name.clone(),
ty: ptype_to_itype_checked(&arg.ty, it_resolver)?,
})
})
.collect::<Result<Vec<_>>>()?;
let arguments = Rc::new(arguments);
Ok(arguments)
}
pub(crate) fn generate_it_output_type<'f>(
signature: &FnSignature,
it_resolver: &mut ITResolver<'f>,
) -> Result<Rc<Vec<IType>>> {
let output_types = signature
.output_types
.iter()
.map(|ty| ptype_to_itype_checked(ty, it_resolver))
.collect::<Result<Vec<_>>>()?;
let output_types = Rc::new(output_types);
Ok(output_types)
}

View File

@ -11,7 +11,7 @@ name = "marine_module_info_parser"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
fluence-sdk-main = "0.6.3" fluence-sdk-main = "0.6.9"
wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0" } wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0" }

View File

@ -10,7 +10,7 @@ name = "call_parameters"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = "0.6.4" fluence = "0.6.9"
[dev-dependencies] [dev-dependencies]
fluence-test = "0.1.7" fluence-test = "0.1.7"

View File

@ -12,7 +12,7 @@ name = "greeting"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = "0.6.4" fluence = "0.6.9"
[dev-dependencies] [dev-dependencies]
fluence-test = "0.1.7" fluence-test = "0.1.7"

View File

@ -10,5 +10,5 @@ name = "records_effector"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = "0.6.4" fluence = "0.6.9"
test-record = { path = "../test-record" } test-record = { path = "../test-record" }

View File

@ -10,5 +10,5 @@ name = "records_pure"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = "0.6.4" fluence = "0.6.9"
test-record = { path = "../test-record" } test-record = { path = "../test-record" }

View File

@ -10,4 +10,4 @@ name = "test_record"
path = "src/test_record.rs" path = "src/test_record.rs"
[dependencies] [dependencies]
fluence = "0.6.4" fluence = "0.6.9"

View File

@ -10,5 +10,5 @@ name = "sqlite_test"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = "0.6.4" fluence = "0.6.9"
marine-sqlite-connector = "0.4.0" marine-sqlite-connector = "0.4.0"

View File

@ -9,7 +9,7 @@ edition = "2018"
[dependencies] [dependencies]
marine-runtime = { path = "../runtime", version = "0.5.0" } marine-runtime = { path = "../runtime", version = "0.5.0" }
marine-utils = { path = "../crates/utils", version = "0.2.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"] } fluence = { version = "0.6.3", features = ["logger"] }
wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" } wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" }

View File

@ -14,5 +14,5 @@ name = "arrays_passing_effector"
path = "src/effector.rs" path = "src/effector.rs"
[dependencies] [dependencies]
fluence = "0.6.4" fluence = "0.6.9"
safe-transmute = "0.11.0" safe-transmute = "0.11.0"

View File

@ -14,5 +14,5 @@ name = "records_passing_pure"
path = "src/pure.rs" path = "src/pure.rs"
[dependencies] [dependencies]
fluence = "0.6.4" fluence = "0.6.9"
safe-transmute = "0.11.0" safe-transmute = "0.11.0"

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine" name = "marine"
description = "Fluence Marine command line tool" description = "Fluence Marine command line tool"
version = "0.6.1" version = "0.6.2"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
repository = "https://github.com/fluencelabs/marine/tools/cli" repository = "https://github.com/fluencelabs/marine/tools/cli"
license = "Apache-2.0" license = "Apache-2.0"

View File

@ -13,7 +13,7 @@ path = "src/main.rs"
[dependencies] [dependencies]
fluence-app-service = { path = "../../fluence-app-service", version = "0.7.1", features = ["raw-module-api"] } 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" anyhow = "1.0.31"
clap = "2.33.1" clap = "2.33.1"