Commit Graph
1708 Commits
Author SHA1 Message Date
Sathya Gunasekaran 6af9c25300 [test] Run Forget only on top level functions 2023-01-14 10:19:40 +00:00
Sathya Gunasekaran 5fa3d41b22 [λ] Make function expr tests be reactive to input
This lets us memoize more and test function expressions better
2023-01-14 10:19:39 +00:00
Sathya Gunasekaran e8cad1584c [be] Refactor capturePureScopes to be more generic 2023-01-14 10:19:39 +00:00
Sathya Gunasekaran b1eb22d941 [be] Don't show duplicate codegen tab
The JS tab and the codegen tab are the same.
2023-01-13 16:33:04 +00:00
Sathya Gunasekaran ddc135cf40 [be] Type CompilerPipeline as Generator 2023-01-13 16:26:09 +00:00
Sathya Gunasekaran d25c2d0d58 [be] Make ts emit ES2015
This gives allows us to use generators without failing type checking.
2023-01-13 16:26:04 +00:00
Lauren Tan 7c65f62c27 Collect bailouts in BuildHIR::lowerStatement
Remove invariants and collect all errors
2023-01-13 16:14:07 -05:00
Lauren Tan 73f09248fb Add Result
Adds a direct translation of Rust's Result type, for later use in BuildHIR and 
possibly other passes
2023-01-12 19:35:20 -05:00
Lauren Tan 325987d744 Delete old CompilerError module
This was a carryover from the old architecture; we can remove it now to get rid 
of the indirection.
2023-01-12 19:35:19 -05:00
Joe Savona 321d7b7d00 [be] Clean up public exports
Cleans up the public exports for the package itself: 

* `parseFunctions()` was only used in playground, so this moves the definition 
there. I had to update playground's dependencies to ensure the babel version 
matched. 

* Flattens away the `HIR` const in the export, and exports just 4 functions all 
at the top-level: `run()`, `compile()`, `printHIR()`, and 
`printReactiveFunction()`. 

This will make it very easy to split the core compiler into a separate package 
from the babel plugin, though i'm not sure it's worth doing that (yet).
2023-01-12 12:16:07 -08:00
Joe Savona bd7e19b85f Codegen is from ReactiveFunction->AST only
Other than BuildReactiveFunction (HIR -> ReactiveFunction), Codegen.ts was the 
only other remaining place that we use HIRTreeVisitor. However, we've already 
switched the compiler to use the new form of codegen, 
CodegenReactiveFunction.ts. This PR extracts the shared code from Codegen.ts 
into the latter, and deletes the unused bits of Codegen.ts which relied on the 
visitor API. 

This now frees us up to merge BuildReactiveFunction and HIRTreeVisitor, removing 
all the complexity of the visitor trait and type params. 

Note that the `ReactiveFunction` data type can represent non-reactive functions. 
So we can still compile non-React code after this change, the pipeline is `AST` 
-> (BuildHIR) -> `HIR` -> (BuildReactiveFunction) -> `ReactiveFunction` -> 
(CodegenReactiveFunction) -> `AST`. Which is the exact sequence I mapped out at 
the start of this project ;-) (happy that worked out!)
2023-01-12 11:49:47 -08:00
Joe Savona da21e9c525 Switch to new BuildReactiveFunction passes 2023-01-12 11:06:40 -08:00
Joe Savona a40ade1e61 Fixes, identical output in new version 2023-01-12 09:43:17 -08:00
Joe Savona 919f193934 MergeOverlappingScopes visits value block final values 2023-01-12 09:12:11 -08:00
Joe Savona 99dcf03852 AlignBlockScopes visits value block final values 2023-01-12 09:12:08 -08:00
Joe Savona 09246207c7 Value block final value has an InstrId 2023-01-12 09:12:01 -08:00
Joe Savona df8945b684 Visit terminal operands during alignment 2023-01-12 09:11:58 -08:00
Joe Savona 9e549e9417 Fork HIRTreeVisitor to specialize it for ReactiveFunction conversion 2023-01-12 09:11:54 -08:00
Joe Savona 46024acb82 MergeOverlappingReactiveScopes (rewritten against ReactiveFunction)
See the background in #982. This PR reimplements part of InferReactiveScopes, 
merging overlapping reactive scopes, but against ReactiveFunction instead of the 
HIR.
2023-01-11 14:04:51 -08:00
Joe Savona 2358d9f01f AlignReactiveScopesToBlockScopes (rewritten against ReactiveFunction)
See the background in #982. This PR reimplements part of InferReactiveScopes, 
aligning reactive scopes to block boundaries, but against ReactiveFunction 
instead of the HIR.
2023-01-11 14:04:48 -08:00
Joe Savona 87d70b9129 BuildReactiveBlocks to construct scopes in ReactiveFunction
The primary goal of this stack is to change HIRTreeVisitor to make it easier to 
handle value blocks. That's complicated by the fact that the visitor is a 
general-purpose visitor, used in several analysis passes including 
BuildReactiveFunction (which translates HIR->ReactiveFunction while also 
grouping instructions into scopes) and InferReactiveScopes (which is actually 
two passes, one to align scopes to block boundaries, one to merge overlapping 
scopes). The long-term goal then is as follows: 

1. Make BuildReactiveFunction transform HIR->ReactiveFunction but _without_ 
reactive scopes. 

2. Align scopes to block boundaries, but rewritten to operate on 
ReactiveFunction 

3. Merge overlapping scopes, again rewritten to operate on ReactiveFunction 

4. Group statements within ReactiveFunction into ReactiveScopeBlocks (today this 
occurs when constructing the ReactiveFunction). 

This PR implements 1 and 4. Because the implementation is incomplete this would 
break the whole compiler, so for now both versions are still around. By default 
compilation uses the old pipeline, but if a feature flag is enabled we use the 
new version. The plan is to incrementally fix up the new version of the passes 
in this stack, and then cutover: removing the flag and the old version of the 
passes.
2023-01-11 14:04:45 -08:00
Joe Savona a4fc975340 Scaffolding for LogicalTerminal 2023-01-10 13:49:57 -08:00
Sathya Gunasekaran f9ecc96bf3 [hir] Update mutable range of operands during LeaveSSA
It's not enough to only update the mutable range of the canonical id created 
instead of the phi but we need to update the mutable range of each of the 
operands of the phi as well to account for the fact that the phi could've been 
mutated later. 

The operands are updated only if the phi is mutated later. Otherwise these 
operands can be cached in their blocks. 

Fixes https://github.com/facebook/react-forget/issues/978
2023-01-11 15:17:14 +00:00
Sathya Gunasekaran 986c95bc09 [hir] Add test case for incorrect memoisation of mutated objects
In this case, x should not be cached within the if or else blocks as it is 
mutated later.
2023-01-11 15:17:13 +00:00
Sathya Gunasekaran ed63dba739 [hir] Print MutableRange in lvalue
This is admittedly a little noisy but super valuable when debugging.
2023-01-11 15:08:37 +00:00
Sathya Gunasekaran bbba752e98 [typer] Add type inference for Phis 2023-01-11 11:30:58 +00:00
Sathya Gunasekaran 1910ede500 [typer] Add PhiType to represent Phis 2023-01-11 11:30:58 +00:00
Sathya Gunasekaran 0c3cfbdd36 [typer] Add type to Phi 2023-01-11 11:30:57 +00:00
Joe Savona 27b37341e5 Playground uses run() to automatically sync w compiler passes
Changes playground to use the modified `run()` function of the compiler, polling 
the generator and building up a Map of tabs automatically based on the passes 
that the compiler runs. This means tabs are always derived from the current 
state of the compiler and we can never forget to add a pass. 

<img width="1497" alt="Screen Shot 2023-01-10 at 11 06 03 AM" 
src="https://user-images.githubusercontent.com/6425824/211639442-da421f73-e19e-4b63-9f33-0ce5a68cceb7.png"> 

Note the inclusion of some recently added passes that weren't added to the 
playground — which was my fault but only bc i intended to ship this PR soon :-)
2023-01-10 11:05:32 -08:00
Joe Savona 7751202433 Make CompilerPipeline a generator
Turns CompilerPipeline into two functions: 

* `run()` is a generator and yields values that are a disjoint union of either 
AST/HIR/ReactiveFunction along with a name for that step. The idea is to use 
this in the playground so that it always matches the exact steps for 
compilation. I'll update playground in a follow-up. 

* `compile()` is ast in, ast out, and uses `run()` under the hood.
2023-01-10 10:15:45 -08:00
Joe Savona f3168d020f Distinguish regular/value blocks 2023-01-10 09:37:33 -08:00
Joe Savona dce5371763 Constant propagation/folding
Implements constant propagation/constant folding for a conservative subset of 
the language. The approach is described in detail in the comments in the file 
itself, a key note here is that this pass currently emits what looks like 
garbage: 

``` 

// input 

const x = 1; 

const y = x + 1; 

// output 

const x = 1; 

2; // <---- you'll see a bunch of lines like this 

const y = 2; 

``` 

These useless lines occur where previously there was a temporary getting 
calculated that was used later (so we saved it until it was used), but now it 
isn't used later so we just emit it in-place. Dead code elimination (DCE) can 
eliminate these and other useless statements later. 

Note that a key motivation for implementing this pass is to reduce memoization 
blocks to what is strictly required for dynamic computations. Why memoize at 
runtime when we compute at build time?
2023-01-09 15:30:20 -08:00
Sathya Gunasekaran 6f9c9cf9ea [hir] Make lambdas dependencies be a list of Places
This lets HIR understand and rename dependencies correctly.
2023-01-10 16:06:55 +00:00
Sathya Gunasekaran 346ecb27fe [hir] Gather dependencies for lambdas 2023-01-09 18:22:35 +00:00
Sathya Gunasekaran ce7cab4eee [hir] Parse and codegen FunctionExpression 2023-01-09 18:22:32 +00:00
Joe Savona 57ea3b7e8a Merge consecutive blocks
See the previous PR for context, this PR adds a new pass to merge consecutive 
blocks.
2023-01-09 13:04:33 -08:00
Joe Savona 7a7538920e Broken test for labeled statements
When we convert a LabeledStatement to HIR we can end up emitting "consecutive" 
blocks, ie where there are two blocks such that control flow will always go from 
from one block to the other, with no other way to reach the second block but 
through the first. Example: 

```javascript 

label: { 

foo(); 

break label; 

} 

bar(); 

``` 

Converts to 

``` 

bb0: 

foo() 

goto bb1: 

bb1: 

bar(); 

... 

``` 

Ideally in this case we would merge these into a single block: 

* When debugging, the extra goto makes it look like there is conditional control 
flow when there isn't. If the code is consecutive it's easier to understand that 
if it's a single block. 

* Conversion from HIR -> AST relies on consecutive code all being in a single 
block, so this breaks codegen (we never visit the goto target since all gotos 
are assumed to be safe to convert to a break or continue). 

This PR adds a failing test case, the next PR fixes it.
2023-01-09 13:04:30 -08:00
Joe Savona d8d5fe989c [be] Improvements to shrink/markInstructionIds 2023-01-09 10:06:03 -08:00
Joe Savona 0abc420c78 [be] Preds/phis use BlockId since blocks may change
Phi operands and Block predecessors currently use a `BasicBlock` reference 
rather than the BlockId. This diverges from other places (like terminals) where 
we use an id and not a direct object reference. Especially since blocks may get 
rewritten or pruned, it's a bit cleaner to use the block id in these places.
2023-01-09 09:22:43 -08:00
Joe Savona 3765219933 [be] Mutate HIR in-place (shrink/rpo)
Changes `shrink()` and `reversePostorderBlocks()` to modify the HIR in-place 
rather than return a new function, for consistency with all our other passes 
which mutate in-place (for performance reasons).
2023-01-09 09:13:31 -08:00
Sathya Gunasekaran 159a3f64d0 [typer] Remove unnecessary unifier parameter 2023-01-05 13:46:55 +00:00
Sathya Gunasekaran db3839e716 [typer] Cleanup lvalue null checking 2023-01-05 13:46:51 +00:00
Sathya Gunasekaran cccec0e5b2 [be] Don't use nested imports 2023-01-04 21:11:40 +00:00
Sathya Gunasekaran b8fd4680b1 [hir] Move inference passes to separate folder 2023-01-04 21:11:37 +00:00
Sathya Gunasekaran d187fff414 [typer] Move type inference to a separate folder 2023-01-04 21:11:33 +00:00
Sathya Gunasekaran efac190973 [typer] Make type inference more conservative
It's not entirely correct to infer arguments to (not) equals operator as 
primitives.
2023-01-04 18:09:25 +00:00
Sathya Gunasekaran 09bdf3553f [hir] Remove unreachable fallthroughs separately from shrink
shrink visits all the fallthroughs even if they are unreachable so this isn't 
the right place to prune unreachable blocks. 

This PR moves pruning into a separate pass.
2023-01-04 18:09:24 +00:00
Joe Savona e4642326d3 Make LValue non-nullable in HIR 2023-01-04 09:51:17 -08:00
Joe Savona 29bb3f55a3 Rename IndexLoad/Store to ComputedLoad/Store
Hopefully a more clear name, these values correspond to computed properties.
2023-01-03 17:03:45 -08:00
Joe Savona bd99d06a5f Support computed property access/assignment
Supports computed properties (as LHS and RHS) correctly. Previously we only 
handled member expressions where the property was an identifier, and would 
incorrect treat `a[b]` the same as `a.b`. Now we correctly distinguish these and 
convert `a[b]` as an IndexLoad and `a.b` as a PropertyLoad. Similar for 
assignment, `a[b] = c` is an IndexStore. For both IndexLoad and IndexStore we 
lower the property to a Place first.
2023-01-03 16:59:41 -08:00