diff --git a/.dockerignore b/.dockerignore index e861ea7b6..29fd6ce6b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,5 +2,6 @@ ** !lib/** !src/** +!examples/** !Cargo.toml !Cargo.lock \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a3bcfcd95..fdfb6d8be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## **[Unreleased]** +- [#968](https://github.com/wasmerio/wasmer/pull/968) Added `--invoke` option to the command +- [#971](https://github.com/wasmerio/wasmer/pull/971) In LLVM backend, use unaligned loads and stores for non-atomic accesses to wasmer memory. +- [#960](https://github.com/wasmerio/wasmer/pull/960) Fix `runtime-c-api` header files when compiled by clang. - [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. - [#917](https://github.com/wasmerio/wasmer/pull/917) Host functions (aka imported functions) may not have `&mut vm::Ctx` as first argument, i.e. the presence of the `&mut vm::Ctx` argument is optional. - [#915](https://github.com/wasmerio/wasmer/pull/915) All backends share the same definition of `Trampoline` (defined in `wasmer-runtime-core`). diff --git a/Dockerfile b/Dockerfile index 43fcda359..6affe470f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM circleci/rust:1.33.0-stretch as wasmer-build-env +FROM circleci/rust:1.38.0-stretch as wasmer-build-env RUN sudo apt-get update && \ sudo apt-get install -y --no-install-recommends \ cmake \ @@ -22,4 +22,4 @@ RUN cargo build --release FROM debian:stretch AS wasmer WORKDIR /root/ COPY --from=wasmer-build /home/circleci/wasmer/target/release/wasmer . -ENTRYPOINT ["./wasmer"] \ No newline at end of file +ENTRYPOINT ["./wasmer"] diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 1bd1958e3..d86d19b4f 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -54,6 +54,10 @@ impl ModuleCodeGenerator } } + fn new_with_target(_: Option, _: Option, _: Option) -> Self { + unimplemented!("cross compilation is not available for clif backend") + } + fn backend_id() -> Backend { Backend::Cranelift } diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index b2f5b62d9..0aca84650 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -4469,6 +4469,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4492,6 +4497,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4515,6 +4525,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4538,6 +4553,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4561,6 +4581,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 16, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4586,6 +4611,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let store = builder.build_store(effective_address, value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64Store { ref memarg } => { @@ -4603,6 +4629,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let store = builder.build_store(effective_address, value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::F32Store { ref memarg } => { @@ -4621,6 +4648,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let store = builder.build_store(effective_address, v); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::F64Store { ref memarg } => { @@ -4639,6 +4667,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let store = builder.build_store(effective_address, v); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::V128Store { ref memarg } => { @@ -4657,6 +4686,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 16, )?; let store = builder.build_store(effective_address, v); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32Load8S { ref memarg } => { @@ -4672,9 +4702,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i8_ptr_ty, 1, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4682,8 +4715,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let result = builder.build_int_s_extend( + narrow_result.into_int_value(), + intrinsics.i32_ty, + &state.var_name(), + ); state.push1(result); } Operator::I32Load16S { ref memarg } => { @@ -4700,6 +4736,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 2, )?; let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4730,6 +4771,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4757,6 +4803,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4781,9 +4832,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i32_ptr_ty, 4, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4791,8 +4845,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let result = builder.build_int_s_extend( + narrow_result.into_int_value(), + intrinsics.i64_ty, + &state.var_name(), + ); state.push1(result); } @@ -4809,9 +4866,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i8_ptr_ty, 1, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4819,8 +4879,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i32_ty, + &state.var_name(), + ); state.push1(result); } Operator::I32Load16U { ref memarg } => { @@ -4836,9 +4899,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i16_ptr_ty, 2, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4846,8 +4912,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i32_ty, + &state.var_name(), + ); state.push1(result); } Operator::I64Load8U { ref memarg } => { @@ -4863,9 +4932,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i8_ptr_ty, 1, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4873,8 +4945,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i64_ty, + &state.var_name(), + ); state.push1(result); } Operator::I64Load16U { ref memarg } => { @@ -4890,9 +4965,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i16_ptr_ty, 2, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4900,8 +4978,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i64_ty, + &state.var_name(), + ); state.push1(result); } Operator::I64Load32U { ref memarg } => { @@ -4917,9 +4998,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i32_ptr_ty, 4, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4927,8 +5011,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i64_ty, + &state.var_name(), + ); state.push1(result); } @@ -4949,6 +5036,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_value = builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32Store16 { ref memarg } | Operator::I64Store16 { ref memarg } => { @@ -4968,6 +5056,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_value = builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64Store32 { ref memarg } => { @@ -4987,6 +5076,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_value = builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I8x16Neg => { @@ -5291,6 +5381,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 1, )?; let elem = builder.build_load(effective_address, ""); + elem.as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -5322,6 +5416,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 2, )?; let elem = builder.build_load(effective_address, ""); + elem.as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -5353,6 +5451,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let elem = builder.build_load(effective_address, ""); + elem.as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -5384,6 +5486,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let elem = builder.build_load(effective_address, ""); + elem.as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -7969,24 +8075,37 @@ impl ModuleCodeGenerator for LLVMModuleCodeGenerator { fn new() -> LLVMModuleCodeGenerator { + Self::new_with_target(None, None, None) + } + + fn new_with_target( + triple: Option, + cpu_name: Option, + cpu_features: Option, + ) -> LLVMModuleCodeGenerator { let context = Context::create(); let module = context.create_module("module"); - Target::initialize_x86(&InitializationConfig { - asm_parser: true, - asm_printer: true, - base: true, - disassembler: true, - info: true, - machine_code: true, - }); - let triple = TargetMachine::get_default_triple().to_string(); + let triple = triple.unwrap_or(TargetMachine::get_default_triple().to_string()); + + match triple { + _ if triple.starts_with("x86") => Target::initialize_x86(&InitializationConfig { + asm_parser: true, + asm_printer: true, + base: true, + disassembler: true, + info: true, + machine_code: true, + }), + _ => unimplemented!("compile to target other than x86-64 is not supported"), + } + let target = Target::from_triple(&triple).unwrap(); let target_machine = target .create_target_machine( &triple, - &TargetMachine::get_host_cpu_name().to_string(), - &TargetMachine::get_host_cpu_features().to_string(), + &cpu_name.unwrap_or(TargetMachine::get_host_cpu_name().to_string()), + &cpu_features.unwrap_or(TargetMachine::get_host_cpu_features().to_string()), OptimizationLevel::Aggressive, RelocMode::Static, CodeModel::Large, diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs index 7c518398c..7750b0081 100644 --- a/lib/runtime-c-api/build.rs +++ b/lib/runtime-c-api/build.rs @@ -13,19 +13,21 @@ fn main() { out_wasmer_header_file.push("wasmer"); const WASMER_PRE_HEADER: &str = r#" -#ifndef WASMER_H_MACROS +#if !defined(WASMER_H_MACROS) #define WASMER_H_MACROS -#if MSVC -#ifdef _M_AMD64 + +#if defined(MSVC) +#if defined(_M_AMD64) #define ARCH_X86_64 #endif #endif -#if GCC -#ifdef __x86_64__ +#if defined(GCC) || defined(__clang__) +#if defined(__x86_64__) #define ARCH_X86_64 #endif #endif + #endif // WASMER_H_MACROS "#; // Generate the C bindings in the `OUT_DIR`. diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index bc4a3ed4f..836a41df2 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -1,17 +1,19 @@ -#ifndef WASMER_H_MACROS +#if !defined(WASMER_H_MACROS) #define WASMER_H_MACROS -#if MSVC -#ifdef _M_AMD64 + +#if defined(MSVC) +#if defined(_M_AMD64) #define ARCH_X86_64 #endif #endif -#if GCC -#ifdef __x86_64__ +#if defined(GCC) || defined(__clang__) +#if defined(__x86_64__) #define ARCH_X86_64 #endif #endif + #endif // WASMER_H_MACROS diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index acf4b20e7..79c350d60 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -1,17 +1,19 @@ -#ifndef WASMER_H_MACROS +#if !defined(WASMER_H_MACROS) #define WASMER_H_MACROS -#if MSVC -#ifdef _M_AMD64 + +#if defined(MSVC) +#if defined(_M_AMD64) #define ARCH_X86_64 #endif #endif -#if GCC -#ifdef __x86_64__ +#if defined(GCC) || defined(__clang__) +#if defined(__x86_64__) #define ARCH_X86_64 #endif #endif + #endif // WASMER_H_MACROS diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 3c78cce8b..df4ef7751 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -205,6 +205,11 @@ pub struct CompilerConfig { pub enforce_stack_check: bool, pub track_state: bool, pub features: Features, + + // target info used by LLVM + pub triple: Option, + pub cpu_name: Option, + pub cpu_features: Option, } pub trait Compiler { diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 2fdd20482..7e8aedd48 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -75,6 +75,13 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, /// Creates a new module code generator. fn new() -> Self; + /// Creates a new module code generator for specified target. + fn new_with_target( + triple: Option, + cpu_name: Option, + cpu_features: Option, + ) -> Self; + /// Returns the backend id associated with this MCG. fn backend_id() -> Backend; @@ -207,7 +214,14 @@ impl< validate_with_features(wasm, &compiler_config.features)?; } - let mut mcg = MCG::new(); + let mut mcg = match MCG::backend_id() { + Backend::LLVM => MCG::new_with_target( + compiler_config.triple.clone(), + compiler_config.cpu_name.clone(), + compiler_config.cpu_features.clone(), + ), + _ => MCG::new(), + }; let mut chain = (self.middleware_chain_generator)(); let info = crate::parse::read_module( wasm, diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index fe39b512a..7cc4386af 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -1,3 +1,7 @@ +//! The cache module provides the common data structures used by compiler backends to allow +//! serializing compiled wasm code to a binary format. The binary format can be persisted, +//! and loaded to allow skipping compilation and fast startup. + use crate::Module; use memmap::Mmap; use std::{ diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index aedd938ae..ad47226fd 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -1,5 +1,6 @@ #![deny( dead_code, + missing_docs, nonstandard_style, unused_imports, unused_mut, @@ -104,6 +105,8 @@ pub use wasmer_runtime_core::{compile_with, validate}; pub use wasmer_runtime_core::{func, imports}; pub mod memory { + //! The memory module contains the implementation data structures and helper functions used to + //! manipulate and access wasm memory. pub use wasmer_runtime_core::memory::{Atomically, Memory, MemoryView}; } @@ -117,6 +120,8 @@ pub mod wasm { } pub mod error { + //! The error module contains the data structures and helper functions used to implement errors that + //! are produced and returned from the wasmer runtime. pub use wasmer_runtime_core::cache::Error as CacheError; pub use wasmer_runtime_core::error::*; } diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index e57eaecad..c06217964 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -483,6 +483,10 @@ impl ModuleCodeGenerator } } + fn new_with_target(_: Option, _: Option, _: Option) -> Self { + unimplemented!("cross compilation is not available for singlepass backend") + } + fn backend_id() -> Backend { Backend::Singlepass } diff --git a/src/bin/kwasmd.rs b/src/bin/kwasmd.rs index 62e22b731..79949417b 100644 --- a/src/bin/kwasmd.rs +++ b/src/bin/kwasmd.rs @@ -63,6 +63,7 @@ fn handle_client(mut stream: UnixStream) { enforce_stack_check: true, track_state: false, features: Default::default(), + ..Default::default() }, &SinglePassCompiler::new(), ) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index edf42faaa..340669f68 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -130,6 +130,10 @@ struct Run { )] backend: Backend, + /// Invoke a specified function + #[structopt(long = "invoke", short = "i")] + invoke: Option, + /// Emscripten symbol map #[structopt(long = "em-symbol-map", parse(from_os_str), group = "emscripten")] em_symbol_map: Option, @@ -449,6 +453,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { simd: options.features.simd || options.features.all, threads: options.features.threads || options.features.all, }, + ..Default::default() }, &*compiler, ) @@ -714,8 +719,12 @@ fn execute_wasm(options: &Run) -> Result<(), String> { args.push(Value::I32(x)); } - let result = instance - .dyn_func("main") + let invoke_fn = match options.invoke.as_ref() { + Some(fun) => fun, + _ => "main", + }; + instance + .dyn_func(&invoke_fn) .map_err(|e| format!("{:?}", e))? .call(&args) .map_err(|e| format!("{:?}", e))?;