Lines
100 %
Functions
40 %
Branches
//! Snapshot/restore of `CompileContext`'s wasm-section + counter state.
//!
//! Used by the Tier 1.5 monomorphisation fixpoint: the type-inference
//! loop emits a defun body assuming a sentinel return type, observes the
//! actual body-derived type, and — if it differs — rolls every wasm-side
//! mutation made during the trial emit back to the pre-emit state and
//! re-runs body emit with the inferred type substituted in.
//! What participates:
//! - `types` / `functions` / `data` sections + their counters and
//! name-lookup maps (`type_count` / `local_func_count` / `data_count`,
//! `type_cache` / `func_names`).
//! - `closures` registry — env-struct + closure-sig + helper-name
//! counters.
//! - `declared_funcs` — funcref declarations queued for the elements
//! section.
//! - `pending_helpers` length — bodies queued during the trial emit are
//! discarded by truncation.
//! - `local_types` length + `next_local` counter + `serializer` cursor
//! — the local-pool state local-to the trial body.
//! - `closure_bodies` — value-position lambda sources keyed by local idx;
//! shares the local-pool lifetime so a body recorded in a trial emit
//! can't outlive the rollback and be inlined under a reused local idx.
//! What does *not* participate:
//! - `imports`, `exports`, `memories`, `codes` — set during bootstrap or
//! on the `add_should_apply` / `add_process` drain, never during body
//! emit.
//! - `host_fns` — registered once at construction time.
//! - `inlining_stack` / `inlining_set` — push/pop is already balanced
//! around the trial emit.
use std::collections::HashMap;
use wasm_encoder::{DataSection, FunctionSection, TypeSection, ValType};
use super::super::layout::OutputSerializer;
use super::CompileContext;
use super::closure::ClosureRegistry;
use super::monomorph::MonomorphCache;
use crate::ast::WasmType;
/// Captured snapshot returned by [`CompileContext::snapshot`]. Restored
/// via [`CompileContext::restore`] (consumes the snapshot). `Clone` so
/// the monomorph fixpoint can roll back to the same pre-emit state
/// across multiple type-inference iterations without re-walking the
/// caller's mutation history.
#[derive(Clone)]
pub(crate) struct ContextSnapshot {
types: TypeSection,
functions: FunctionSection,
data: DataSection,
type_count: u32,
local_func_count: u32,
data_count: u32,
type_cache: HashMap<Vec<ValType>, HashMap<Vec<ValType>, u32>>,
func_names: HashMap<String, u32>,
closures: ClosureRegistry,
declared_funcs: Vec<u32>,
monomorphs: MonomorphCache,
pending_helpers_len: usize,
next_local: u32,
local_types: Vec<(WasmType, u32)>,
closure_bodies: HashMap<u32, (crate::ast::LambdaParams, crate::ast::Expr)>,
serializer: OutputSerializer,
}
impl CompileContext {
/// Captures the wasm-side mutable state so a trial body emit can be
/// rolled back. See module docs for which fields participate.
pub(crate) fn snapshot(&self) -> ContextSnapshot {
ContextSnapshot {
types: self.types.clone(),
functions: self.functions.clone(),
data: self.data.clone(),
type_count: self.type_count,
local_func_count: self.local_func_count,
data_count: self.data_count,
type_cache: self.type_cache.clone(),
func_names: self.func_names.clone(),
closures: self.closures.clone(),
declared_funcs: self.declared_funcs.clone(),
monomorphs: self.monomorphs.clone(),
pending_helpers_len: self.pending_helpers.len(),
next_local: self.next_local,
local_types: self.local_types.clone(),
closure_bodies: self.closure_bodies.clone(),
serializer: self.serializer.clone(),
/// Restores the wasm-side state to a captured [`ContextSnapshot`].
/// Truncates `pending_helpers` to the snapshot's length so any helper
/// queued by the trial emit is discarded; helpers queued *before*
/// the snapshot stay in place.
pub(crate) fn restore(&mut self, snap: ContextSnapshot) {
self.types = snap.types;
self.functions = snap.functions;
self.data = snap.data;
self.type_count = snap.type_count;
self.local_func_count = snap.local_func_count;
self.data_count = snap.data_count;
self.type_cache = snap.type_cache;
self.func_names = snap.func_names;
self.closures = snap.closures;
self.declared_funcs = snap.declared_funcs;
self.monomorphs = snap.monomorphs;
self.pending_helpers.truncate(snap.pending_helpers_len);
self.next_local = snap.next_local;
self.local_types = snap.local_types;
self.closure_bodies = snap.closure_bodies;
self.serializer = snap.serializer;