@samitouri / QOS-React-1 / commits / 01ad9d895e

[rust] Remove arena allocator

Using an arena allocator can be faster, but it comes with several challenges: * It requires tediously tagging nearly every value with a lifetime. Any function that has to deal with arena-allocated data (which is every meaningful function) ends up with a lifetime parameter. Bleh. We also have to thread the allocator itself wherever we need to allocate, though this is less of a problem since _most_ functions already need the Environment and we can store the allocator there. * There is not yet widespread support in the Rust ecosystem for using custom allocators with custom data types. This means that things like HashMap/Set and IndexMap/Set can't be arena allocated. This means that either we have to add support to these data types (by upstreaming or forking) or just accept that we're only partially using the arena allocator. * Finally, `bumpalo`'s `Box` cannot be moved out of, which turns out to be an annoying limitation that i've already had to work around several times. In the end i'm not sure arena allocators are worth it at this stage of the project. Relay Compiler has been successful without one, and other Rust-based internal compilers get by without them too.

Joe Savona committed Jul 28, 2023 at 16:12 UTC 01ad9d895e523c35f83c0f4f5151e5cea13dbcc6
30 files changed +354 -566
compiler/forget/Cargo.lock
-7
@@ -450,7 +450,6 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
450 name = "forget_build_hir"
451 version = "0.1.0"
452 dependencies = [
453 - "bumpalo",
453 "forget_diagnostics",
454 "forget_estree",
455 "forget_hir",
@@ -472,7 +471,6 @@ dependencies = [
471 name = "forget_estree"
472 version = "0.1.0"
473 dependencies = [
475 - "bumpalo",
474 "forget_estree_codegen",
475 "insta",
476 "serde",
@@ -505,7 +503,6 @@ dependencies = [
503 name = "forget_fixtures"
504 version = "0.1.0"
505 dependencies = [
508 - "bumpalo",
506 "forget_build_hir",
507 "forget_estree",
508 "forget_estree_swc",
@@ -520,7 +517,6 @@ dependencies = [
517 name = "forget_hir"
518 version = "0.1.0"
519 dependencies = [
523 - "bumpalo",
520 "forget_diagnostics",
521 "forget_estree",
522 "forget_utils",
@@ -533,7 +529,6 @@ dependencies = [
529 name = "forget_optimization"
530 version = "0.1.0"
531 dependencies = [
536 - "bumpalo",
532 "forget_build_hir",
533 "forget_diagnostics",
534 "forget_estree",
@@ -549,7 +544,6 @@ dependencies = [
544 name = "forget_ssa"
545 version = "0.1.0"
546 dependencies = [
552 - "bumpalo",
547 "forget_diagnostics",
548 "forget_hir",
549 "forget_utils",
@@ -562,7 +556,6 @@ dependencies = [
556 name = "forget_utils"
557 version = "0.1.0"
558 dependencies = [
565 - "bumpalo",
559 "stacker",
560 ]
561
compiler/forget/Cargo.toml
-1
@@ -26,7 +26,6 @@ forget_swc_demo = { path = "crates/forget_swc_demo" }
26 forget_utils = { path = "crates/forget_utils" }
27
28 # dependencies
29 -bumpalo = { version = "3.13.0", features = ["boxed", "collections"] }
29 indexmap = { version = "2.0.0", features = ["serde"] }
30 insta = { version = "1.30.0", features = ["glob"] }
31 miette = { version = "5.9.0" }
compiler/forget/crates/forget_build_hir/Cargo.toml
-1
@@ -16,6 +16,5 @@ repository.workspace = true
16 forget_hir = { workspace = true }
17 forget_estree = { workspace = true}
18 indexmap = { workspace = true }
19 -bumpalo = { workspace = true }
19 forget_diagnostics = { workspace = true }
20 thiserror = { workspace = true }
compiler/forget/crates/forget_build_hir/src/build.rs
+50 -60
@@ -1,6 +1,5 @@
1 use std::collections::HashSet;
2
3 -use bumpalo::collections::{CollectIn, String};
3 use forget_diagnostics::Diagnostic;
4 use forget_estree::{
5 AssignmentTarget, BinaryExpression, BlockStatement, Expression, ExpressionOrSpread,
@@ -23,10 +22,7 @@ use crate::error::BuildHIRError;
22 ///
23 /// Failures generally include nonsensical input (`delete 1`) or syntax
24 /// that is not yet supported.
26 -pub fn build<'a>(
27 - env: &'a Environment<'a>,
28 - fun: Function,
29 -) -> Result<Box<forget_hir::Function<'a>>, Diagnostic> {
25 +pub fn build(env: &Environment, fun: Function) -> Result<Box<forget_hir::Function>, Diagnostic> {
26 let mut builder = Builder::new(env);
27
28 match fun.body {
@@ -44,7 +40,7 @@ pub fn build<'a>(
40 }
41 }
42
47 - let mut params = env.vec_with_capacity(fun.params.len());
43 + let mut params = Vec::with_capacity(fun.params.len());
44 for param in fun.params {
45 match param {
46 Pattern::Identifier(param) => {
@@ -83,21 +79,19 @@ pub fn build<'a>(
79
80 let body = builder.build()?;
81 Ok(Box::new(forget_hir::Function {
86 - id: fun
87 - .id
88 - .map(|id| String::from_str_in(&id.name, &env.allocator)),
82 + id: fun.id.map(|id| id.name),
83 body,
84 params,
85 // TODO: populate context!
92 - context: env.vec_new(),
86 + context: Default::default(),
87 is_async: fun.is_async,
88 is_generator: fun.is_generator,
89 }))
90 }
91
98 -fn lower_block_statement<'a>(
99 - env: &'a Environment<'a>,
100 - builder: &mut Builder<'a>,
92 +fn lower_block_statement(
93 + env: &Environment,
94 + builder: &mut Builder,
95 stmt: BlockStatement,
96 ) -> Result<(), Diagnostic> {
97 for stmt in stmt.body {
@@ -108,11 +102,11 @@ fn lower_block_statement<'a>(
102
103 /// Convert a statement to HIR. This will often result in multiple instructions and blocks
104 /// being created as statements often describe control flow.
111 -fn lower_statement<'a>(
112 - env: &'a Environment<'a>,
113 - builder: &mut Builder<'a>,
105 +fn lower_statement(
106 + env: &Environment,
107 + builder: &mut Builder,
108 stmt: Statement,
115 - label: Option<String<'a>>,
109 + label: Option<String>,
110 ) -> Result<(), Diagnostic> {
111 match stmt {
112 Statement::BlockStatement(stmt) => {
@@ -350,9 +344,9 @@ fn lower_statement<'a>(
344 /// InstructionValue is returned, this function is recursive and may cause multiple instructions
345 /// to be emitted, possibly across multiple basic blocks (in the case of expressions with control
346 /// flow semenatics such as logical, conditional, and optional expressions).
353 -fn lower_expression<'a>(
354 - env: &'a Environment<'a>,
355 - builder: &mut Builder<'a>,
347 +fn lower_expression(
348 + env: &Environment,
349 + builder: &mut Builder,
350 expr: Expression,
351 ) -> Result<InstrIx, Diagnostic> {
352 let value = match expr {
@@ -367,16 +361,16 @@ fn lower_expression<'a>(
361 };
362 InstructionValue::LoadLocal(LoadLocal { place })
363 }
370 - Binding::Module(..) | Binding::Global => InstructionValue::LoadGlobal(LoadGlobal {
371 - name: String::from_str_in(&expr.name, &env.allocator),
372 - }),
364 + Binding::Module(..) | Binding::Global => {
365 + InstructionValue::LoadGlobal(LoadGlobal { name: expr.name })
366 + }
367 }
368 }
369 Expression::Literal(expr) => InstructionValue::Primitive(forget_hir::Primitive {
370 value: lower_primitive(env, builder, *expr),
371 }),
372 Expression::ArrayExpression(expr) => {
379 - let mut elements = env.vec_with_capacity(expr.elements.len());
373 + let mut elements = Vec::with_capacity(expr.elements.len());
374 for expr in expr.elements {
375 let element = match expr {
376 Some(forget_estree::ExpressionOrSpread::SpreadElement(expr)) => {
@@ -477,12 +471,12 @@ fn lower_expression<'a>(
471 Ok(builder.push(value))
472 }
473
480 -fn lower_arguments<'a>(
481 - env: &'a Environment<'a>,
482 - builder: &mut Builder<'a>,
474 +fn lower_arguments(
475 + env: &Environment,
476 + builder: &mut Builder,
477 args: Vec<ExpressionOrSpread>,
484 -) -> Result<bumpalo::collections::Vec<'a, PlaceOrSpread>, Diagnostic> {
485 - let mut arguments = env.vec_with_capacity(args.len());
478 +) -> Result<Vec<PlaceOrSpread>, Diagnostic> {
479 + let mut arguments = Vec::with_capacity(args.len());
480 for arg in args {
481 let element = match arg {
482 forget_estree::ExpressionOrSpread::SpreadElement(arg) => {
@@ -501,15 +495,15 @@ fn lower_arguments<'a>(
495 Ok(arguments)
496 }
497
504 -fn lower_function<'a>(
505 - env: &'a Environment<'a>,
506 - builder: &mut Builder<'a>,
498 +fn lower_function(
499 + env: &Environment,
500 + builder: &mut Builder,
501 function: forget_estree::Function,
508 -) -> Result<forget_hir::FunctionExpression<'a>, Diagnostic> {
502 +) -> Result<forget_hir::FunctionExpression, Diagnostic> {
503 println!("get_context_identifiers() ...");
504 let context_identifiers = get_context_identifiers(env, &function);
505 println!("ok");
512 - let mut context = env.vec_new();
506 + let mut context = Vec::new();
507 let mut seen = HashSet::new();
508 for identifier in context_identifiers {
509 match builder.resolve_identifier(identifier)? {
@@ -529,17 +523,17 @@ fn lower_function<'a>(
523 fun.context = context;
524 Ok(forget_hir::FunctionExpression {
525 // TODO: collect dependencies!
532 - dependencies: env.vec_new(),
526 + dependencies: Default::default(),
527 lowered_function: fun,
528 })
529 }
530
537 -fn lower_jsx_element<'a>(
538 - env: &'a Environment<'a>,
539 - builder: &mut Builder<'a>,
531 +fn lower_jsx_element(
532 + env: &Environment,
533 + builder: &mut Builder,
534 expr: forget_estree::JSXElement,
541 -) -> Result<JSXElement<'a>, Diagnostic> {
542 - let props: Result<Vec<JSXAttribute<'_>>, Diagnostic> = expr
535 +) -> Result<JSXElement, Diagnostic> {
536 + let props: Result<Vec<JSXAttribute>, Diagnostic> = expr
537 .opening_element
538 .attributes
539 .into_iter()
@@ -567,25 +561,25 @@ fn lower_jsx_element<'a>(
561 // })
562 }
563
570 -fn lower_jsx_attribute<'a>(
571 - env: &'a Environment<'a>,
572 - builder: &mut Builder<'a>,
564 +fn lower_jsx_attribute(
565 + env: &Environment,
566 + builder: &mut Builder,
567 attr: forget_estree::JSXAttributeOrSpread,
574 -) -> Result<JSXAttribute<'a>, Diagnostic> {
568 +) -> Result<JSXAttribute, Diagnostic> {
569 todo!("lower jsx attribute")
570 }
571
578 -fn lower_jsx_child<'a>(
579 - env: &'a Environment<'a>,
580 - builder: &mut Builder<'a>,
572 +fn lower_jsx_child(
573 + env: &Environment,
574 + builder: &mut Builder,
575 child: forget_estree::JSXChildItem,
576 ) -> Result<InstrIx, Diagnostic> {
577 todo!("lower jsx child")
578 }
579
586 -fn lower_assignment<'a>(
587 - env: &'a Environment<'a>,
588 - builder: &mut Builder<'a>,
580 +fn lower_assignment(
581 + env: &Environment,
582 + builder: &mut Builder,
583 kind: InstructionKind,
584 lvalue: AssignmentTarget,
585 value: InstrIx,
@@ -608,12 +602,12 @@ fn lower_assignment<'a>(
602 })
603 }
604
611 -fn lower_identifier_for_assignment<'a>(
612 - _env: &'a Environment<'a>,
613 - builder: &mut Builder<'a>,
605 +fn lower_identifier_for_assignment(
606 + _env: &Environment,
607 + builder: &mut Builder,
608 _kind: InstructionKind,
609 identifier: forget_estree::Identifier,
616 -) -> Result<IdentifierOperand<'a>, Diagnostic> {
610 +) -> Result<IdentifierOperand, Diagnostic> {
611 let binding = builder.resolve_identifier(&identifier)?;
612 match binding {
613 Binding::Module(..) | Binding::Global => Err(Diagnostic::invalid_react(
@@ -632,16 +626,12 @@ fn lower_identifier_for_assignment<'a>(
626 }
627
628 /// Converts an ESTree literal into a HIR primitive
635 -fn lower_primitive<'a>(
636 - env: &'a Environment<'a>,
637 - _builder: &mut Builder<'a>,
638 - literal: Literal,
639 -) -> PrimitiveValue<'a> {
629 +fn lower_primitive(_env: &Environment, _builder: &mut Builder, literal: Literal) -> PrimitiveValue {
630 match literal.value {
631 JsValue::Bool(bool) => PrimitiveValue::Boolean(bool),
632 JsValue::Null => PrimitiveValue::Null,
633 JsValue::Number(value) => PrimitiveValue::Number(f64::from(value).into()),
644 - JsValue::String(s) => PrimitiveValue::String(String::from_str_in(&s, &env.allocator)),
634 + JsValue::String(s) => PrimitiveValue::String(s),
635 _ => todo!("Lower literal {literal:#?}"),
636 }
637 }
compiler/forget/crates/forget_build_hir/src/builder.rs
+44 -45
@@ -1,7 +1,6 @@
1 use std::cell::RefCell;
2 use std::rc::Rc;
3
4 -use bumpalo::collections::{String, Vec};
4 use forget_diagnostics::Diagnostic;
5 use forget_hir::{
6 initialize_hir, BasicBlock, BlockId, BlockKind, Blocks, Environment, GotoKind, Identifier,
@@ -20,59 +19,59 @@ use crate::BuildHIRError;
19 /// generally involves driving calls to enter/exit blocks, resolve
20 /// labels and variables, and then calling `build()` when the HIR
21 /// is complete.
23 -pub(crate) struct Builder<'a> {
22 +pub(crate) struct Builder<'e> {
23 #[allow(dead_code)]
25 - environment: &'a Environment<'a>,
24 + environment: &'e Environment,
25
27 - completed: Blocks<'a>,
26 + completed: Blocks,
27
29 - instructions: Vec<'a, Instruction<'a>>,
28 + instructions: Vec<Instruction>,
29
30 entry: BlockId,
31
33 - wip: WipBlock<'a>,
32 + wip: WipBlock,
33
34 id_gen: InstructionIdGenerator,
35
37 - scopes: Vec<'a, ControlFlowScope<'a>>,
36 + scopes: Vec<ControlFlowScope>,
37 }
38
40 -pub(crate) struct WipBlock<'a> {
39 +pub(crate) struct WipBlock {
40 pub id: BlockId,
41 pub kind: BlockKind,
43 - pub instructions: Vec<'a, InstrIx>,
42 + pub instructions: Vec<InstrIx>,
43 }
44
46 -pub(crate) enum Binding<'a> {
47 - Local(Identifier<'a>),
48 - Module(Identifier<'a>),
45 +pub(crate) enum Binding {
46 + Local(Identifier),
47 + Module(Identifier),
48 Global,
49 }
50
51 #[derive(Clone, PartialEq, Eq, Debug)]
53 -enum ControlFlowScope<'a> {
54 - Loop(LoopScope<'a>),
52 +enum ControlFlowScope {
53 + Loop(LoopScope),
54
56 - // Switch(SwitchScope<'a>),
55 + // Switch(SwitchScope),
56 #[allow(dead_code)]
58 - Label(LabelScope<'a>),
57 + Label(LabelScope),
58 }
59
60 #[derive(Clone, PartialEq, Eq, Debug)]
62 -pub(crate) struct LoopScope<'a> {
63 - pub label: Option<String<'a>>,
61 +pub(crate) struct LoopScope {
62 + pub label: Option<String>,
63 pub continue_block: BlockId,
64 pub break_block: BlockId,
65 }
66
67 #[derive(Clone, PartialEq, Eq, Debug)]
69 -pub(crate) struct LabelScope<'a> {
70 - pub label: String<'a>,
68 +pub(crate) struct LabelScope {
69 + pub label: String,
70 pub block: BlockId,
71 }
72
74 -impl<'a> ControlFlowScope<'a> {
75 - fn label(&self) -> Option<&String<'a>> {
73 +impl ControlFlowScope {
74 + fn label(&self) -> Option<&String> {
75 match self {
76 Self::Loop(scope) => scope.label.as_ref(),
77 Self::Label(scope) => Some(&scope.label),
@@ -87,22 +86,22 @@ impl<'a> ControlFlowScope<'a> {
86 }
87 }
88
90 -impl<'a> Builder<'a> {
91 - pub(crate) fn new(environment: &'a Environment<'a>) -> Self {
89 +impl<'e> Builder<'e> {
90 + pub(crate) fn new(environment: &'e Environment) -> Self {
91 let entry = environment.next_block_id();
92 let current = WipBlock {
93 id: entry,
94 kind: BlockKind::Block,
96 - instructions: environment.vec_new(),
95 + instructions: Default::default(),
96 };
97 Self {
98 environment,
99 completed: Default::default(),
101 - instructions: environment.vec_new(),
100 + instructions: Default::default(),
101 entry,
102 wip: current,
103 id_gen: InstructionIdGenerator::new(),
105 - scopes: environment.vec_new(),
104 + scopes: Default::default(),
105 }
106 }
107
@@ -111,7 +110,7 @@ impl<'a> Builder<'a> {
110 ///
111 /// TODO: refine the type, only invariants should be possible here,
112 /// not other types of errors
114 - pub(crate) fn build(self) -> Result<HIR<'a>, Diagnostic> {
113 + pub(crate) fn build(self) -> Result<HIR, Diagnostic> {
114 let mut hir = HIR {
115 entry: self.entry,
116 blocks: self.completed,
@@ -123,7 +122,7 @@ impl<'a> Builder<'a> {
122 }
123
124 /// Adds a new instruction to the end of the work in progress block
126 - pub(crate) fn push(&mut self, value: InstructionValue<'a>) -> InstrIx {
125 + pub(crate) fn push(&mut self, value: InstructionValue) -> InstrIx {
126 let instr = Instruction {
127 id: self.id_gen.next(),
128 value,
@@ -136,19 +135,19 @@ impl<'a> Builder<'a> {
135
136 /// Terminates the work in progress block with the given terminal, and starts a new
137 /// work in progress block with the given kind
139 - pub(crate) fn terminate(&mut self, terminal: TerminalValue<'a>, next_kind: BlockKind) {
138 + pub(crate) fn terminate(&mut self, terminal: TerminalValue, next_kind: BlockKind) {
139 let next_wip = WipBlock {
140 id: self.environment.next_block_id(),
141 kind: next_kind,
143 - instructions: self.environment.vec_new(),
142 + instructions: Default::default(),
143 };
144 self.terminate_with_fallthrough(terminal, next_wip)
145 }
146
147 pub(crate) fn terminate_with_fallthrough(
148 &mut self,
150 - terminal: TerminalValue<'a>,
151 - fallthrough: WipBlock<'a>,
149 + terminal: TerminalValue,
150 + fallthrough: WipBlock,
151 ) {
152 let prev_wip = std::mem::replace(&mut self.wip, fallthrough);
153 self.completed.insert(Box::new(BasicBlock {
@@ -160,21 +159,21 @@ impl<'a> Builder<'a> {
159 value: terminal,
160 },
161 predecessors: Default::default(),
163 - phis: self.environment.vec_new(),
162 + phis: Default::default(),
163 }));
164 }
165
167 - pub(crate) fn reserve(&mut self, kind: BlockKind) -> WipBlock<'a> {
166 + pub(crate) fn reserve(&mut self, kind: BlockKind) -> WipBlock {
167 WipBlock {
168 id: self.environment.next_block_id(),
169 kind,
171 - instructions: self.environment.vec_new(),
170 + instructions: Default::default(),
171 }
172 }
173
174 pub(crate) fn enter<F>(&mut self, kind: BlockKind, f: F) -> Result<BlockId, Diagnostic>
175 where
177 - F: FnOnce(&mut Self) -> Result<TerminalValue<'a>, Diagnostic>,
176 + F: FnOnce(&mut Self) -> Result<TerminalValue, Diagnostic>,
177 {
178 let wip = self.reserve(kind);
179 let id = wip.id;
@@ -182,9 +181,9 @@ impl<'a> Builder<'a> {
181 Ok(id)
182 }
183
185 - fn enter_reserved<F>(&mut self, wip: WipBlock<'a>, f: F) -> Result<(), Diagnostic>
184 + fn enter_reserved<F>(&mut self, wip: WipBlock, f: F) -> Result<(), Diagnostic>
185 where
187 - F: FnOnce(&mut Self) -> Result<TerminalValue<'a>, Diagnostic>,
186 + F: FnOnce(&mut Self) -> Result<TerminalValue, Diagnostic>,
187 {
188 let current = std::mem::replace(&mut self.wip, wip);
189
@@ -210,18 +209,18 @@ impl<'a> Builder<'a> {
209 value: terminal,
210 },
211 predecessors: Default::default(),
213 - phis: self.environment.vec_new(),
212 + phis: Default::default(),
213 }));
214 result
215 }
216
217 pub(crate) fn enter_loop<F>(
218 &mut self,
220 - scope: LoopScope<'a>,
219 + scope: LoopScope,
220 f: F,
222 - ) -> Result<TerminalValue<'a>, Diagnostic>
221 + ) -> Result<TerminalValue, Diagnostic>
222 where
224 - F: FnOnce(&mut Self) -> Result<TerminalValue<'a>, Diagnostic>,
223 + F: FnOnce(&mut Self) -> Result<TerminalValue, Diagnostic>,
224 {
225 self.scopes.push(ControlFlowScope::Loop(scope.clone()));
226 let terminal = f(self);
@@ -235,7 +234,7 @@ impl<'a> Builder<'a> {
234 /// we synthesize a temporary identifier to store the possibly-missing value
235 /// into, and emit a later StoreLocal for the original identifier
236 #[allow(dead_code)]
238 - pub(crate) fn make_temporary(&self) -> forget_hir::Identifier<'a> {
237 + pub(crate) fn make_temporary(&self) -> forget_hir::Identifier {
238 forget_hir::Identifier {
239 id: self.environment.next_identifier_id(),
240 name: None,
@@ -318,7 +317,7 @@ impl<'a> Builder<'a> {
317 pub(crate) fn resolve_identifier(
318 &mut self,
319 identifier: &forget_estree::Identifier,
321 - ) -> Result<Binding<'a>, Diagnostic> {
320 + ) -> Result<Binding, Diagnostic> {
321 match &identifier.binding {
322 Some(binding) => Ok(match binding {
323 forget_estree::Binding::Global => Binding::Global,
compiler/forget/crates/forget_build_hir/src/context.rs
+2 -2
@@ -3,8 +3,8 @@ use std::collections::HashSet;
3 use forget_estree::{Binding, BindingId, Function, Identifier, Visitor};
4 use forget_hir::Environment;
5
6 -pub(crate) fn get_context_identifiers<'a, 'ast>(
7 - _env: &'a Environment<'a>,
6 +pub(crate) fn get_context_identifiers<'ast>(
7 + _env: &Environment,
8 function: &'ast Function,
9 ) -> Vec<&'ast Identifier> {
10 let mut visitor = ContextVisitor::new();
compiler/forget/crates/forget_estree/Cargo.toml
-1
@@ -13,7 +13,6 @@ repository.workspace = true
13 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
14
15 [dependencies]
16 -bumpalo = { workspace = true }
16 insta = { workspace = true }
17 serde = { workspace = true }
18 serde_json = { workspace = true }
compiler/forget/crates/forget_estree/src/snapshots/forget_estree__tests__fixtures@test.json.snap
-15
@@ -395,10 +395,7 @@ Output:
395 "type": "JSXMemberExpression",
396 "object": {
397 "type": "JSXIdentifier",
398 - "type": "Identifier",
398 "name": "Foo",
400 - "loc": null,
401 - "range": null,
399 "loc": {
400 "source": null,
401 "start": {
@@ -417,10 +414,7 @@ Output:
414 },
415 "property": {
416 "type": "JSXIdentifier",
420 - "type": "Identifier",
417 "name": "Bar",
422 - "loc": null,
423 - "range": null,
418 "loc": {
419 "source": null,
420 "start": {
@@ -458,10 +452,7 @@ Output:
452 "type": "JSXAttribute",
453 "name": {
454 "type": "JSXIdentifier",
461 - "type": "Identifier",
455 "name": "a",
463 - "loc": null,
464 - "range": null,
456 "loc": {
457 "source": null,
458 "start": {
@@ -561,10 +552,7 @@ Output:
552 "type": "JSXMemberExpression",
553 "object": {
554 "type": "JSXIdentifier",
564 - "type": "Identifier",
555 "name": "Foo",
566 - "loc": null,
567 - "range": null,
556 "loc": {
557 "source": null,
558 "start": {
@@ -583,10 +571,7 @@ Output:
571 },
572 "property": {
573 "type": "JSXIdentifier",
586 - "type": "Identifier",
574 "name": "Bar",
588 - "loc": null,
589 - "range": null,
575 "loc": {
576 "source": null,
577 "start": {
compiler/forget/crates/forget_fixtures/Cargo.toml
-1
@@ -20,5 +20,4 @@ forget_hir = { workspace = true }
20 forget_optimization = { workspace = true }
21 forget_ssa = { workspace = true }
22 forget_build_hir = { workspace = true }
23 -bumpalo = { workspace = true }
23 miette = { workspace = true, features = ["backtrace", "fancy"] }
compiler/forget/crates/forget_fixtures/tests/fixtures/jsx.js deleted
-9
@@ -1,9 +0,0 @@
1 -function Component(props) {
2 - return (
3 - <Foo bool={true} str="string" number={3.14} var={props.variable}>
4 - Hello
5 - {props.foo}
6 - <div>{props.bar}</div>
7 - </Foo>
8 - );
9 -}
compiler/forget/crates/forget_fixtures/tests/fixtures_test.rs
+2 -5
@@ -1,7 +1,6 @@
1 use std::env;
2 use std::fmt::Write;
3
4 -use bumpalo::Bump;
4 use forget_build_hir::build;
5 use forget_estree::{ModuleItem, Statement};
6 use forget_estree_swc::parse;
@@ -24,14 +23,12 @@ fn fixtures() {
23 for (ix, item) in ast.body.into_iter().enumerate() {
24 if let ModuleItem::Statement(stmt) = item {
25 if let Statement::FunctionDeclaration(fun) = stmt {
27 - let allocator = Bump::new();
28 - let environment = allocator.alloc(Environment::new(
29 - &allocator,
26 + let environment = Environment::new(
27 Features {
28 validate_frozen_lambdas: true,
29 },
30 Registry,
34 - ));
31 + );
32 if ix != 0 {
33 output.push_str("\n\n");
34 }
compiler/forget/crates/forget_hir/Cargo.toml
-1
@@ -13,7 +13,6 @@ repository.workspace = true
13 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
14
15 [dependencies]
16 -bumpalo = { workspace = true }
16 forget_estree = { workspace = true }
17 indexmap = { workspace = true }
18 serde = { workspace = true }
compiler/forget/crates/forget_hir/src/basic_block.rs
+7 -7
@@ -12,7 +12,7 @@ use crate::{Identifier, InstrIx, Terminal};
12 ///
13 /// [1] Assuming no exceptions are thrown.
14 #[derive(Debug)]
15 -pub struct BasicBlock<'a> {
15 +pub struct BasicBlock {
16 /// The identifier for the block
17 pub id: BlockId,
18
@@ -23,21 +23,21 @@ pub struct BasicBlock<'a> {
23 pub kind: BlockKind,
24
25 /// The ordered instructions in this block
26 - pub instructions: bumpalo::collections::Vec<'a, InstrIx>,
26 + pub instructions: Vec<InstrIx>,
27
28 /// The terminal instruction for the block
29 - pub terminal: Terminal<'a>,
29 + pub terminal: Terminal,
30
31 /// The immediate predecessors of this block
32 pub predecessors: IndexSet<BlockId>,
33
34 - pub phis: bumpalo::collections::Vec<'a, Phi<'a>>,
34 + pub phis: Vec<Phi>,
35 }
36
37 #[derive(Debug)]
38 -pub struct Phi<'a> {
39 - pub identifier: Identifier<'a>,
40 - pub operands: IndexMap<BlockId, Identifier<'a>>,
38 +pub struct Phi {
39 + pub identifier: Identifier,
40 + pub operands: IndexMap<BlockId, Identifier>,
41 }
42
43 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
compiler/forget/crates/forget_hir/src/environment.rs
+6 -31
@@ -2,9 +2,6 @@ use std::cell::{Cell, RefCell};
2 use std::collections::HashMap;
3 use std::rc::Rc;
4
5 -use bumpalo::boxed::Box;
6 -use bumpalo::collections::Vec;
7 -use bumpalo::Bump;
5 use forget_estree::BindingId;
6
7 use crate::{
@@ -15,7 +12,7 @@ use crate::{
12 /// compiled. Environments may not be reused between React functions, but *are*
13 /// shared between each React function and all its nested function expressions.
14 #[derive(Debug)]
18 -pub struct Environment<'a> {
15 +pub struct Environment {
16 /// The set of enabled compiler features
17 pub features: Features,
18
@@ -24,10 +21,6 @@ pub struct Environment<'a> {
21 #[allow(dead_code)]
22 registry: Registry,
23
27 - /// Arena allocator so that data for compilation can be efficiently allocated
28 - /// and the memory reclaimed when compilation completes.
29 - pub allocator: &'a Bump,
30 -
24 /// The next available block index
25 next_block_id: Cell<BlockId>,
26
@@ -36,13 +29,12 @@ pub struct Environment<'a> {
29
30 next_type_var_id: Cell<TypeVarId>,
31
39 - bindings: Rc<RefCell<HashMap<(bumpalo::collections::String<'a>, BindingId), Identifier<'a>>>>,
32 + bindings: Rc<RefCell<HashMap<(String, BindingId), Identifier>>>,
33 }
34
42 -impl<'a> Environment<'a> {
43 - pub fn new(allocator: &'a Bump, features: Features, registry: Registry) -> Self {
35 +impl Environment {
36 + pub fn new(features: Features, registry: Registry) -> Self {
37 Self {
45 - allocator,
38 features,
39 registry,
40 next_block_id: Cell::new(BlockId(0)),
@@ -52,23 +44,6 @@ impl<'a> Environment<'a> {
44 }
45 }
46
55 - /// Allocate a value into the environment's memory arena
56 - pub fn alloc<T>(&self, value: T) -> &'a mut T {
57 - self.allocator.alloc(value)
58 - }
59 -
60 - pub fn box_new<T>(&self, value: T) -> Box<'a, T> {
61 - Box::new_in(value, &self.allocator)
62 - }
63 -
64 - pub fn vec_new<T>(&self) -> Vec<'a, T> {
65 - Vec::new_in(&self.allocator)
66 - }
67 -
68 - pub fn vec_with_capacity<T>(&self, capacity: usize) -> Vec<'a, T> {
69 - Vec::with_capacity_in(capacity, &self.allocator)
70 - }
71 -
47 /// Get the next available block id
48 pub fn next_block_id(&self) -> BlockId {
49 let id = self.next_block_id.get();
@@ -90,8 +65,8 @@ impl<'a> Environment<'a> {
65 id
66 }
67
93 - pub fn resolve_binding_identifier(&self, name: &str, binding_id: BindingId) -> Identifier<'a> {
94 - let key_name = bumpalo::collections::String::from_str_in(name, &self.allocator);
68 + pub fn resolve_binding_identifier(&self, name: &str, binding_id: BindingId) -> Identifier {
69 + let key_name = name.to_string();
70 let mut bindings = self.bindings.borrow_mut();
71 if let Some(identifier) = bindings.get(&(key_name.clone(), binding_id)) {
72 identifier.clone()
compiler/forget/crates/forget_hir/src/function.rs
+50 -51
@@ -1,4 +1,3 @@
1 -use bumpalo::collections::{String, Vec};
1 use forget_diagnostics::Diagnostic;
2 use indexmap::IndexMap;
3
@@ -6,11 +5,11 @@ use crate::{BasicBlock, BlockId, FunctionExpression, IdentifierOperand, InstrIx,
5
6 /// Represents either a React function or a function expression
7 #[derive(Debug)]
9 -pub struct Function<'a> {
10 - pub id: Option<String<'a>>,
11 - pub body: HIR<'a>,
12 - pub params: Vec<'a, IdentifierOperand<'a>>,
13 - pub context: Vec<'a, IdentifierOperand<'a>>,
8 +pub struct Function {
9 + pub id: Option<String>,
10 + pub body: HIR,
11 + pub params: Vec<IdentifierOperand>,
12 + pub context: Vec<IdentifierOperand>,
13 pub is_async: bool,
14 pub is_generator: bool,
15 }
@@ -20,20 +19,20 @@ pub struct Function<'a> {
19 /// so that compiler passes can complete forward data flow analysis in a
20 /// single pass over the CFG in the case where there are no loops.
21 #[derive(Debug)]
23 -pub struct HIR<'a> {
22 +pub struct HIR {
23 /// The id of the first block
24 pub entry: BlockId,
25
26 /// Blocks are stored in a map for easy retrieval by their id,
27 /// but the blocks are in reverse postorder
29 - pub blocks: Blocks<'a>,
28 + pub blocks: Blocks,
29
30 /// All instructions for the block. This may contain unused items,
32 - pub instructions: Vec<'a, Instruction<'a>>,
31 + pub instructions: Vec<Instruction>,
32 }
33
35 -impl<'a> HIR<'a> {
36 - pub fn inline(&mut self, other: FunctionExpression<'a>) -> () {
34 +impl HIR {
35 + pub fn inline(&mut self, other: FunctionExpression) -> () {
36 let offset = self.instructions.len();
37 for mut instr in other.lowered_function.body.instructions.into_iter() {
38 instr.each_operand(|operand| {
@@ -54,11 +53,11 @@ impl<'a> HIR<'a> {
53 }
54
55 #[derive(Default, Debug)]
57 -pub struct Blocks<'a> {
58 - data: IndexMap<BlockId, Option<Box<BasicBlock<'a>>>>,
56 +pub struct Blocks {
57 + data: IndexMap<BlockId, Option<Box<BasicBlock>>>,
58 }
59
61 -impl<'a> Blocks<'a> {
60 +impl Blocks {
61 pub fn new() -> Self {
62 Self {
63 data: Default::default(),
@@ -75,7 +74,7 @@ impl<'a> Blocks<'a> {
74 self.data.len()
75 }
76
78 - pub fn insert(&mut self, block: Box<BasicBlock<'a>>) -> Option<Option<Box<BasicBlock<'a>>>> {
77 + pub fn insert(&mut self, block: Box<BasicBlock>) -> Option<Option<Box<BasicBlock>>> {
78 self.data.insert(block.id, Some(block))
79 }
80
@@ -83,7 +82,7 @@ impl<'a> Blocks<'a> {
82 self.data.keys().cloned().collect()
83 }
84
86 - pub fn remove(&mut self, id: BlockId) -> Box<BasicBlock<'a>> {
85 + pub fn remove(&mut self, id: BlockId) -> Box<BasicBlock> {
86 self.data.remove(&id).unwrap().unwrap()
87 }
88
@@ -91,38 +90,38 @@ impl<'a> Blocks<'a> {
90 self.data.extend(other.data);
91 }
92
94 - pub fn into_iter(self) -> BlocksIntoIter<'a> {
93 + pub fn into_iter(self) -> BlocksIntoIter {
94 BlocksIntoIter::new(self.data.into_iter())
95 }
96
98 - pub fn block(&self, id: BlockId) -> &BasicBlock<'a> {
97 + pub fn block(&self, id: BlockId) -> &BasicBlock {
98 self.data.get(&id).unwrap().as_ref().unwrap()
99 }
100
102 - pub fn block_mut(&mut self, id: BlockId) -> &mut BasicBlock<'a> {
101 + pub fn block_mut(&mut self, id: BlockId) -> &mut BasicBlock {
102 self.data.get_mut(&id).unwrap().as_mut().unwrap()
103 }
104
106 - pub fn iter(&self) -> BlocksIter<'_, 'a> {
105 + pub fn iter(&self) -> BlocksIter<'_> {
106 BlocksIter::new(self.data.iter())
107 }
108
110 - pub fn iter_mut(&mut self) -> BlocksIterMut<'_, 'a> {
109 + pub fn iter_mut(&mut self) -> BlocksIterMut<'_> {
110 BlocksIterMut::new(self.data.iter_mut())
111 }
112 }
114 -pub struct BlocksIntoIter<'a> {
115 - iter: indexmap::map::IntoIter<BlockId, Option<Box<BasicBlock<'a>>>>,
113 +pub struct BlocksIntoIter {
114 + iter: indexmap::map::IntoIter<BlockId, Option<Box<BasicBlock>>>,
115 }
116
118 -impl<'a> BlocksIntoIter<'a> {
119 - fn new(iter: indexmap::map::IntoIter<BlockId, Option<Box<BasicBlock<'a>>>>) -> Self {
117 +impl BlocksIntoIter {
118 + fn new(iter: indexmap::map::IntoIter<BlockId, Option<Box<BasicBlock>>>) -> Self {
119 Self { iter }
120 }
121 }
122
124 -impl<'a> Iterator for BlocksIntoIter<'a> {
125 - type Item = Box<BasicBlock<'a>>;
123 +impl Iterator for BlocksIntoIter {
124 + type Item = Box<BasicBlock>;
125
126 fn size_hint(&self) -> (usize, Option<usize>) {
127 self.iter.size_hint()
@@ -139,18 +138,18 @@ impl<'a> Iterator for BlocksIntoIter<'a> {
138 }
139 }
140
142 -pub struct BlocksIter<'b, 'a> {
143 - iter: indexmap::map::Iter<'b, BlockId, Option<Box<BasicBlock<'a>>>>,
141 +pub struct BlocksIter<'b> {
142 + iter: indexmap::map::Iter<'b, BlockId, Option<Box<BasicBlock>>>,
143 }
144
146 -impl<'b, 'a> BlocksIter<'b, 'a> {
147 - fn new(iter: indexmap::map::Iter<'b, BlockId, Option<Box<BasicBlock<'a>>>>) -> Self {
145 +impl<'b> BlocksIter<'b> {
146 + fn new(iter: indexmap::map::Iter<'b, BlockId, Option<Box<BasicBlock>>>) -> Self {
147 Self { iter }
148 }
149 }
150
152 -impl<'b, 'a> Iterator for BlocksIter<'b, 'a> {
153 - type Item = &'b BasicBlock<'a>;
151 +impl<'b> Iterator for BlocksIter<'b> {
152 + type Item = &'b BasicBlock;
153
154 fn size_hint(&self) -> (usize, Option<usize>) {
155 self.iter.size_hint()
@@ -164,18 +163,18 @@ impl<'b, 'a> Iterator for BlocksIter<'b, 'a> {
163 }
164 }
165
167 -pub struct BlocksIterMut<'b, 'a> {
168 - iter: indexmap::map::IterMut<'b, BlockId, Option<Box<BasicBlock<'a>>>>,
166 +pub struct BlocksIterMut<'b> {
167 + iter: indexmap::map::IterMut<'b, BlockId, Option<Box<BasicBlock>>>,
168 }
169
171 -impl<'b, 'a> BlocksIterMut<'b, 'a> {
172 - fn new(iter: indexmap::map::IterMut<'b, BlockId, Option<Box<BasicBlock<'a>>>>) -> Self {
170 +impl<'b> BlocksIterMut<'b> {
171 + fn new(iter: indexmap::map::IterMut<'b, BlockId, Option<Box<BasicBlock>>>) -> Self {
172 Self { iter }
173 }
174 }
175
177 -impl<'b, 'a> Iterator for BlocksIterMut<'b, 'a> {
178 - type Item = &'b mut BasicBlock<'a>;
176 +impl<'b> Iterator for BlocksIterMut<'b> {
177 + type Item = &'b mut BasicBlock;
178
179 fn size_hint(&self) -> (usize, Option<usize>) {
180 self.iter.size_hint()
@@ -189,14 +188,14 @@ impl<'b, 'a> Iterator for BlocksIterMut<'b, 'a> {
188 }
189 }
190
192 -pub struct BlockRewriter<'blocks, 'a> {
193 - blocks: &'blocks mut Blocks<'a>,
191 +pub struct BlockRewriter<'blocks> {
192 + blocks: &'blocks mut Blocks,
193 current: BlockId,
195 - new_blocks: std::vec::Vec<Box<BasicBlock<'a>>>,
194 + new_blocks: std::vec::Vec<Box<BasicBlock>>,
195 }
196
198 -impl<'blocks, 'a> BlockRewriter<'blocks, 'a> {
199 - pub fn new(blocks: &'blocks mut Blocks<'a>, entry: BlockId) -> Self {
197 +impl<'blocks> BlockRewriter<'blocks> {
198 + pub fn new(blocks: &'blocks mut Blocks, entry: BlockId) -> Self {
199 Self {
200 blocks,
201 current: entry,
@@ -206,7 +205,7 @@ impl<'blocks, 'a> BlockRewriter<'blocks, 'a> {
205
206 pub fn each_block<F>(&mut self, mut f: F) -> ()
207 where
209 - F: FnMut(Box<BasicBlock<'a>>, &mut Self) -> BlockRewriterAction<'a>,
208 + F: FnMut(Box<BasicBlock>, &mut Self) -> BlockRewriterAction,
209 {
210 let mut keys = self.blocks.block_ids();
211 loop {
@@ -236,7 +235,7 @@ impl<'blocks, 'a> BlockRewriter<'blocks, 'a> {
235
236 pub fn try_each_block<F>(&mut self, mut f: F) -> Result<(), Diagnostic>
237 where
239 - F: FnMut(Box<BasicBlock<'a>>, &mut Self) -> Result<BlockRewriterAction<'a>, Diagnostic>,
238 + F: FnMut(Box<BasicBlock>, &mut Self) -> Result<BlockRewriterAction, Diagnostic>,
239 {
240 let mut keys = self.blocks.block_ids();
241 loop {
@@ -270,22 +269,22 @@ impl<'blocks, 'a> BlockRewriter<'blocks, 'a> {
269 self.blocks.data.contains_key(&block_id)
270 }
271
273 - pub fn block(&self, block_id: BlockId) -> &BasicBlock<'a> {
272 + pub fn block(&self, block_id: BlockId) -> &BasicBlock {
273 assert_ne!(block_id, self.current);
274 self.blocks.block(block_id)
275 }
276
278 - pub fn block_mut(&mut self, block_id: BlockId) -> &mut BasicBlock<'a> {
277 + pub fn block_mut(&mut self, block_id: BlockId) -> &mut BasicBlock {
278 assert_ne!(block_id, self.current);
279 self.blocks.block_mut(block_id)
280 }
281
283 - pub fn add_block(&mut self, block: Box<BasicBlock<'a>>) {
282 + pub fn add_block(&mut self, block: Box<BasicBlock>) {
283 self.new_blocks.push(block);
284 }
285 }
286
288 -pub enum BlockRewriterAction<'a> {
289 - Keep(Box<BasicBlock<'a>>),
287 +pub enum BlockRewriterAction {
288 + Keep(Box<BasicBlock>),
289 Remove,
290 }
compiler/forget/crates/forget_hir/src/initialize.rs
+12 -12
@@ -11,7 +11,7 @@ use crate::{
11 /// Runs a variety of passes to put the HIR in canonical form. This should be called
12 /// after initial HIR construction and after any transformations that change the
13 /// shape of the control-flow graph.
14 -pub fn initialize_hir<'a>(hir: &mut HIR<'a>) -> Result<(), Diagnostic> {
14 +pub fn initialize_hir(hir: &mut HIR) -> Result<(), Diagnostic> {
15 prune_tombstones(hir);
16 reverse_postorder_blocks(hir);
17 remove_unreachable_for_updates(hir);
@@ -22,7 +22,7 @@ pub fn initialize_hir<'a>(hir: &mut HIR<'a>) -> Result<(), Diagnostic> {
22 Ok(())
23 }
24
25 -pub fn prune_tombstones<'a>(hir: &mut HIR<'a>) {
25 +pub fn prune_tombstones(hir: &mut HIR) {
26 for block in hir.blocks.iter_mut() {
27 block.instructions.retain(|ix| {
28 let instr = &hir.instructions[usize::from(*ix)];
@@ -34,12 +34,12 @@ pub fn prune_tombstones<'a>(hir: &mut HIR<'a>) {
34
35 /// Modifies the HIR to put the blocks in reverse postorder, with predecessors before
36 /// successors (except for the case of loops)
37 -pub fn reverse_postorder_blocks<'a>(hir: &mut HIR<'a>) {
37 +pub fn reverse_postorder_blocks(hir: &mut HIR) {
38 let mut visited = HashSet::<BlockId>::with_capacity(hir.blocks.len());
39 let mut postorder = std::vec::Vec::<BlockId>::with_capacity(hir.blocks.len());
40 - fn visit<'a>(
40 + fn visit(
41 block_id: BlockId,
42 - hir: &HIR<'a>,
42 + hir: &HIR,
43 visited: &mut HashSet<BlockId>,
44 postorder: &mut std::vec::Vec<BlockId>,
45 ) {
@@ -89,7 +89,7 @@ pub fn reverse_postorder_blocks<'a>(hir: &mut HIR<'a>) {
89 }
90
91 /// Prunes ForTerminal.update values (sets to None) if they are unreachable
92 -pub fn remove_unreachable_for_updates<'a>(hir: &mut HIR<'a>) {
92 +pub fn remove_unreachable_for_updates(hir: &mut HIR) {
93 BlockRewriter::new(&mut hir.blocks, hir.entry).each_block(|mut block, rewriter| {
94 if let TerminalValue::For(terminal) = &mut block.terminal.value {
95 if let Some(update) = terminal.update {
@@ -104,7 +104,7 @@ pub fn remove_unreachable_for_updates<'a>(hir: &mut HIR<'a>) {
104
105 /// Prunes unreachable fallthrough values, setting them to None if the referenced
106 /// block was not otherwise reachable.
107 -pub fn remove_unreachable_fallthroughs<'a>(hir: &mut HIR<'a>) {
107 +pub fn remove_unreachable_fallthroughs(hir: &mut HIR) {
108 BlockRewriter::new(&mut hir.blocks, hir.entry).each_block(|mut block, rewriter| {
109 block
110 .terminal
@@ -121,7 +121,7 @@ pub fn remove_unreachable_fallthroughs<'a>(hir: &mut HIR<'a>) {
121 }
122
123 /// Rewrites DoWhile statements into Gotos if the test block is not reachable
124 -pub fn remove_unreachable_do_while_statements<'a>(hir: &mut HIR<'a>) {
124 +pub fn remove_unreachable_do_while_statements(hir: &mut HIR) {
125 BlockRewriter::new(&mut hir.blocks, hir.entry).each_block(|mut block, rewriter| {
126 if let TerminalValue::DoWhile(terminal) = &mut block.terminal.value {
127 if !rewriter.contains(terminal.test) {
@@ -137,7 +137,7 @@ pub fn remove_unreachable_do_while_statements<'a>(hir: &mut HIR<'a>) {
137
138 /// Updates the instruction ids for all instructions and blocks
139 /// Relies on the blocks being in reverse postorder to ensure that id ordering is correct
140 -pub fn mark_instruction_ids<'a>(hir: &mut HIR<'a>) -> Result<(), Diagnostic> {
140 +pub fn mark_instruction_ids(hir: &mut HIR) -> Result<(), Diagnostic> {
141 let mut id_gen = InstructionIdGenerator::new();
142 let mut visited = HashSet::<(usize, usize)>::new();
143 for (ii, block) in hir.blocks.iter_mut().enumerate() {
@@ -161,15 +161,15 @@ pub struct BlockVisitedTwice {
161 }
162
163 /// Updates the predecessors of each block
164 -pub fn mark_predecessors<'a>(hir: &mut HIR<'a>) {
164 +pub fn mark_predecessors(hir: &mut HIR) {
165 for block in hir.blocks.iter_mut() {
166 block.predecessors.clear();
167 }
168 let mut visited = HashSet::<BlockId>::with_capacity(hir.blocks.len());
169 - fn visit<'a>(
169 + fn visit(
170 block_id: BlockId,
171 prev_id: Option<BlockId>,
172 - hir: &mut HIR<'a>,
172 + hir: &mut HIR,
173 visited: &mut HashSet<BlockId>,
174 ) {
175 let block = hir.blocks.block_mut(block_id);
compiler/forget/crates/forget_hir/src/inline_use_memo.rs
+3 -7
@@ -2,7 +2,6 @@ use std::cell::RefCell;
2 use std::collections::HashSet;
3 use std::rc::Rc;
4
5 -use bumpalo::collections::String;
5 use forget_diagnostics::Diagnostic;
6
7 use crate::{
@@ -63,10 +62,7 @@ use crate::{
62 /// [13] StoreLocal 'x', #6
63 /// ```
64 ///
66 -pub fn inline_use_memo<'a>(
67 - env: &Environment<'a>,
68 - fun: &mut Function<'a>,
69 -) -> Result<(), Diagnostic> {
65 +pub fn inline_use_memo(env: &Environment, fun: &mut Function) -> Result<(), Diagnostic> {
66 let mut use_memo_globals: HashSet<InstrIx> = Default::default();
67 let mut functions: HashSet<InstrIx> = Default::default();
68
@@ -108,7 +104,7 @@ pub fn inline_use_memo<'a>(
104 let temporary = Identifier {
105 id: temporary_id,
106 // NOTE: for memoization to work correctly this variable has to be named
111 - name: Some(String::from_str_in("t", &env.allocator)),
107 + name: Some("t".to_string()),
108 data: Rc::new(RefCell::new(IdentifierData {
109 mutable_range: MutableRange::new(),
110 scope: None,
@@ -232,7 +228,7 @@ pub fn inline_use_memo<'a>(
228 id: continuation_block_id,
229 instructions: continuation_instructions,
230 kind: block.kind,
235 - phis: env.vec_new(),
231 + phis: Default::default(),
232 predecessors: Default::default(),
233 terminal,
234 });
compiler/forget/crates/forget_hir/src/instruction.rs
+71 -72
@@ -2,21 +2,20 @@ use std::cell::RefCell;
2 use std::fmt::Display;
3 use std::rc::Rc;
4
5 -use bumpalo::collections::{String, Vec};
5 use forget_estree::BinaryOperator;
6
7 use crate::{Function, IdentifierId, InstrIx, InstructionId, ScopeId, Type};
8
9 #[derive(Debug)]
11 -pub struct Instruction<'a> {
10 +pub struct Instruction {
11 pub id: InstructionId,
13 - pub value: InstructionValue<'a>,
12 + pub value: InstructionValue,
13 }
14
16 -impl<'a> Instruction<'a> {
15 +impl Instruction {
16 pub fn each_identifier_store<F>(&mut self, mut f: F) -> ()
17 where
19 - F: FnMut(&mut LValue<'a>) -> (),
18 + F: FnMut(&mut LValue) -> (),
19 {
20 match &mut self.value {
21 InstructionValue::DeclareContext(instr) => {
@@ -43,7 +42,7 @@ impl<'a> Instruction<'a> {
42
43 pub fn try_each_identifier_store<F, E>(&mut self, mut f: F) -> Result<(), E>
44 where
46 - F: FnMut(&mut LValue<'a>) -> Result<(), E>,
45 + F: FnMut(&mut LValue) -> Result<(), E>,
46 {
47 match &mut self.value {
48 InstructionValue::DeclareContext(instr) => {
@@ -71,7 +70,7 @@ impl<'a> Instruction<'a> {
70
71 pub fn each_identifier_load<F>(&mut self, mut f: F) -> ()
72 where
74 - F: FnMut(&mut IdentifierOperand<'a>) -> (),
73 + F: FnMut(&mut IdentifierOperand) -> (),
74 {
75 match &mut self.value {
76 InstructionValue::LoadLocal(instr) => f(&mut instr.place),
@@ -151,46 +150,46 @@ impl<'a> Instruction<'a> {
150 }
151
152 #[derive(Debug)]
154 -pub enum InstructionValue<'a> {
155 - Array(Array<'a>),
156 - // Await(Await<'a>),
153 +pub enum InstructionValue {
154 + Array(Array),
155 + // Await(Await),
156 Binary(Binary),
158 - Call(Call<'a>),
159 - // ComputedDelete(ComputedDelete<'a>),
160 - // ComputedLoad(ComputedLoad<'a>),
161 - // ComputedStore(ComputedStore<'a>),
162 - // Debugger(Debugger<'a>),
163 - DeclareContext(DeclareContext<'a>),
164 - DeclareLocal(DeclareLocal<'a>),
165 - // Destructure(Destructure<'a>),
166 - Function(FunctionExpression<'a>),
167 - JSXElement(JSXElement<'a>),
168 - // JsxFragment(JsxFragment<'a>),
169 - // JsxText(JsxText<'a>),
157 + Call(Call),
158 + // ComputedDelete(ComputedDelete),
159 + // ComputedLoad(ComputedLoad),
160 + // ComputedStore(ComputedStore),
161 + // Debugger(Debugger),
162 + DeclareContext(DeclareContext),
163 + DeclareLocal(DeclareLocal),
164 + // Destructure(Destructure),
165 + Function(FunctionExpression),
166 + JSXElement(JSXElement),
167 + // JsxFragment(JsxFragment),
168 + // JsxText(JsxText),
169 LoadContext(LoadContext),
171 - LoadGlobal(LoadGlobal<'a>),
172 - LoadLocal(LoadLocal<'a>),
173 - // MethodCall(MethodCall<'a>),
174 - // New(New<'a>),
175 - // NextIterable(NextIterable<'a>),
176 - // Object(Object<'a>),
177 - Primitive(Primitive<'a>),
178 - // PropertyDelete(PropertyDelete<'a>),
179 - // PropertyLoad(PropertyLoad<'a>),
180 - // PropertyStore(PropertyStore<'a>),
181 - // RegExp(RegExp<'a>),
182 - // StoreContext(StoreContext<'a>),
183 - StoreLocal(StoreLocal<'a>),
184 - // TaggedTemplate(TaggedTemplate<'a>),
185 - // Template(Template<'a>),
186 - // TypeCast(TypeCast<'a>),
187 - // Unary(Unary<'a>),
170 + LoadGlobal(LoadGlobal),
171 + LoadLocal(LoadLocal),
172 + // MethodCall(MethodCall),
173 + // New(New),
174 + // NextIterable(NextIterable),
175 + // Object(Object),
176 + Primitive(Primitive),
177 + // PropertyDelete(PropertyDelete),
178 + // PropertyLoad(PropertyLoad),
179 + // PropertyStore(PropertyStore),
180 + // RegExp(RegExp),
181 + // StoreContext(StoreContext),
182 + StoreLocal(StoreLocal),
183 + // TaggedTemplate(TaggedTemplate),
184 + // Template(Template),
185 + // TypeCast(TypeCast),
186 + // Unary(Unary),
187 Tombstone,
188 }
189
190 #[derive(Debug)]
192 -pub struct Array<'a> {
193 - pub elements: Vec<'a, Option<PlaceOrSpread>>,
191 +pub struct Array {
192 + pub elements: Vec<Option<PlaceOrSpread>>,
193 }
194
195 #[derive(Debug)]
@@ -207,32 +206,32 @@ pub struct Binary {
206 }
207
208 #[derive(Debug)]
210 -pub struct Call<'a> {
209 +pub struct Call {
210 pub callee: Operand,
212 - pub arguments: Vec<'a, PlaceOrSpread>,
211 + pub arguments: Vec<PlaceOrSpread>,
212 }
213
214 #[derive(Debug)]
216 -pub struct FunctionExpression<'a> {
217 - pub dependencies: Vec<'a, Operand>,
218 - pub lowered_function: Box<Function<'a>>,
215 +pub struct FunctionExpression {
216 + pub dependencies: Vec<Operand>,
217 + pub lowered_function: Box<Function>,
218 }
219
220 #[derive(Debug, Clone, PartialEq, Eq)]
222 -pub struct Primitive<'a> {
223 - pub value: PrimitiveValue<'a>,
221 +pub struct Primitive {
222 + pub value: PrimitiveValue,
223 }
224
225 #[derive(Debug, Clone, PartialEq, Eq)]
227 -pub enum PrimitiveValue<'a> {
226 +pub enum PrimitiveValue {
227 Boolean(bool),
228 Null,
229 Number(Number),
231 - String(String<'a>),
230 + String(String),
231 Undefined,
232 }
233
235 -impl<'a> PrimitiveValue<'a> {
234 +impl PrimitiveValue {
235 pub fn is_truthy(&self) -> bool {
236 match &self {
237 PrimitiveValue::Boolean(value) => *value,
@@ -370,8 +369,8 @@ impl std::ops::Div for Number {
369 }
370
371 #[derive(Debug)]
373 -pub struct LoadLocal<'a> {
374 - pub place: IdentifierOperand<'a>,
372 +pub struct LoadLocal {
373 + pub place: IdentifierOperand,
374 }
375
376 #[derive(Debug)]
@@ -380,37 +379,37 @@ pub struct LoadContext {
379 }
380
381 #[derive(Debug, PartialEq, Eq, Clone)]
383 -pub struct LoadGlobal<'a> {
384 - pub name: String<'a>,
382 +pub struct LoadGlobal {
383 + pub name: String,
384 }
385
386 #[derive(Debug)]
388 -pub struct DeclareLocal<'a> {
389 - pub lvalue: LValue<'a>,
387 +pub struct DeclareLocal {
388 + pub lvalue: LValue,
389 }
390
391 #[derive(Debug)]
393 -pub struct DeclareContext<'a> {
394 - pub lvalue: LValue<'a>, // note: kind must be InstructionKind::Let
392 +pub struct DeclareContext {
393 + pub lvalue: LValue, // note: kind must be InstructionKind::Let
394 }
395
396 #[derive(Debug)]
398 -pub struct StoreLocal<'a> {
399 - pub lvalue: LValue<'a>,
397 +pub struct StoreLocal {
398 + pub lvalue: LValue,
399 pub value: Operand,
400 }
401
402 #[derive(Debug)]
404 -pub struct JSXElement<'a> {
403 +pub struct JSXElement {
404 pub tag: Operand,
406 - pub props: Vec<'a, JSXAttribute<'a>>,
407 - pub children: Option<Vec<'a, Operand>>,
405 + pub props: Vec<JSXAttribute>,
406 + pub children: Option<Vec<Operand>>,
407 }
408
409 #[derive(Debug)]
411 -pub enum JSXAttribute<'a> {
410 +pub enum JSXAttribute {
411 Spread { argument: Operand },
413 - Attribute { name: String<'a>, value: Operand },
412 + Attribute { name: String, value: Operand },
413 }
414
415 #[derive(Clone, Debug)]
@@ -420,14 +419,14 @@ pub struct Operand {
419 }
420
421 #[derive(Clone, Debug)]
423 -pub struct IdentifierOperand<'a> {
424 - pub identifier: Identifier<'a>,
422 +pub struct IdentifierOperand {
423 + pub identifier: Identifier,
424 pub effect: Option<Effect>,
425 }
426
427 #[derive(Debug)]
429 -pub struct LValue<'a> {
430 - pub identifier: IdentifierOperand<'a>,
428 +pub struct LValue {
429 + pub identifier: IdentifierOperand,
430 pub kind: InstructionKind,
431 }
432
@@ -503,10 +502,10 @@ impl Display for Effect {
502 }
503
504 #[derive(Clone, Debug)]
506 -pub struct Identifier<'a> {
505 +pub struct Identifier {
506 /// Uniquely identifiers this identifier
507 pub id: IdentifierId,
509 - pub name: Option<String<'a>>,
508 + pub name: Option<String>,
509
510 pub data: Rc<RefCell<IdentifierData>>,
511 }
compiler/forget/crates/forget_hir/src/merge_consecutive_blocks.rs
+1 -4
@@ -17,10 +17,7 @@ use crate::{
17 /// Note that this pass leaves value/loop blocks alone because they cannot
18 /// be merged without breaking the structure of the high-level terminals
19 /// that reference them.
20 -pub fn merge_consecutive_blocks<'a>(
21 - env: &Environment<'a>,
22 - fun: &mut Function<'a>,
23 -) -> Result<(), Diagnostic> {
20 +pub fn merge_consecutive_blocks(env: &Environment, fun: &mut Function) -> Result<(), Diagnostic> {
21 let mut merged = MergedBlocks::default();
22 let blocks = &mut fun.body.blocks;
23 let instructions = &mut fun.body.instructions;
compiler/forget/crates/forget_hir/src/print.rs
+27 -27
@@ -12,11 +12,11 @@ use crate::{
12 /// handle things like indentation and maybe wrapping long lines. The
13 /// `pretty` crate seems to have a lot of usage but the type signatures
14 /// are pretty tedious, we can make something much simpler.
15 -pub trait Print<'a> {
16 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result;
15 +pub trait Print {
16 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result;
17 }
18
19 -impl<'a> Function<'a> {
19 +impl Function {
20 pub fn debug(&self) {
21 let mut out = String::new();
22 self.print(&self.body, &mut out).unwrap();
@@ -24,8 +24,8 @@ impl<'a> Function<'a> {
24 }
25 }
26
27 -impl<'a> Print<'a> for Function<'a> {
28 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
27 +impl Print for Function {
28 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
29 ensure_sufficient_stack(|| {
30 writeln!(
31 out,
@@ -51,8 +51,8 @@ impl<'a> Print<'a> for Function<'a> {
51 }
52 }
53
54 -impl<'a> Print<'a> for BasicBlock<'a> {
55 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
54 +impl Print for BasicBlock {
55 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
56 writeln!(out, "{} ({})", self.id, self.kind)?;
57 if !self.predecessors.is_empty() {
58 write!(out, " predecessors: ")?;
@@ -83,8 +83,8 @@ impl<'a> Print<'a> for BasicBlock<'a> {
83 }
84 }
85
86 -impl<'a> Print<'a> for Phi<'a> {
87 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
86 +impl Print for Phi {
87 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
88 write!(out, " ")?;
89 self.identifier.print(hir, out)?;
90 write!(out, ": phi(")?;
@@ -100,8 +100,8 @@ impl<'a> Print<'a> for Phi<'a> {
100 }
101 }
102
103 -impl<'a> Print<'a> for Instruction<'a> {
104 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
103 +impl Print for Instruction {
104 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
105 write!(out, " {} ", self.id)?;
106 self.value.print(hir, out)?;
107 writeln!(out, "")?;
@@ -109,8 +109,8 @@ impl<'a> Print<'a> for Instruction<'a> {
109 }
110 }
111
112 -impl<'a> Print<'a> for InstructionValue<'a> {
113 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
112 +impl Print for InstructionValue {
113 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
114 match self {
115 InstructionValue::Array(value) => {
116 write!(out, "Array [")?;
@@ -211,8 +211,8 @@ impl<'a> Print<'a> for InstructionValue<'a> {
211 }
212 }
213
214 -impl<'a> Print<'a> for PlaceOrSpread {
215 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
214 +impl Print for PlaceOrSpread {
215 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
216 match self {
217 PlaceOrSpread::Place(place) => place.print(hir, out),
218 PlaceOrSpread::Spread(place) => {
@@ -224,8 +224,8 @@ impl<'a> Print<'a> for PlaceOrSpread {
224 }
225 }
226
227 -impl<'a> Print<'a> for Operand {
228 - fn print(&self, _hir: &HIR<'a>, out: &mut impl Write) -> Result {
227 +impl Print for Operand {
228 + fn print(&self, _hir: &HIR, out: &mut impl Write) -> Result {
229 write!(
230 out,
231 "{} {}",
@@ -238,15 +238,15 @@ impl<'a> Print<'a> for Operand {
238 }
239 }
240
241 -impl<'a> Print<'a> for LValue<'a> {
242 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
241 +impl Print for LValue {
242 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
243 write!(out, "{} ", self.kind)?;
244 self.identifier.print(hir, out)
245 }
246 }
247
248 -impl<'a> Print<'a> for IdentifierOperand<'a> {
249 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
248 +impl Print for IdentifierOperand {
249 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
250 write!(
251 out,
252 "{} ",
@@ -259,8 +259,8 @@ impl<'a> Print<'a> for IdentifierOperand<'a> {
259 }
260 }
261
262 -impl<'a> Print<'a> for Identifier<'a> {
263 - fn print(&self, _hir: &HIR<'a>, out: &mut impl Write) -> Result {
262 +impl Print for Identifier {
263 + fn print(&self, _hir: &HIR, out: &mut impl Write) -> Result {
264 write!(
265 out,
266 "{}{}",
@@ -273,8 +273,8 @@ impl<'a> Print<'a> for Identifier<'a> {
273 }
274 }
275
276 -impl<'a> Print<'a> for Terminal<'a> {
277 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
276 +impl Print for Terminal {
277 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
278 write!(out, " {} ", self.id)?;
279 self.value.print(hir, out)?;
280 writeln!(out, "")?;
@@ -282,8 +282,8 @@ impl<'a> Print<'a> for Terminal<'a> {
282 }
283 }
284
285 -impl<'a> Print<'a> for TerminalValue<'a> {
286 - fn print(&self, hir: &HIR<'a>, out: &mut impl Write) -> Result {
285 +impl Print for TerminalValue {
286 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
287 match self {
288 TerminalValue::Return(terminal) => {
289 write!(out, "Return ")?;
compiler/forget/crates/forget_hir/src/terminal.rs
+6 -8
@@ -4,13 +4,13 @@ use crate::{BlockId, InstructionId};
4 /// Terminals represent statements or expressions that affect control flow,
5 /// such as for-of, if-else, return, logical (??), ternaries (?:), etc.
6 #[derive(Debug)]
7 -pub struct Terminal<'a> {
7 +pub struct Terminal {
8 pub id: InstructionId,
9 - pub value: TerminalValue<'a>,
9 + pub value: TerminalValue,
10 }
11
12 #[derive(Debug)]
13 -pub enum TerminalValue<'a> {
13 +pub enum TerminalValue {
14 Branch(BranchTerminal),
15 DoWhile(DoWhileTerminal),
16 // ForOf(ForOfTerminal),
@@ -25,11 +25,11 @@ pub enum TerminalValue<'a> {
25 // Switch(SwitchTerminal),
26 // Ternary(TernaryTerminal),
27 // Throw(ThrowTerminal),
28 - Unsupported(UnsupportedTerminal<'a>),
28 + Unsupported(UnsupportedTerminal),
29 // While(WhileTerminal),
30 }
31
32 -impl<'a> TerminalValue<'a> {
32 +impl TerminalValue {
33 pub fn map_optional_fallthroughs<F>(&mut self, f: F) -> ()
34 where
35 F: Fn(BlockId) -> Option<BlockId>,
@@ -103,9 +103,7 @@ impl<'a> TerminalValue<'a> {
103 }
104
105 #[derive(Debug)]
106 -pub struct UnsupportedTerminal<'a> {
107 - phantom: std::marker::PhantomData<&'a ()>,
108 -}
106 +pub struct UnsupportedTerminal {}
107
108 #[derive(Debug)]
109 pub struct BranchTerminal {
compiler/forget/crates/forget_optimization/Cargo.toml
-1
@@ -19,7 +19,6 @@ forget_ssa = { workspace = true }
19 forget_build_hir = { workspace = true }
20 forget_utils = { workspace = true }
21 forget_diagnostics = { workspace = true }
22 -bumpalo = { workspace = true }
22 indexmap = { workspace = true }
23 miette = { workspace = true }
24 thiserror = { workspace = true }
\ No newline at end of file
compiler/forget/crates/forget_optimization/src/constant_propagation.rs
+30 -36
@@ -9,18 +9,15 @@ use forget_hir::{
9 };
10 use forget_ssa::eliminate_redundant_phis;
11
12 -pub fn constant_propagation<'a>(
13 - env: &Environment<'a>,
14 - fun: &mut Function<'a>,
15 -) -> Result<(), Diagnostic> {
12 +pub fn constant_propagation(env: &Environment, fun: &mut Function) -> Result<(), Diagnostic> {
13 let mut constants = Constants::new();
14 constant_propagation_impl(env, fun, &mut constants)
15 }
16
20 -fn constant_propagation_impl<'a>(
21 - env: &Environment<'a>,
22 - fun: &mut Function<'a>,
23 - constants: &mut Constants<'a>,
17 +fn constant_propagation_impl(
18 + env: &Environment,
19 + fun: &mut Function,
20 + constants: &mut Constants,
21 ) -> Result<(), Diagnostic> {
22 loop {
23 let have_terminals_changed = apply_constant_propagation(env, fun, constants)?;
@@ -55,16 +52,16 @@ fn constant_propagation_impl<'a>(
52 Ok(())
53 }
54
58 -fn apply_constant_propagation<'a>(
59 - env: &Environment<'a>,
60 - fun: &mut Function<'a>,
61 - constants: &mut Constants<'a>,
55 +fn apply_constant_propagation(
56 + env: &Environment,
57 + fun: &mut Function,
58 + constants: &mut Constants,
59 ) -> Result<bool, Diagnostic> {
60 let mut has_changes = false;
61
62 for block in fun.body.blocks.iter_mut() {
63 for phi in block.phis.iter() {
67 - let mut value: Option<Constant<'a>> = None;
64 + let mut value: Option<Constant> = None;
65 for (_, operand) in &phi.operands {
66 if let Some(operand_value) = constants.get(&operand.id) {
67 match &mut value {
@@ -128,10 +125,7 @@ fn apply_constant_propagation<'a>(
125 Ok(has_changes)
126 }
127
131 -fn read_primitive_instruction<'a>(
132 - instrs: &[Instruction<'a>],
133 - operand: &Operand,
134 -) -> Option<Primitive<'a>> {
128 +fn read_primitive_instruction(instrs: &[Instruction], operand: &Operand) -> Option<Primitive> {
129 let instr = &instrs[usize::from(operand.ix)].value;
130 if let InstructionValue::Primitive(primitive) = instr {
131 Some(primitive.clone())
@@ -140,11 +134,11 @@ fn read_primitive_instruction<'a>(
134 }
135 }
136
143 -fn evaluate_instruction<'a>(
144 - env: &Environment<'a>,
145 - instrs: &[Instruction<'a>],
146 - mut instr: &mut InstructionValue<'a>,
147 - constants: &mut Constants<'a>,
137 +fn evaluate_instruction(
138 + env: &Environment,
139 + instrs: &[Instruction],
140 + mut instr: &mut InstructionValue,
141 + constants: &mut Constants,
142 ) -> Result<(), Diagnostic> {
143 let read_constant = |operand: &Operand| {
144 let instr = &instrs[usize::from(operand.ix)].value;
@@ -189,7 +183,7 @@ fn evaluate_instruction<'a>(
183 // the function (using its context variables list)
184 // - Track the last such filtered Constants instance we visited the function
185 // with. Only visit again if the Constants have changed.
192 - let mut inner_constants: Constants<'a> = value
186 + let mut inner_constants: Constants = value
187 .lowered_function
188 .context
189 .iter()
@@ -207,12 +201,12 @@ fn evaluate_instruction<'a>(
201 Ok(())
202 }
203
210 -fn apply_binary_operator<'a>(
211 - _env: &Environment<'a>,
212 - left: Primitive<'a>,
204 +fn apply_binary_operator(
205 + _env: &Environment,
206 + left: Primitive,
207 operator: BinaryOperator,
214 - right: Primitive<'a>,
215 -) -> Option<Primitive<'a>> {
208 + right: Primitive,
209 +) -> Option<Primitive> {
210 match (left.value, right.value) {
211 (PrimitiveValue::Number(left), PrimitiveValue::Number(right)) => match operator {
212 BinaryOperator::Add => Some(Primitive {
@@ -271,16 +265,16 @@ fn apply_binary_operator<'a>(
265 }
266 }
267
274 -type Constants<'a> = HashMap<IdentifierId, Constant<'a>>;
268 +type Constants = HashMap<IdentifierId, Constant>;
269
270 #[derive(Debug, Clone, PartialEq, Eq)]
277 -enum Constant<'a> {
278 - Global(LoadGlobal<'a>),
279 - Primitive(Primitive<'a>),
271 +enum Constant {
272 + Global(LoadGlobal),
273 + Primitive(Primitive),
274 }
275
282 -impl<'a> From<&Constant<'a>> for InstructionValue<'a> {
283 - fn from(value: &Constant<'a>) -> Self {
276 +impl From<&Constant> for InstructionValue {
277 + fn from(value: &Constant) -> Self {
278 match value {
279 Constant::Global(value) => InstructionValue::LoadGlobal(value.clone()),
280 Constant::Primitive(value) => InstructionValue::Primitive(value.clone()),
@@ -288,8 +282,8 @@ impl<'a> From<&Constant<'a>> for InstructionValue<'a> {
282 }
283 }
284
291 -impl<'a> From<Constant<'a>> for InstructionValue<'a> {
292 - fn from(value: Constant<'a>) -> Self {
285 +impl From<Constant> for InstructionValue {
286 + fn from(value: Constant) -> Self {
287 match value {
288 Constant::Global(value) => InstructionValue::LoadGlobal(value),
289 Constant::Primitive(value) => InstructionValue::Primitive(value),
compiler/forget/crates/forget_ssa/Cargo.toml
-1
@@ -16,7 +16,6 @@ repository.workspace = true
16 forget_hir = { workspace = true }
17 forget_utils = { workspace = true }
18 forget_diagnostics = { workspace = true }
19 -bumpalo = { workspace = true }
19 indexmap = { workspace = true }
20 miette = { workspace = true }
21 thiserror = { workspace = true }
\ No newline at end of file
compiler/forget/crates/forget_ssa/src/eliminate_redundant_phis.rs
+3 -4
@@ -1,7 +1,6 @@
1 use std::collections::{HashMap, HashSet};
2
3 use forget_hir::{BlockId, Environment, Function, Identifier, IdentifierId, InstructionValue};
4 -use forget_utils::RetainMut;
4
5 /// Pass to eliminate redundant phi nodes:
6 /// all operands are the same identifier, ie `x2 = phi(x1, x1, x1)`.
@@ -15,8 +14,8 @@ use forget_utils::RetainMut;
14 /// phi is encountered we add a mapping (eg x2 -> x1) to a rewrite table. Subsequent instructions, terminals,
15 /// and phis rewrite all their identifiers based on this table. The algorithm loops over the CFG repeatedly
16 /// until there are no new rewrites: for a CFG without back-edges it completes in a single pass.
18 -type Rewrites<'a> = HashMap<IdentifierId, Identifier<'a>>;
19 -pub fn eliminate_redundant_phis<'a>(env: &Environment, fun: &mut Function<'a>) {
17 +type Rewrites = HashMap<IdentifierId, Identifier>;
18 +pub fn eliminate_redundant_phis(env: &Environment, fun: &mut Function) {
19 let hir = &mut fun.body;
20 let mut rewrites = Rewrites::new();
21
@@ -97,7 +96,7 @@ pub fn eliminate_redundant_phis<'a>(env: &Environment, fun: &mut Function<'a>) {
96 }
97 }
98
100 -fn rewrite<'a>(rewrites: &Rewrites<'a>, identifier: &mut Identifier<'a>) {
99 +fn rewrite(rewrites: &Rewrites, identifier: &mut Identifier) {
100 if let Some(rewrite) = rewrites.get(&identifier.id) {
101 *identifier = rewrite.clone()
102 }
compiler/forget/crates/forget_ssa/src/enter.rs
+39 -40
@@ -1,7 +1,6 @@
1 use std::cell::RefCell;
2 use std::rc::Rc;
3
4 -use bumpalo::collections::Vec;
4 use forget_diagnostics::{invariant, Diagnostic};
5 use forget_hir::{
6 BasicBlock, BlockId, Blocks, Environment, Function, Identifier, IdentifierData, IdentifierId,
@@ -9,15 +8,15 @@ use forget_hir::{
8 };
9 use indexmap::{IndexMap, IndexSet};
10
12 -pub fn enter_ssa<'a>(env: &Environment<'a>, fun: &mut Function<'a>) -> Result<(), Diagnostic> {
11 +pub fn enter_ssa(env: &Environment, fun: &mut Function) -> Result<(), Diagnostic> {
12 assert!(fun.context.is_empty());
13 enter_ssa_impl(env, fun, None)
14 }
15
17 -pub fn enter_ssa_impl<'a>(
18 - env: &Environment<'a>,
19 - fun: &mut Function<'a>,
20 - context_defs: Option<IndexMap<IdentifierId, Identifier<'a>>>,
16 +pub fn enter_ssa_impl(
17 + env: &Environment,
18 + fun: &mut Function,
19 + context_defs: Option<IndexMap<IdentifierId, Identifier>>,
20 ) -> Result<(), Diagnostic> {
21 let blocks = &fun.body.blocks;
22 let instructions = &mut fun.body.instructions;
@@ -40,10 +39,10 @@ pub fn enter_ssa_impl<'a>(
39 Ok(())
40 }
41
43 -fn visit_instructions<'a, 'e, 'f>(
44 - env: &Environment<'a>,
45 - builder: &mut Builder<'a, 'e, 'f>,
46 - instructions: &mut Vec<'a, Instruction<'a>>,
42 +fn visit_instructions<'e, 'f>(
43 + env: &Environment,
44 + builder: &mut Builder<'e, 'f>,
45 + instructions: &mut Vec<Instruction>,
46 ) -> Result<(), Diagnostic> {
47 builder.each_block(|block, builder| {
48 for instr_ix in &block.instructions {
@@ -75,11 +74,11 @@ fn visit_instructions<'a, 'e, 'f>(
74 }
75
76 #[derive(Debug)]
78 -struct Builder<'a, 'e, 'f> {
79 - env: &'e Environment<'a>,
80 - blocks: &'f Blocks<'a>,
77 +struct Builder<'e, 'f> {
78 + env: &'e Environment,
79 + blocks: &'f Blocks,
80
82 - states: IndexMap<BlockId, BlockState<'a>>,
81 + states: IndexMap<BlockId, BlockState>,
82 current: BlockId,
83 unsealed_predecessors: IndexMap<BlockId, usize>,
84 unknown: IndexSet<IdentifierId>,
@@ -87,34 +86,34 @@ struct Builder<'a, 'e, 'f> {
86 }
87
88 #[derive(Debug)]
90 -struct BlockState<'a> {
91 - defs: IndexMap<IdentifierId, Identifier<'a>>,
92 - incomplete_phis: Vec<'a, IncompletePhi<'a>>,
93 - phis: Vec<'a, Phi<'a>>,
89 +struct BlockState {
90 + defs: IndexMap<IdentifierId, Identifier>,
91 + incomplete_phis: Vec<IncompletePhi>,
92 + phis: Vec<Phi>,
93 }
94
96 -impl<'a> BlockState<'a> {
97 - fn new(env: &Environment<'a>) -> Self {
95 +impl BlockState {
96 + fn new() -> Self {
97 Self {
98 defs: Default::default(),
100 - incomplete_phis: env.vec_new(),
101 - phis: env.vec_new(),
99 + incomplete_phis: Default::default(),
100 + phis: Default::default(),
101 }
102 }
103 }
104
105 #[derive(Debug)]
107 -struct IncompletePhi<'a> {
108 - old_id: Identifier<'a>,
109 - new_id: Identifier<'a>,
106 +struct IncompletePhi {
107 + old_id: Identifier,
108 + new_id: Identifier,
109 }
110
112 -impl<'a, 'e, 'f> Builder<'a, 'e, 'f> {
113 - fn new(env: &'e Environment<'a>, entry: BlockId, blocks: &'f Blocks<'a>) -> Self {
111 +impl<'e, 'f> Builder<'e, 'f> {
112 + fn new(env: &'e Environment, entry: BlockId, blocks: &'f Blocks) -> Self {
113 let states = blocks
114 .block_ids()
115 .into_iter()
117 - .map(|block_id| (block_id, BlockState::new(env)))
116 + .map(|block_id| (block_id, BlockState::new()))
117 .collect();
118 Self {
119 env,
@@ -127,12 +126,12 @@ impl<'a, 'e, 'f> Builder<'a, 'e, 'f> {
126 }
127 }
128
130 - fn initialize_context(&mut self, defs: IndexMap<IdentifierId, Identifier<'a>>) {
129 + fn initialize_context(&mut self, defs: IndexMap<IdentifierId, Identifier>) {
130 let state = self.states.get_mut(&self.current).unwrap();
131 state.defs = defs;
132 }
133
135 - fn complete(self) -> IndexMap<BlockId, BlockState<'a>> {
134 + fn complete(self) -> IndexMap<BlockId, BlockState> {
135 self.states
136 }
137
@@ -140,7 +139,7 @@ impl<'a, 'e, 'f> Builder<'a, 'e, 'f> {
139 self.env.next_identifier_id()
140 }
141
143 - fn visit_store(&mut self, lvalue: &mut LValue<'a>) -> Result<(), Diagnostic> {
142 + fn visit_store(&mut self, lvalue: &mut LValue) -> Result<(), Diagnostic> {
143 let old_identifier = &lvalue.identifier.identifier;
144 // TODO: use Result (?)
145 invariant(!self.unknown.contains(&old_identifier.id), || {
@@ -163,7 +162,7 @@ impl<'a, 'e, 'f> Builder<'a, 'e, 'f> {
162 Ok(())
163 }
164
166 - fn visit_param(&mut self, param: &mut IdentifierOperand<'a>) -> () {
165 + fn visit_param(&mut self, param: &mut IdentifierOperand) -> () {
166 let old_identifier = &param.identifier;
167 let new_identifier = self.make_identifier(old_identifier);
168 let state = self.states.get_mut(&self.current).unwrap();
@@ -171,12 +170,12 @@ impl<'a, 'e, 'f> Builder<'a, 'e, 'f> {
170 param.identifier = new_identifier;
171 }
172
174 - fn visit_load(&mut self, local: &mut IdentifierOperand<'a>) -> () {
173 + fn visit_load(&mut self, local: &mut IdentifierOperand) -> () {
174 let new_identifier = self.get_id_at(self.current, &local.identifier);
175 local.identifier = new_identifier;
176 }
177
179 - fn get_id_at(&mut self, block_id: BlockId, old_identifier: &Identifier<'a>) -> Identifier<'a> {
178 + fn get_id_at(&mut self, block_id: BlockId, old_identifier: &Identifier) -> Identifier {
179 // Check if we've already resolved this identifier in this block
180 let state = self.states.get(&block_id).unwrap();
181 if let Some(identifier) = state.defs.get(&old_identifier.id) {
@@ -219,9 +218,9 @@ impl<'a, 'e, 'f> Builder<'a, 'e, 'f> {
218 fn add_phi(
219 &mut self,
220 block_id: BlockId,
222 - old_identifier: &Identifier<'a>,
223 - new_identifier: Identifier<'a>,
224 - ) -> Identifier<'a> {
221 + old_identifier: &Identifier,
222 + new_identifier: Identifier,
223 + ) -> Identifier {
224 let mut phi = Phi {
225 identifier: new_identifier.clone(),
226 operands: Default::default(),
@@ -237,7 +236,7 @@ impl<'a, 'e, 'f> Builder<'a, 'e, 'f> {
236 new_identifier
237 }
238
240 - fn make_identifier(&self, old_identifier: &Identifier<'a>) -> Identifier<'a> {
239 + fn make_identifier(&self, old_identifier: &Identifier) -> Identifier {
240 let old_data = old_identifier.data.borrow();
241 Identifier {
242 id: self.next_ssa_id(),
@@ -252,7 +251,7 @@ impl<'a, 'e, 'f> Builder<'a, 'e, 'f> {
251
252 fn fix_incomplete_phis(&mut self, block_id: BlockId) -> () {
253 let state = self.states.get_mut(&block_id).unwrap();
255 - let incomplete_phis = std::mem::replace(&mut state.incomplete_phis, self.env.vec_new());
254 + let incomplete_phis = std::mem::take(&mut state.incomplete_phis);
255 for phi in incomplete_phis {
256 self.add_phi(block_id, &phi.old_id, phi.new_id);
257 }
@@ -260,7 +259,7 @@ impl<'a, 'e, 'f> Builder<'a, 'e, 'f> {
259
260 fn each_block<F>(&mut self, mut f: F) -> Result<(), Diagnostic>
261 where
263 - F: FnMut(&BasicBlock<'a>, &mut Self) -> Result<(), Diagnostic>,
262 + F: FnMut(&BasicBlock, &mut Self) -> Result<(), Diagnostic>,
263 {
264 let mut visited = IndexSet::new();
265 let block_ids = self.blocks.block_ids();
compiler/forget/crates/forget_ssa/src/leave.rs
+1 -1
@@ -1,5 +1,5 @@
1 use forget_hir::{Environment, HIR};
2
3 -pub fn leave_ssa<'a>(_env: &'a Environment, _hir: &mut HIR<'a>) {
3 +pub fn leave_ssa(_env: &Environment, _hir: &mut HIR) {
4 todo!("leave_ssa()");
5 }
compiler/forget/crates/forget_utils/Cargo.toml
-1
@@ -13,5 +13,4 @@ repository.workspace = true
13 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
14
15 [dependencies]
16 -bumpalo = { workspace = true }
16 stacker = { workspace = true }
compiler/forget/crates/forget_utils/src/lib.rs
-2
@@ -1,5 +1,3 @@
1 mod ensure_sufficient_stack;
2 -mod retain_mut;
2
3 pub use ensure_sufficient_stack::*;
5 -pub use retain_mut::*;
compiler/forget/crates/forget_utils/src/retain_mut.rs deleted
-113
@@ -1,113 +0,0 @@
1 -use bumpalo::collections::Vec;
2 -
3 -pub trait RetainMut<T> {
4 - fn retain_mut<F>(&mut self, f: F) -> ()
5 - where
6 - F: FnMut(&mut T) -> bool;
7 -}
8 -
9 -impl<'a, T> RetainMut<T> for Vec<'a, T> {
10 - fn retain_mut<F>(&mut self, mut f: F) -> ()
11 - where
12 - F: FnMut(&mut T) -> bool,
13 - {
14 - // NOTE: implementation adapted from retain_mut crate
15 - // which is in turn adapted from Rust stdlib
16 - // https://docs.rs/retain_mut/latest/src/retain_mut/lib.rs.html#68-69
17 -
18 - let original_len = self.len();
19 - // Avoid double drop if the drop guard is not executed,
20 - // since we may make some holes during the process.
21 - unsafe { self.set_len(0) };
22 -
23 - // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked]
24 - // |<- processed len ->| ^- next to check
25 - // |<- deleted cnt ->|
26 - // |<- original_len ->|
27 - // Kept: Elements which predicate returns true on.
28 - // Hole: Moved or dropped element slot.
29 - // Unchecked: Unchecked valid elements.
30 - //
31 - // This drop guard will be invoked when predicate or `drop` of element panicked.
32 - // It shifts unchecked elements to cover holes and `set_len` to the correct length.
33 - // In cases when predicate and `drop` never panick, it will be optimized out.
34 - struct BackshiftOnDrop<'a, 'b, T> {
35 - v: &'b mut Vec<'a, T>,
36 - processed_len: usize,
37 - deleted_cnt: usize,
38 - original_len: usize,
39 - }
40 -
41 - impl<T> Drop for BackshiftOnDrop<'_, '_, T> {
42 - fn drop(&mut self) {
43 - if self.deleted_cnt > 0 {
44 - // SAFETY: Trailing unchecked items must be valid since we never touch them.
45 - unsafe {
46 - std::ptr::copy(
47 - self.v.as_ptr().add(self.processed_len),
48 - self.v
49 - .as_mut_ptr()
50 - .add(self.processed_len - self.deleted_cnt),
51 - self.original_len - self.processed_len,
52 - );
53 - }
54 - }
55 - // SAFETY: After filling holes, all items are in contiguous memory.
56 - unsafe {
57 - self.v.set_len(self.original_len - self.deleted_cnt);
58 - }
59 - }
60 - }
61 -
62 - let mut g = BackshiftOnDrop {
63 - v: self,
64 - processed_len: 0,
65 - deleted_cnt: 0,
66 - original_len,
67 - };
68 -
69 - fn process_loop<F, T, const DELETED: bool>(
70 - original_len: usize,
71 - f: &mut F,
72 - g: &mut BackshiftOnDrop<'_, '_, T>,
73 - ) where
74 - F: FnMut(&mut T) -> bool,
75 - {
76 - while g.processed_len != original_len {
77 - // SAFETY: Unchecked element must be valid.
78 - let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) };
79 - if !f(cur) {
80 - // Advance early to avoid double drop if `drop_in_place` panicked.
81 - g.processed_len += 1;
82 - g.deleted_cnt += 1;
83 - // SAFETY: We never touch this element again after dropped.
84 - unsafe { std::ptr::drop_in_place(cur) };
85 - // We already advanced the counter.
86 - if DELETED {
87 - continue;
88 - } else {
89 - break;
90 - }
91 - }
92 - if DELETED {
93 - // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element.
94 - // We use copy for move, and never touch this element again.
95 - unsafe {
96 - let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt);
97 - std::ptr::copy_nonoverlapping(cur, hole_slot, 1);
98 - }
99 - }
100 - g.processed_len += 1;
101 - }
102 - }
103 -
104 - // Stage 1: Nothing was deleted.
105 - process_loop::<F, T, false>(original_len, &mut f, &mut g);
106 -
107 - // Stage 2: Some elements were deleted.
108 - process_loop::<F, T, true>(original_len, &mut f, &mut g);
109 -
110 - // All item are processed. This can be optimized to `set_len` by LLVM.
111 - drop(g);
112 - }
113 -}