swc_opt_ssa/
lib.rs

1use std::collections::BTreeSet;
2
3use id_arena::{Arena, Id};
4use swc_ecma_ast::Lit;
5use swc_ssa::{SCatch, SPostcedent, STarget, STerm, SValue, ch::ConstVal, simplify::SValGetter};
6use swc_tac::Item;
7pub mod impls;
8pub mod into;
9pub use portal_jsc_swc_util::r#type::{ObjType, OptType};
10#[derive(Clone, Debug)]
11#[non_exhaustive]
12pub enum OptValue<I = Id<OptValueW>, B = Id<OptBlock>, F = OptFunc, D = ()> {
13    Deopt {
14        value: I,
15        deoptimizer: D,
16    },
17    Assert {
18        val: I,
19        ty: Option<OptType>,
20    },
21    Emit {
22        val: SValue<I, B, F>,
23        ty: Option<OptType>,
24    },
25}
26impl<I, B, F, D> OptValue<I, B, F, D> {
27    pub fn as_ref<'a>(&'a self) -> OptValue<&'a I, &'a B, &'a F, &'a D> {
28        match self {
29            OptValue::Deopt { value, deoptimizer } => OptValue::Deopt { value, deoptimizer },
30            OptValue::Assert { val, ty } => OptValue::Assert {
31                val,
32                ty: ty.clone(),
33            },
34            OptValue::Emit { val, ty } => OptValue::Emit {
35                val: val.as_ref(),
36                ty: ty.clone(),
37            },
38        }
39    }
40    pub fn as_mut<'a>(&'a mut self) -> OptValue<&'a mut I, &'a mut B, &'a mut F, &'a mut D> {
41        match self {
42            OptValue::Deopt { value, deoptimizer } => OptValue::Deopt { value, deoptimizer },
43            OptValue::Assert { val, ty } => OptValue::Assert {
44                val,
45                ty: ty.clone(),
46            },
47            OptValue::Emit { val, ty } => OptValue::Emit {
48                val: val.as_mut(),
49                ty: ty.clone(),
50            },
51        }
52    }
53    pub fn map<Ctx, E, I2: Ord, B2, F2, D2>(
54        self,
55        ctx: &mut Ctx,
56        i: &mut (dyn FnMut(&mut Ctx, I) -> Result<I2, E> + '_),
57        b: &mut (dyn FnMut(&mut Ctx, B) -> Result<B2, E> + '_),
58        f: &mut (dyn FnMut(&mut Ctx, F) -> Result<F2, E> + '_),
59        d: &mut (dyn FnMut(&mut Ctx, D) -> Result<D2, E> + '_),
60    ) -> Result<OptValue<I2, B2, F2, D2>, E> {
61        Ok(match self {
62            OptValue::Deopt { value, deoptimizer } => OptValue::Deopt {
63                value: i(ctx, value)?,
64                deoptimizer: d(ctx, deoptimizer)?,
65            },
66            OptValue::Assert { val, ty } => OptValue::Assert {
67                val: i(ctx, val)?,
68                ty,
69            },
70            OptValue::Emit { val, ty } => OptValue::Emit {
71                val: val.map(ctx, i, b, f)?,
72                ty,
73            },
74        })
75    }
76}
77#[derive(Clone, Debug)]
78pub struct OptValueW { pub value: OptValue }
79#[derive(Default, Clone, Debug)]
80pub struct OptBlock {
81    pub params: Vec<(Id<OptValueW>, Option<OptType>)>,
82    pub insts: Vec<Id<OptValueW>>,
83    pub postcedent: OptPostcedent,
84}
85pub type OptPostcedent = SPostcedent<Id<OptValueW>, Id<OptBlock>>;
86pub type OptTarget = STarget<Id<OptValueW>, Id<OptBlock>>;
87pub type OptTerm = STerm<Id<OptValueW>, Id<OptBlock>>;
88pub type OptCatch = SCatch<Id<OptValueW>, Id<OptBlock>>;
89#[derive(Default, Clone, Debug)]
90pub struct OptCfg {
91    pub values: Arena<OptValueW>,
92    pub blocks: Arena<OptBlock>,
93    pub decls: BTreeSet<swc_ecma_ast::Id>,
94}
95impl OptValueW {
96    pub fn ty(&self, cfg: &OptCfg) -> Option<OptType> {
97        match &self.value {
98            OptValue::Deopt { value: d, .. } => {
99                let x = cfg.values[*d].ty(cfg);
100                x.and_then(|y| y.parent(Default::default()))
101            }
102            OptValue::Assert { val, ty } => ty.clone(),
103            OptValue::Emit { val, ty } => ty.clone(),
104        }
105    }
106    pub fn constant(&self, cfg: &OptCfg) -> Option<Lit> {
107        match &self.value {
108            OptValue::Deopt { value: a, .. } => cfg.values[*a].constant(cfg),
109            OptValue::Assert { val, ty } => cfg.values[*val].constant(cfg),
110            OptValue::Emit { val, ty } => match val {
111                SValue::Item { item: i, span } => match i {
112                    Item::Lit { lit } => Some(lit.clone()),
113                    _ => None,
114                },
115                _ => None,
116            },
117        }
118    }
119}
120impl SValGetter<Id<OptValueW>, Id<OptBlock>, OptFunc> for OptCfg {
121    fn val(&self, id: Id<OptValueW>) -> Option<&SValue<Id<OptValueW>, Id<OptBlock>, OptFunc>> {
122        match &self.values[id].value {
123            OptValue::Deopt { value: a, .. } => self.val(*a),
124            OptValue::Assert { val, ty } => self.val(*val),
125            OptValue::Emit { val, ty } => Some(val),
126        }
127    }
128}
129#[derive(Clone, Debug)]
130pub struct OptFunc {
131    pub cfg: OptCfg,
132    pub entry: Id<OptBlock>,
133    pub is_generator: bool,
134    pub is_async: bool,
135}
136impl OptCfg {
137    pub fn add_blockparam(&mut self, k: Id<OptBlock>, ty: Option<OptType>) -> Id<OptValueW> {
138        let v = self.values.alloc(OptValueW { value: OptValue::Emit {
139            val: SValue::Param {
140                block: k,
141                idx: self.blocks[k].params.len(),
142                ty: (),
143            },
144            ty: ty.clone(),
145        } });
146        self.blocks[k].params.push((v, ty));
147        return v;
148    }
149}