mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-15 18:01:22 +00:00
Merge master and add documentation.
This commit is contained in:
@ -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,
|
||||
|
Reference in New Issue
Block a user