Merge master and add documentation.

This commit is contained in:
losfair
2019-11-13 14:52:22 +08:00
74 changed files with 1782 additions and 489 deletions

View File

@ -1,121 +1,195 @@
use crate::backend::Backend;
//! The state module is used to track state of a running web assembly instances so that
//! state could read or updated at runtime. Use cases include generating stack traces, switching
//! generated code from one tier to another, or serializing state of a running instace.
use std::collections::BTreeMap;
use std::ops::Bound::{Included, Unbounded};
use crate::backend::Backend;
/// An index to a register
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct RegisterIndex(pub usize);
/// A kind of wasm or constant value
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum WasmAbstractValue {
/// A wasm runtime value
Runtime,
/// A wasm constant value
Const(u64),
}
/// A container for the state of a running wasm instance.
#[derive(Clone, Debug)]
pub struct MachineState {
/// Stack values.
pub stack_values: Vec<MachineValue>,
/// Register values.
pub register_values: Vec<MachineValue>,
/// Previous frame.
pub prev_frame: BTreeMap<usize, MachineValue>,
/// Wasm stack.
pub wasm_stack: Vec<WasmAbstractValue>,
/// Private depth of the wasm stack.
pub wasm_stack_private_depth: usize,
/// Wasm instruction offset.
pub wasm_inst_offset: usize,
}
/// A diff of two `MachineState`s.
#[derive(Clone, Debug, Default)]
pub struct MachineStateDiff {
/// Last.
pub last: Option<usize>,
/// Stack push.
pub stack_push: Vec<MachineValue>,
/// Stack pop.
pub stack_pop: usize,
/// Register diff.
pub reg_diff: Vec<(RegisterIndex, MachineValue)>,
/// Previous frame diff.
pub prev_frame_diff: BTreeMap<usize, Option<MachineValue>>, // None for removal
/// Wasm stack push.
pub wasm_stack_push: Vec<WasmAbstractValue>,
/// Wasm stack pop.
pub wasm_stack_pop: usize,
/// Private depth of the wasm stack.
pub wasm_stack_private_depth: usize, // absolute value; not a diff.
/// Wasm instruction offset.
pub wasm_inst_offset: usize, // absolute value; not a diff.
}
/// A kind of machine value.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum MachineValue {
/// Undefined.
Undefined,
/// Vmctx.
Vmctx,
/// Vmctx Deref.
VmctxDeref(Vec<usize>),
/// Preserve Register.
PreserveRegister(RegisterIndex),
/// Copy Stack BP Relative.
CopyStackBPRelative(i32), // relative to Base Pointer, in byte offset
ExplicitShadow, // indicates that all values above this are above the shadow region
/// Explicit Shadow.
ExplicitShadow, // indicates that all values above this are above the shadow region
/// Wasm Stack.
WasmStack(usize),
/// Wasm Local.
WasmLocal(usize),
/// Two Halves.
TwoHalves(Box<(MachineValue, MachineValue)>), // 32-bit values. TODO: optimize: add another type for inner "half" value to avoid boxing?
}
/// A map of function states.
#[derive(Clone, Debug)]
pub struct FunctionStateMap {
/// Initial.
pub initial: MachineState,
/// Local Function Id.
pub local_function_id: usize,
/// Locals.
pub locals: Vec<WasmAbstractValue>,
/// Shadow size.
pub shadow_size: usize, // for single-pass backend, 32 bytes on x86-64
/// Diffs.
pub diffs: Vec<MachineStateDiff>,
/// Wasm Function Header target offset.
pub wasm_function_header_target_offset: Option<SuspendOffset>,
/// Wasm offset to target offset
pub wasm_offset_to_target_offset: BTreeMap<usize, SuspendOffset>,
/// Loop offsets.
pub loop_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
/// Call offsets.
pub call_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
/// Trappable offsets.
pub trappable_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
}
/// A kind of suspend offset.
#[derive(Clone, Copy, Debug)]
pub enum SuspendOffset {
/// A loop.
Loop(usize),
/// A call.
Call(usize),
/// A trappable.
Trappable(usize),
}
/// Info for an offset.
#[derive(Clone, Debug)]
pub struct OffsetInfo {
/// End offset.
pub end_offset: usize, // excluded bound
/// Diff Id.
pub diff_id: usize,
/// Activate offset.
pub activate_offset: usize,
}
/// A map of module state.
#[derive(Clone, Debug)]
pub struct ModuleStateMap {
/// Local functions.
pub local_functions: BTreeMap<usize, FunctionStateMap>,
/// Total size.
pub total_size: usize,
}
/// State dump of a wasm function.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WasmFunctionStateDump {
/// Local function id.
pub local_function_id: usize,
/// Wasm instruction offset.
pub wasm_inst_offset: usize,
/// Stack.
pub stack: Vec<Option<u64>>,
/// Locals.
pub locals: Vec<Option<u64>>,
}
/// An image of the execution state.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ExecutionStateImage {
/// Frames.
pub frames: Vec<WasmFunctionStateDump>,
}
/// Represents an image of an `Instance` including its memory, globals, and execution state.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InstanceImage {
/// Memory for this `InstanceImage`
pub memory: Option<Vec<u8>>,
/// Stored globals for this `InstanceImage`
pub globals: Vec<u128>,
/// `ExecutionStateImage` for this `InstanceImage`
pub execution_state: ExecutionStateImage,
}
/// A `CodeVersion` is a container for a unit of generated code for a module.
#[derive(Debug, Clone)]
pub struct CodeVersion {
/// Indicates if this code version is the baseline version.
pub baseline: bool,
/// `ModuleStateMap` for this code version.
pub msm: ModuleStateMap,
/// A pointer to the machine code for this module.
pub base: usize,
/// The backend used to compile this module.
pub backend: Backend,
}
impl ModuleStateMap {
/// Looks up an ip from self using the given ip, base, and offset table provider.
pub fn lookup_ip<F: FnOnce(&FunctionStateMap) -> &BTreeMap<usize, OffsetInfo>>(
&self,
ip: usize,
@ -148,6 +222,7 @@ impl ModuleStateMap {
}
}
}
/// Looks up a call ip from self using the given ip and base values.
pub fn lookup_call_ip(
&self,
ip: usize,
@ -156,6 +231,7 @@ impl ModuleStateMap {
self.lookup_ip(ip, base, |fsm| &fsm.call_offsets)
}
/// Looks up a trappable ip from self using the given ip and base values.
pub fn lookup_trappable_ip(
&self,
ip: usize,
@ -164,6 +240,7 @@ impl ModuleStateMap {
self.lookup_ip(ip, base, |fsm| &fsm.trappable_offsets)
}
/// Looks up a loop ip from self using the given ip and base values.
pub fn lookup_loop_ip(
&self,
ip: usize,
@ -174,6 +251,7 @@ impl ModuleStateMap {
}
impl FunctionStateMap {
/// Creates a new `FunctionStateMap` with the given parameters.
pub fn new(
initial: MachineState,
local_function_id: usize,
@ -196,6 +274,7 @@ impl FunctionStateMap {
}
impl MachineState {
/// Creates a `MachineStateDiff` from self and the given `&MachineState`.
pub fn diff(&self, old: &MachineState) -> MachineStateDiff {
let first_diff_stack_depth: usize = self
.stack_values
@ -258,6 +337,7 @@ impl MachineState {
}
impl MachineStateDiff {
/// Creates a `MachineState` from the given `&FunctionStateMap`.
pub fn build_state(&self, m: &FunctionStateMap) -> MachineState {
let mut chain: Vec<&MachineStateDiff> = vec![];
chain.push(self);
@ -300,6 +380,7 @@ impl MachineStateDiff {
}
impl ExecutionStateImage {
/// Prints a backtrace if the `WASMER_BACKTRACE` environment variable is 1.
pub fn print_backtrace_if_needed(&self) {
use std::env;
@ -313,6 +394,7 @@ impl ExecutionStateImage {
eprintln!("Run with `WASMER_BACKTRACE=1` environment variable to display a backtrace.");
}
/// Converts self into a `String`, used for display purposes.
pub fn output(&self) -> String {
fn join_strings(x: impl Iterator<Item = String>, sep: &str) -> String {
let mut ret = String::new();
@ -378,6 +460,7 @@ impl ExecutionStateImage {
}
impl InstanceImage {
/// Converts a slice of bytes into an `Option<InstanceImage>`
pub fn from_bytes(input: &[u8]) -> Option<InstanceImage> {
use bincode::deserialize;
match deserialize(input) {
@ -386,63 +469,104 @@ impl InstanceImage {
}
}
/// Converts self into a vector of bytes.
pub fn to_bytes(&self) -> Vec<u8> {
use bincode::serialize;
serialize(self).unwrap()
}
}
/// Declarations for x86-64 registers.
pub mod x64_decl {
use super::*;
/// General-purpose registers.
#[repr(u8)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum GPR {
/// RAX register
RAX,
/// RCX register
RCX,
/// RDX register
RDX,
/// RBX register
RBX,
/// RSP register
RSP,
/// RBP register
RBP,
/// RSI register
RSI,
/// RDI register
RDI,
/// R8 register
R8,
/// R9 register
R9,
/// R10 register
R10,
/// R11 register
R11,
/// R12 register
R12,
/// R13 register
R13,
/// R14 register
R14,
/// R15 register
R15,
}
/// XMM registers.
#[repr(u8)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum XMM {
/// XMM register 0
XMM0,
/// XMM register 1
XMM1,
/// XMM register 2
XMM2,
/// XMM register 3
XMM3,
/// XMM register 4
XMM4,
/// XMM register 5
XMM5,
/// XMM register 6
XMM6,
/// XMM register 7
XMM7,
/// XMM register 8
XMM8,
/// XMM register 9
XMM9,
/// XMM register 10
XMM10,
/// XMM register 11
XMM11,
/// XMM register 12
XMM12,
/// XMM register 13
XMM13,
/// XMM register 14
XMM14,
/// XMM register 15
XMM15,
}
/// A machine register under the x86-64 architecture.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum X64Register {
/// General-purpose registers.
GPR(GPR),
/// XMM (floating point/SIMD) registers.
XMM(XMM),
}
impl X64Register {
/// Returns the index of the register.
pub fn to_index(&self) -> RegisterIndex {
match *self {
X64Register::GPR(x) => RegisterIndex(x as usize),
@ -450,6 +574,7 @@ pub mod x64_decl {
}
}
/// Converts a DWARD regnum to X64Register.
pub fn from_dwarf_regnum(x: u16) -> Option<X64Register> {
Some(match x {
0 => X64Register::GPR(GPR::RAX),
@ -484,6 +609,7 @@ pub mod x64_decl {
}
pub mod x64 {
//! The x64 state module contains functions to generate state and code for x64 targets.
pub use super::x64_decl::*;
use super::*;
use crate::codegen::BreakpointMap;
@ -503,6 +629,7 @@ pub mod x64 {
ptr as usize as u64
}
/// Create a new `MachineState` with default values.
pub fn new_machine_state() -> MachineState {
MachineState {
stack_values: vec![],
@ -514,6 +641,8 @@ pub mod x64 {
}
}
/// Invokes a call return on the stack for the given module state map, code base, instance
/// image and context.
#[warn(unused_variables)]
pub unsafe fn invoke_call_return_on_stack(
msm: &ModuleStateMap,
@ -865,6 +994,7 @@ pub mod x64 {
)
}
/// Builds an `InstanceImage` for the given `Ctx` and `ExecutionStateImage`.
pub fn build_instance_image(
vmctx: &mut Ctx,
execution_state: ExecutionStateImage,
@ -900,6 +1030,8 @@ pub mod x64 {
}
}
/// Returns a `ExecutionStateImage` for the given versions, stack, initial registers and
/// initial address.
#[warn(unused_variables)]
pub unsafe fn read_stack<'a, I: Iterator<Item = &'a CodeVersion>, F: Fn() -> I + 'a>(
versions: F,