Move wasm data/debuginfo into the ELF compilation image (#3235)

* Move wasm data/debuginfo into the ELF compilation image

This commit moves existing allocations of `Box<[u8]>` stored separately
from compilation's final ELF image into the ELF image itself. The goal
of this commit is to reduce the amount of data which `bincode` will need
to process in the future. DWARF debugging information and wasm data
segments can be quite large, and they're relatively rarely read, so
there's typically no need to copy them around. Instead by moving them
into the ELF image this opens up the opportunity in the future to
eliminate copies and use data directly as-found in the image itself.

For information accessed possibly-multiple times, such as the wasm data
ranges, the indexes of the data within the ELF image are computed when
a `CompiledModule` is created. These indexes are then used to directly
index into the image without having to root around in the ELF file each
time they're accessed.

One other change located here is that the symbolication context
previously cloned the debug information into it to adhere to the
`'static` lifetime safely, but this isn't actually ever used in
`wasmtime` right now so the unsafety around this has been removed and
instead borrowed data is returned (no more clones, yay!).

* Fix lightbeam
This commit is contained in:
Alex Crichton
2021-08-25 09:03:07 -05:00
committed by GitHub
parent a662f5361d
commit 7d05ebe7ff
12 changed files with 273 additions and 222 deletions

View File

@@ -6,6 +6,8 @@ use crate::{
StackMap, Tunables, TypeTables, WasmError, WasmFuncType,
};
use anyhow::Result;
use object::write::Object;
use object::{Architecture, BinaryFormat};
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::borrow::Cow;
@@ -184,21 +186,70 @@ pub trait Compiler: Send + Sync {
types: &TypeTables,
) -> Result<Box<dyn Any + Send>, CompileError>;
/// Collects the results of compilation and emits an in-memory ELF object
/// which is the serialized representation of all compiler artifacts.
/// Collects the results of compilation into an in-memory object.
///
/// Note that ELF is used regardless of the target architecture.
/// This function will receive the same `Box<dyn Ayn>` produced as part of
/// `compile_function`, as well as the general compilation environment with
/// the translation/types. This method is expected to populate information
/// in the object file such as:
///
/// * Compiled code in a `.text` section
/// * Unwind information in Wasmtime-specific sections
/// * DWARF debugging information for the host, if `emit_dwarf` is `true`
/// and the compiler supports it.
/// * Relocations, if necessary, for the text section
///
/// The final result of compilation will contain more sections inserted by
/// the compiler-agnostic runtime.
fn emit_obj(
&self,
module: &ModuleTranslation,
types: &TypeTables,
funcs: PrimaryMap<DefinedFuncIndex, Box<dyn Any + Send>>,
emit_dwarf: bool,
) -> Result<(Vec<u8>, PrimaryMap<DefinedFuncIndex, FunctionInfo>)>;
obj: &mut Object,
) -> Result<PrimaryMap<DefinedFuncIndex, FunctionInfo>>;
/// Emits a small ELF object file in-memory which has two functions for the
/// host-to-wasm and wasm-to-host trampolines for the wasm type given.
fn emit_trampoline_obj(&self, ty: &WasmFuncType, host_fn: usize) -> Result<Vec<u8>>;
/// Inserts two functions for host-to-wasm and wasm-to-host trampolines into
/// the `obj` provided.
///
/// This will configure the same sections as `emit_obj`, but will likely be
/// much smaller.
fn emit_trampoline_obj(
&self,
ty: &WasmFuncType,
host_fn: usize,
obj: &mut Object,
) -> Result<()>;
/// Creates a new `Object` file which is used to build the results of a
/// compilation into.
///
/// The returned object file will have an appropriate
/// architecture/endianness for `self.triple()`, but at this time it is
/// always an ELF file, regardless of target platform.
fn object(&self) -> Result<Object> {
use target_lexicon::Architecture::*;
let triple = self.triple();
Ok(Object::new(
BinaryFormat::Elf,
match triple.architecture {
X86_32(_) => Architecture::I386,
X86_64 => Architecture::X86_64,
Arm(_) => Architecture::Arm,
Aarch64(_) => Architecture::Aarch64,
S390x => Architecture::S390x,
architecture => {
anyhow::bail!("target architecture {:?} is unsupported", architecture,);
}
},
match triple.endianness().unwrap() {
target_lexicon::Endianness::Little => object::Endianness::Little,
target_lexicon::Endianness::Big => object::Endianness::Big,
},
))
}
/// Returns the target triple that this compiler is compiling for.
fn triple(&self) -> &target_lexicon::Triple;