Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental Native Compilation Refactor #2272

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b2a41a7
WIP of LLVM metadata as a function generator
syrusakbary Apr 26, 2021
438ded1
Merge branch 'middleware-refactor' into llvm-traps
syrusakbary Apr 27, 2021
cc74ba6
Merge branch 'master' into llvm-traps
syrusakbary Apr 27, 2021
fe05ed0
First working iteration of proper Native loading
syrusakbary Apr 29, 2021
6d1ca9e
Refactored struct representation of experimental native compilation
syrusakbary Apr 29, 2021
69f716d
Fixed linting issues
syrusakbary Apr 29, 2021
5fa5379
Update lib/compiler/src/compiler.rs
syrusakbary Apr 29, 2021
5ca3d84
Update lib/compiler-llvm/src/compiler.rs
syrusakbary Apr 30, 2021
7f726ca
Update wasmparser
syrusakbary Apr 30, 2021
b97139a
Merge branch 'llvm-traps' of github.com:wasmerio/wasmer into llvm-traps
syrusakbary Apr 30, 2021
f1d649d
Improved create-exe
syrusakbary Apr 30, 2021
ca0da94
Merge branch 'master' into llvm-traps
syrusakbary Apr 30, 2021
91e24f0
Merge branch 'universal-compiled-info' into llvm-traps
syrusakbary Apr 30, 2021
e845d45
Updated serialization mechanism
syrusakbary Apr 30, 2021
b37981b
Attach frame info registration in native and object-file engine
syrusakbary Apr 30, 2021
727ec5a
Merge branch 'master' into llvm-traps
syrusakbary Apr 30, 2021
26235a7
Update lib/engine-native/src/serialize.rs
syrusakbary May 3, 2021
37e566d
Update lib/compiler-llvm/src/object_file.rs
syrusakbary May 3, 2021
bd84b4c
Update lib/engine-native/src/artifact.rs
syrusakbary May 3, 2021
32f0e34
Update lib/compiler-llvm/src/object_file.rs
syrusakbary May 3, 2021
19ef939
Update lib/compiler-llvm/src/object_file.rs
syrusakbary May 3, 2021
cc2cc77
Update lib/engine-object-file/src/artifact.rs
syrusakbary May 3, 2021
6eb7084
Improvoed comment
syrusakbary May 3, 2021
555b16f
Reuse variable
syrusakbary May 3, 2021
c352602
Fixed function body sizes
syrusakbary May 4, 2021
b183538
Update indexmap version
syrusakbary May 4, 2021
e73ebb1
Merge branch 'master' into llvm-traps
syrusakbary May 4, 2021
8aa7247
Fixed duplicated imports
syrusakbary May 4, 2021
17b3b8e
Update lib/engine-object-file/src/artifact.rs
syrusakbary May 5, 2021
fe3210a
Update lib/engine-native/src/artifact.rs
syrusakbary May 5, 2021
355134e
Update lib/engine-native/src/artifact.rs
syrusakbary May 5, 2021
1deb551
Merge branch 'master' into llvm-traps
syrusakbary May 12, 2021
f86597e
Added check for wasm pc (so we only trap on Wasm functions)
syrusakbary May 13, 2021
6d02377
Addressed all comments
syrusakbary May 13, 2021
d3a8d0b
Make objectfile the same for windows and unix
syrusakbary May 13, 2021
d3c856b
Improve readability of frameinfo
syrusakbary May 13, 2021
b900b5b
Merge branch 'master' into llvm-traps
syrusakbary May 24, 2021
374da7b
Fixed compilation issue with data
syrusakbary May 24, 2021
cd17339
Remove endianess check in engines
syrusakbary May 24, 2021
360af93
Merge branch 'llvm-traps' of https://github.com/wasmerio/wasmer into …
syrusakbary May 24, 2021
067391c
Fixed linting
syrusakbary May 24, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ wasmer-engine = { path = "../engine", version = "1.0.2" }
wasmer-engine-jit = { path = "../engine-jit", version = "1.0.2", optional = true }
wasmer-engine-native = { path = "../engine-native", version = "1.0.2", optional = true }
wasmer-types = { path = "../types", version = "1.0.2" }
indexmap = { version = "1.4", features = ["serde-1"] }
indexmap = { version = "1.6", features = ["serde-1"] }
cfg-if = "0.1"
wat = { version = "1.0", optional = true }
thiserror = "1.0"
Expand Down
27 changes: 23 additions & 4 deletions lib/cli/src/commands/create_exe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ impl CreateExe {
env::set_current_dir(&working_dir)?;

#[cfg(not(windows))]
let wasm_object_path = PathBuf::from("wasm.o");
let wasm_object_path = PathBuf::from("wasm.a");
#[cfg(windows)]
let wasm_object_path = PathBuf::from("wasm.obj");
let wasm_object_path = PathBuf::from("wasm.a");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer need windows/non-windows here since they're the same.


let wasm_module_path = starting_cd.join(&self.path);

Expand Down Expand Up @@ -284,23 +284,42 @@ impl LinkCode {
} else {
command
};

// Add libraries required per platform.
// We need userenv, sockets (Ws2_32), advapi32 for some system calls and bcrypt for random numbers.
#[cfg(windows)]
let command = command
.arg("-Wl,--whole-archive")
.arg("-luserenv")
.arg("-lWs2_32")
.arg("-ladvapi32")
.arg("-lbcrypt");
// On unix we need dlopen-related symbols, libmath for a few things, and pthreads.

cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] {
let command = command.arg("-Wl,-all_load");
}
else if #[cfg(unix)] {
let command = command.arg("-Wl,--whole-archive");
}
else if #[cfg(windows)] {
let command = command.arg("-Wl,--whole-archive");
}
}

#[cfg(not(windows))]
let command = command.arg("-ldl").arg("-lm").arg("-pthread");
let link_aganist_extra_libs = self
.additional_libraries
.iter()
.map(|lib| format!("-l{}", lib));
let command = command.args(link_aganist_extra_libs);
let output = command.arg("-o").arg(&self.output_path).output()?;
let command = command
.args(link_aganist_extra_libs)
.arg("-o")
.arg(&self.output_path);
println!("COMMAND: {:?}", command);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Remove

let output = command.output()?;

if !output.status.success() {
bail!(
Expand Down
182 changes: 80 additions & 102 deletions lib/compiler-llvm/src/compiler.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
use crate::config::LLVM;
use crate::object_file::get_frame_info;
use crate::trampoline::FuncTrampoline;
use crate::translator::FuncTranslator;
use crate::CompiledKind;
use inkwell::context::Context;
use inkwell::memory_buffer::MemoryBuffer;
use inkwell::module::{Linkage, Module};
use inkwell::targets::FileType;
use inkwell::DLLStorageClass;
use loupe::MemoryUsage;
use rayon::iter::ParallelBridge;
use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use std::sync::Arc;
use wasmer_compiler::{
Compilation, CompileError, CompileModuleInfo, Compiler, CustomSection, CustomSectionProtection,
Dwarf, FunctionBodyData, ModuleMiddleware, ModuleTranslationState, RelocationTarget,
SectionBody, SectionIndex, Symbol, SymbolRegistry, Target,
Compilation, CompileError, CompileModuleInfo, CompiledFunctionFrameInfo, Compiler,
CustomSection, CustomSectionProtection, Dwarf, ExperimentalNativeCompilation, FunctionBodyData,
ModuleMiddleware, ModuleTranslationState, RelocationTarget, SectionBody, SectionIndex, Symbol,
SymbolRegistry, Target,
};
use wasmer_types::entity::{EntityRef, PrimaryMap};
use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex};
Expand Down Expand Up @@ -80,110 +77,94 @@ impl LLVMCompiler {
module_translation: &ModuleTranslationState,
function_body_inputs: &PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
symbol_registry: &dyn SymbolRegistry,
wasmer_metadata: &[u8],
) -> Result<Vec<u8>, CompileError> {
let target_machine = self.config().target_machine(target);
let ctx = Context::create();

) -> Result<ExperimentalNativeCompilation, CompileError> {
// TODO: https:/github.com/rayon-rs/rayon/issues/822

let merged_bitcode = function_body_inputs.into_iter().par_bridge().map_init(
|| {
let target_machine = self.config().target_machine(target);
FuncTranslator::new(target_machine)
},
|func_translator, (i, input)| {
let module = func_translator.translate_to_module(
&compile_info.module,
module_translation,
&i,
input,
self.config(),
&compile_info.memory_styles,
&compile_info.table_styles,
symbol_registry,
)?;
Ok(module.write_bitcode_to_memory().as_slice().to_vec())
},
);
let function_bodies_and_frame_infos = function_body_inputs
.into_iter()
.par_bridge()
.map_init(
|| {
let target_machine = self.config().target_machine(target);
FuncTranslator::new(target_machine)
},
|func_translator, (i, input)| {
let module = func_translator.translate_to_module(
&compile_info.module,
module_translation,
&i,
input,
self.config(),
&compile_info.memory_styles,
&compile_info.table_styles,
symbol_registry,
)?;
let memory_buffer = func_translator
.target_machine
.write_to_memory_buffer(&module, FileType::Object)
.unwrap();
let memory_buffer = memory_buffer.as_slice().to_vec();
let frame_info = get_frame_info(&memory_buffer)?;
Ok((memory_buffer, frame_info))
},
)
.collect::<Result<Vec<_>, CompileError>>()?;

let (function_bodies, frame_infos): (Vec<Vec<u8>>, Vec<CompiledFunctionFrameInfo>) =
function_bodies_and_frame_infos.into_iter().unzip();
let function_bodies = function_bodies.into_iter().par_bridge().map(|b| Ok(b));

let trampolines_bitcode = compile_info.module.signatures.iter().par_bridge().map_init(
let frame_infos = frame_infos
.into_iter()
.collect::<PrimaryMap<LocalFunctionIndex, CompiledFunctionFrameInfo>>();
let trampolines = compile_info.module.signatures.iter().par_bridge().map_init(
|| {
let target_machine = self.config().target_machine(target);
FuncTrampoline::new(target_machine)
},
|func_trampoline, (i, sig)| {
let name = symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(i));
let symbol = Symbol::FunctionCallTrampoline(i);
let name = symbol_registry.symbol_to_name(symbol);
let module = func_trampoline.trampoline_to_module(sig, self.config(), &name)?;
Ok(module.write_bitcode_to_memory().as_slice().to_vec())
let memory_buffer = func_trampoline
.target_machine
.write_to_memory_buffer(&module, FileType::Object)
.unwrap();
Ok(memory_buffer.as_slice().to_vec())
},
);

let dynamic_trampolines_bitcode =
compile_info.module.functions.iter().par_bridge().map_init(
|| {
let target_machine = self.config().target_machine(target);
(
FuncTrampoline::new(target_machine),
&compile_info.module.signatures,
)
},
|(func_trampoline, signatures), (i, sig)| {
let sig = &signatures[*sig];
let name = symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(i));
let module =
func_trampoline.dynamic_trampoline_to_module(sig, self.config(), &name)?;
Ok(module.write_bitcode_to_memory().as_slice().to_vec())
},
);

let merged_bitcode = merged_bitcode
.chain(trampolines_bitcode)
.chain(dynamic_trampolines_bitcode)
.collect::<Result<Vec<_>, CompileError>>()?
.into_par_iter()
.reduce_with(|bc1, bc2| {
let ctx = Context::create();
let membuf = MemoryBuffer::create_from_memory_range(&bc1, "");
let m1 = Module::parse_bitcode_from_buffer(&membuf, &ctx).unwrap();
let membuf = MemoryBuffer::create_from_memory_range(&bc2, "");
let m2 = Module::parse_bitcode_from_buffer(&membuf, &ctx).unwrap();
m1.link_in_module(m2).unwrap();
m1.write_bitcode_to_memory().as_slice().to_vec()
});
let merged_module = if let Some(bc) = merged_bitcode {
let membuf = MemoryBuffer::create_from_memory_range(&bc, "");
Module::parse_bitcode_from_buffer(&membuf, &ctx).unwrap()
} else {
ctx.create_module("")
};

let i8_ty = ctx.i8_type();
let metadata_init = i8_ty.const_array(
wasmer_metadata
.iter()
.map(|v| i8_ty.const_int(*v as u64, false))
.collect::<Vec<_>>()
.as_slice(),
let dynamic_trampolines = compile_info.module.functions.iter().par_bridge().map_init(
|| {
let target_machine = self.config().target_machine(target);
(
FuncTrampoline::new(target_machine),
&compile_info.module.signatures,
)
},
|(func_trampoline, signatures), (i, sig)| {
let sig = &signatures[*sig];
let symbol = Symbol::DynamicFunctionTrampoline(i);
let name = symbol_registry.symbol_to_name(symbol);
let module =
func_trampoline.dynamic_trampoline_to_module(sig, self.config(), &name)?;
let memory_buffer = func_trampoline
.target_machine
.write_to_memory_buffer(&module, FileType::Object)
.unwrap();
Ok(memory_buffer.as_slice().to_vec())
},
);
let metadata_gv =
merged_module.add_global(metadata_init.get_type(), None, "WASMER_METADATA");
metadata_gv.set_initializer(&metadata_init);
metadata_gv.set_linkage(Linkage::DLLExport);
metadata_gv.set_dll_storage_class(DLLStorageClass::Export);

if self.config().enable_verifier {
merged_module.verify().unwrap();
}

let memory_buffer = target_machine
.write_to_memory_buffer(&merged_module, FileType::Object)
.unwrap();
if let Some(ref callbacks) = self.config.callbacks {
callbacks.obj_memory_buffer(&CompiledKind::Module, &memory_buffer);
}
let object_files = function_bodies
.chain(trampolines)
.chain(dynamic_trampolines)
.collect::<Result<Vec<_>, CompileError>>()?;

Ok(memory_buffer.as_slice().to_vec())
Ok(ExperimentalNativeCompilation {
object_files,
frame_infos,
})
}
}

Expand All @@ -201,16 +182,13 @@ impl Compiler for LLVMCompiler {
// The list of function bodies
function_body_inputs: &PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
symbol_registry: &dyn SymbolRegistry,
// The metadata to inject into the wasmer_metadata section of the object file.
wasmer_metadata: &[u8],
) -> Option<Result<Vec<u8>, CompileError>> {
) -> Option<Result<ExperimentalNativeCompilation, CompileError>> {
Some(self.compile_native_object(
target,
compile_info,
module_translation,
function_body_inputs,
symbol_registry,
wasmer_metadata,
))
}

Expand Down
37 changes: 37 additions & 0 deletions lib/compiler-llvm/src/object_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use std::num::TryFromIntError;

use crate::translator::FUNCTION_SECTION_NAME;
use wasmer_compiler::{
CompileError, CompiledFunctionFrameInfo, CustomSection, CustomSectionProtection,
CustomSections, FunctionAddressMap, FunctionBody, InstructionAddressMap, Relocation,
Expand All @@ -20,12 +21,48 @@ fn map_object_err(error: object::read::Error) -> CompileError {
CompileError::Codegen(format!("error parsing object file: {}", error))
}

fn map_object_err(error: object::read::Error) -> CompileError {
CompileError::Codegen(format!("error parsing object file: {}", error))
}

pub struct CompiledFunction {
pub compiled_function: wasmer_compiler::CompiledFunction,
pub custom_sections: CustomSections,
pub eh_frame_section_indices: Vec<SectionIndex>,
}

pub fn get_function_body_size(data: &[u8]) -> Result<u64, CompileError> {
use object::{Object, ObjectSection};

let in_object = object::File::parse(&data).map_err(map_object_err)?;
let section = in_object.section_by_name(FUNCTION_SECTION_NAME);
match section {
Some(section) => Ok(section.size()),
None => Ok(0),
}
}

/// Get the frame information from an object file.
pub fn get_frame_info(contents: &[u8]) -> Result<CompiledFunctionFrameInfo, CompileError> {
let function_length = get_function_body_size(contents)? as usize;
let address_map = FunctionAddressMap {
instructions: vec![InstructionAddressMap {
srcloc: SourceLoc::default(),
code_offset: 0,
code_len: function_length,
}],
start_srcloc: SourceLoc::default(),
end_srcloc: SourceLoc::default(),
body_offset: 0,
body_len: function_length,
};

Ok(CompiledFunctionFrameInfo {
address_map,
traps: vec![],
})
}

pub fn load_object_file<F>(
contents: &[u8],
root_section: &str,
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler-llvm/src/trampoline/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use wasmer_types::{FunctionType, LocalFunctionIndex};

pub struct FuncTrampoline {
ctx: Context,
target_machine: TargetMachine,
pub(crate) target_machine: TargetMachine,
abi: Box<dyn Abi>,
}

Expand Down
Loading