1
//! Snapshot/restore of `CompileContext`'s wasm-section + counter state.
2
//!
3
//! Used by the Tier 1.5 monomorphisation fixpoint: the type-inference
4
//! loop emits a defun body assuming a sentinel return type, observes the
5
//! actual body-derived type, and — if it differs — rolls every wasm-side
6
//! mutation made during the trial emit back to the pre-emit state and
7
//! re-runs body emit with the inferred type substituted in.
8
//!
9
//! What participates:
10
//! - `types` / `functions` / `data` sections + their counters and
11
//!   name-lookup maps (`type_count` / `local_func_count` / `data_count`,
12
//!   `type_cache` / `func_names`).
13
//! - `closures` registry — env-struct + closure-sig + helper-name
14
//!   counters.
15
//! - `declared_funcs` — funcref declarations queued for the elements
16
//!   section.
17
//! - `pending_helpers` length — bodies queued during the trial emit are
18
//!   discarded by truncation.
19
//! - `local_types` length + `next_local` counter + `serializer` cursor
20
//!   — the local-pool state local-to the trial body.
21
//! - `closure_bodies` — value-position lambda sources keyed by local idx;
22
//!   shares the local-pool lifetime so a body recorded in a trial emit
23
//!   can't outlive the rollback and be inlined under a reused local idx.
24
//!
25
//! What does *not* participate:
26
//! - `imports`, `exports`, `memories`, `codes` — set during bootstrap or
27
//!   on the `add_should_apply` / `add_process` drain, never during body
28
//!   emit.
29
//! - `host_fns` — registered once at construction time.
30
//! - `inlining_stack` / `inlining_set` — push/pop is already balanced
31
//!   around the trial emit.
32

            
33
use std::collections::HashMap;
34

            
35
use wasm_encoder::{DataSection, FunctionSection, TypeSection, ValType};
36

            
37
use super::super::layout::OutputSerializer;
38
use super::CompileContext;
39
use super::closure::ClosureRegistry;
40
use super::monomorph::MonomorphCache;
41
use crate::ast::WasmType;
42

            
43
/// Captured snapshot returned by [`CompileContext::snapshot`]. Restored
44
/// via [`CompileContext::restore`] (consumes the snapshot). `Clone` so
45
/// the monomorph fixpoint can roll back to the same pre-emit state
46
/// across multiple type-inference iterations without re-walking the
47
/// caller's mutation history.
48
#[derive(Clone)]
49
pub(crate) struct ContextSnapshot {
50
    types: TypeSection,
51
    functions: FunctionSection,
52
    data: DataSection,
53
    type_count: u32,
54
    local_func_count: u32,
55
    data_count: u32,
56
    type_cache: HashMap<Vec<ValType>, HashMap<Vec<ValType>, u32>>,
57
    func_names: HashMap<String, u32>,
58
    closures: ClosureRegistry,
59
    declared_funcs: Vec<u32>,
60
    monomorphs: MonomorphCache,
61
    pending_helpers_len: usize,
62
    next_local: u32,
63
    local_types: Vec<(WasmType, u32)>,
64
    closure_bodies: HashMap<u32, (crate::ast::LambdaParams, crate::ast::Expr)>,
65
    serializer: OutputSerializer,
66
}
67

            
68
impl CompileContext {
69
    /// Captures the wasm-side mutable state so a trial body emit can be
70
    /// rolled back. See module docs for which fields participate.
71
893
    pub(crate) fn snapshot(&self) -> ContextSnapshot {
72
893
        ContextSnapshot {
73
893
            types: self.types.clone(),
74
893
            functions: self.functions.clone(),
75
893
            data: self.data.clone(),
76
893
            type_count: self.type_count,
77
893
            local_func_count: self.local_func_count,
78
893
            data_count: self.data_count,
79
893
            type_cache: self.type_cache.clone(),
80
893
            func_names: self.func_names.clone(),
81
893
            closures: self.closures.clone(),
82
893
            declared_funcs: self.declared_funcs.clone(),
83
893
            monomorphs: self.monomorphs.clone(),
84
893
            pending_helpers_len: self.pending_helpers.len(),
85
893
            next_local: self.next_local,
86
893
            local_types: self.local_types.clone(),
87
893
            closure_bodies: self.closure_bodies.clone(),
88
893
            serializer: self.serializer.clone(),
89
893
        }
90
893
    }
91

            
92
    /// Restores the wasm-side state to a captured [`ContextSnapshot`].
93
    /// Truncates `pending_helpers` to the snapshot's length so any helper
94
    /// queued by the trial emit is discarded; helpers queued *before*
95
    /// the snapshot stay in place.
96
1097
    pub(crate) fn restore(&mut self, snap: ContextSnapshot) {
97
1097
        self.types = snap.types;
98
1097
        self.functions = snap.functions;
99
1097
        self.data = snap.data;
100
1097
        self.type_count = snap.type_count;
101
1097
        self.local_func_count = snap.local_func_count;
102
1097
        self.data_count = snap.data_count;
103
1097
        self.type_cache = snap.type_cache;
104
1097
        self.func_names = snap.func_names;
105
1097
        self.closures = snap.closures;
106
1097
        self.declared_funcs = snap.declared_funcs;
107
1097
        self.monomorphs = snap.monomorphs;
108
1097
        self.pending_helpers.truncate(snap.pending_helpers_len);
109
1097
        self.next_local = snap.next_local;
110
1097
        self.local_types = snap.local_types;
111
1097
        self.closure_bodies = snap.closure_bodies;
112
1097
        self.serializer = snap.serializer;
113
1097
    }
114
}