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}