Initial reorg.

This is largely the same as #305, but updated for the current tree.
This commit is contained in:
Dan Gohman
2019-11-07 17:11:06 -08:00
parent 2c69546a24
commit 22641de629
351 changed files with 52 additions and 52 deletions

93
crates/obj/src/context.rs Normal file
View File

@@ -0,0 +1,93 @@
#![allow(clippy::cast_ptr_alignment)]
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::ptr;
use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_entity::EntityRef;
use cranelift_wasm::GlobalInit;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use wasmtime_environ::{Module, TargetSharedSignatureIndex, VMOffsets};
pub struct TableRelocation {
pub index: usize,
pub offset: usize,
}
pub fn layout_vmcontext(
module: &Module,
target_config: &TargetFrontendConfig,
) -> (Box<[u8]>, Box<[TableRelocation]>) {
let ofs = VMOffsets::new(target_config.pointer_bytes(), &module);
let out_len = ofs.size_of_vmctx() as usize;
let mut out = vec![0; out_len];
// Assign unique indicies to unique signatures.
let mut signature_registry = HashMap::new();
let mut signature_registry_len = signature_registry.len();
for (index, sig) in module.signatures.iter() {
let offset = ofs.vmctx_vmshared_signature_id(index) as usize;
let target_index = match signature_registry.entry(sig) {
Entry::Occupied(o) => *o.get(),
Entry::Vacant(v) => {
assert!(signature_registry_len <= ::core::u32::MAX as usize);
let id = TargetSharedSignatureIndex::new(signature_registry_len as u32);
signature_registry_len += 1;
*v.insert(id)
}
};
unsafe {
let to = out.as_mut_ptr().add(offset) as *mut TargetSharedSignatureIndex;
ptr::write(to, target_index);
}
}
let num_tables_imports = module.imported_tables.len();
let mut table_relocs = Vec::with_capacity(module.table_plans.len() - num_tables_imports);
for (index, table) in module.table_plans.iter().skip(num_tables_imports) {
let def_index = module.defined_table_index(index).unwrap();
let offset = ofs.vmctx_vmtable_definition(def_index) as usize;
let current_elements = table.table.minimum;
unsafe {
assert_eq!(
::std::mem::size_of::<u32>() as u8,
ofs.size_of_vmtable_definition_current_elements(),
"vmtable_definition_current_elements expected to be u32"
);
let to = out
.as_mut_ptr()
.add(offset)
.add(ofs.vmtable_definition_current_elements() as usize);
ptr::write(to as *mut u32, current_elements);
}
table_relocs.push(TableRelocation {
index: def_index.index(),
offset,
});
}
let num_globals_imports = module.imported_globals.len();
for (index, global) in module.globals.iter().skip(num_globals_imports) {
let def_index = module.defined_global_index(index).unwrap();
let offset = ofs.vmctx_vmglobal_definition(def_index) as usize;
let to = unsafe { out.as_mut_ptr().add(offset) };
match global.initializer {
GlobalInit::I32Const(x) => unsafe {
ptr::write(to as *mut i32, x);
},
GlobalInit::I64Const(x) => unsafe {
ptr::write(to as *mut i64, x);
},
GlobalInit::F32Const(x) => unsafe {
ptr::write(to as *mut u32, x);
},
GlobalInit::F64Const(x) => unsafe {
ptr::write(to as *mut u64, x);
},
_ => panic!("unsupported global type"),
}
}
(out.into_boxed_slice(), table_relocs.into_boxed_slice())
}

View File

@@ -0,0 +1,28 @@
use alloc::string::String;
use alloc::vec::Vec;
use faerie::{Artifact, Decl};
use wasmtime_environ::DataInitializer;
/// Declares data segment symbol
pub fn declare_data_segment(
obj: &mut Artifact,
_data_initaliazer: &DataInitializer,
index: usize,
) -> Result<(), String> {
let name = format!("_memory_{}", index);
obj.declare(name, Decl::data())
.map_err(|err| format!("{}", err))?;
Ok(())
}
/// Emit segment data and initialization location
pub fn emit_data_segment(
obj: &mut Artifact,
data_initaliazer: &DataInitializer,
index: usize,
) -> Result<(), String> {
let name = format!("_memory_{}", index);
obj.define(name, Vec::from(data_initaliazer.data))
.map_err(|err| format!("{}", err))?;
Ok(())
}

109
crates/obj/src/function.rs Normal file
View File

@@ -0,0 +1,109 @@
use alloc::string::String;
use cranelift_codegen::settings;
use cranelift_codegen::settings::Configurable;
use cranelift_entity::EntityRef;
use faerie::{Artifact, Decl, Link};
use wasmtime_environ::{Compilation, Module, RelocationTarget, Relocations};
fn get_reloc_target_special_import_name(target: RelocationTarget) -> Option<&'static str> {
Some(match target {
RelocationTarget::Memory32Grow => &"wasmtime_memory32_grow",
RelocationTarget::ImportedMemory32Grow => &"wasmtime_memory32_grow",
RelocationTarget::Memory32Size => &"wasmtime_memory32_size",
RelocationTarget::ImportedMemory32Size => &"wasmtime_imported_memory32_size",
_ => return None,
})
}
/// Defines module functions
pub fn declare_functions(
obj: &mut Artifact,
module: &Module,
relocations: &Relocations,
) -> Result<(), String> {
for i in 0..module.imported_funcs.len() {
let string_name = format!("_wasm_function_{}", i);
obj.declare(string_name, Decl::function_import())
.map_err(|err| format!("{}", err))?;
}
for (_, function_relocs) in relocations.iter() {
for r in function_relocs {
let special_import_name = get_reloc_target_special_import_name(r.reloc_target);
if let Some(special_import_name) = special_import_name {
obj.declare(special_import_name, Decl::function_import())
.map_err(|err| format!("{}", err))?;
}
}
}
for (i, _function_relocs) in relocations.iter().rev() {
let func_index = module.func_index(i);
let string_name = format!("_wasm_function_{}", func_index.index());
obj.declare(string_name, Decl::function().global())
.map_err(|err| format!("{}", err))?;
}
Ok(())
}
/// Emits module functions
pub fn emit_functions(
obj: &mut Artifact,
module: &Module,
compilation: &Compilation,
relocations: &Relocations,
) -> Result<(), String> {
debug_assert!(
module.start_func.is_none()
|| module.start_func.unwrap().index() >= module.imported_funcs.len(),
"imported start functions not supported yet"
);
let mut shared_builder = settings::builder();
shared_builder
.enable("enable_verifier")
.expect("Missing enable_verifier setting");
for (i, _function_relocs) in relocations.iter() {
let body = &compilation.get(i).body;
let func_index = module.func_index(i);
let string_name = format!("_wasm_function_{}", func_index.index());
obj.define(string_name, body.clone())
.map_err(|err| format!("{}", err))?;
}
for (i, function_relocs) in relocations.iter() {
let func_index = module.func_index(i);
let string_name = format!("_wasm_function_{}", func_index.index());
for r in function_relocs {
debug_assert_eq!(r.addend, 0);
match r.reloc_target {
RelocationTarget::UserFunc(target_index) => {
let target_name = format!("_wasm_function_{}", target_index.index());
obj.link(Link {
from: &string_name,
to: &target_name,
at: r.offset as u64,
})
.map_err(|err| format!("{}", err))?;
}
RelocationTarget::Memory32Grow
| RelocationTarget::ImportedMemory32Grow
| RelocationTarget::Memory32Size
| RelocationTarget::ImportedMemory32Size => {
obj.link(Link {
from: &string_name,
to: get_reloc_target_special_import_name(r.reloc_target).expect("name"),
at: r.offset as u64,
})
.map_err(|err| format!("{}", err))?;
}
RelocationTarget::JumpTable(_, _) => {
// ignore relocations for jump tables
}
_ => panic!("relocations target not supported yet: {:?}", r.reloc_target),
};
}
}
Ok(())
}

40
crates/obj/src/lib.rs Normal file
View File

@@ -0,0 +1,40 @@
//! Object-file writing library using the wasmtime environment.
#![deny(
missing_docs,
trivial_numeric_casts,
unused_extern_crates,
unstable_features
)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(
feature = "cargo-clippy",
allow(clippy::new_without_default, clippy::new_without_default_derive)
)]
#![cfg_attr(
feature = "cargo-clippy",
warn(
clippy::float_arithmetic,
clippy::mut_mut,
clippy::nonminimal_bool,
clippy::option_map_unwrap_or,
clippy::option_map_unwrap_or_else,
clippy::print_stdout,
clippy::unicode_not_nfc,
clippy::use_self
)
)]
extern crate alloc;
mod context;
mod data_segment;
mod function;
mod module;
mod table;
pub use crate::module::emit_module;
/// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");

63
crates/obj/src/module.rs Normal file
View File

@@ -0,0 +1,63 @@
use crate::context::layout_vmcontext;
use crate::data_segment::{declare_data_segment, emit_data_segment};
use crate::function::{declare_functions, emit_functions};
use crate::table::{declare_table, emit_table};
use alloc::string::String;
use cranelift_codegen::isa::TargetFrontendConfig;
use faerie::{Artifact, Decl, Link};
use wasmtime_environ::{Compilation, DataInitializer, Module, Relocations};
fn emit_vmcontext_init(
obj: &mut Artifact,
module: &Module,
target_config: &TargetFrontendConfig,
) -> Result<(), String> {
let (data, table_relocs) = layout_vmcontext(module, target_config);
obj.declare_with("_vmcontext_init", Decl::data().global(), data.to_vec())
.map_err(|err| format!("{}", err))?;
for reloc in table_relocs.iter() {
let target_name = format!("_table_{}", reloc.index);
obj.link(Link {
from: "_vmcontext_init",
to: &target_name,
at: reloc.offset as u64,
})
.map_err(|err| format!("{}", err))?;
}
Ok(())
}
/// Emits a module that has been emitted with the `wasmtime-environ` environment
/// implementation to a native object file.
pub fn emit_module(
obj: &mut Artifact,
module: &Module,
compilation: &Compilation,
relocations: &Relocations,
data_initializers: &[DataInitializer],
target_config: &TargetFrontendConfig,
) -> Result<(), String> {
declare_functions(obj, module, relocations)?;
for i in 0..data_initializers.len() {
declare_data_segment(obj, &data_initializers[i], i)?;
}
for i in 0..module.table_plans.len() {
declare_table(obj, i)?;
}
emit_functions(obj, module, compilation, relocations)?;
for i in 0..data_initializers.len() {
emit_data_segment(obj, &data_initializers[i], i)?;
}
for i in 0..module.table_plans.len() {
emit_table(obj, i)?;
}
emit_vmcontext_init(obj, module, target_config)?;
Ok(())
}

20
crates/obj/src/table.rs Normal file
View File

@@ -0,0 +1,20 @@
use alloc::string::String;
use alloc::vec::Vec;
use faerie::{Artifact, Decl};
/// Declares data segment symbol
pub fn declare_table(obj: &mut Artifact, index: usize) -> Result<(), String> {
let name = format!("_table_{}", index);
obj.declare(name, Decl::data())
.map_err(|err| format!("{}", err))?;
Ok(())
}
/// Emit segment data and initialization location
pub fn emit_table(obj: &mut Artifact, index: usize) -> Result<(), String> {
let name = format!("_table_{}", index);
// FIXME: We need to initialize table using function symbols
obj.define(name, Vec::new())
.map_err(|err| format!("{}", err))?;
Ok(())
}