-
insert_toplevel_func
Wraps the entire script in a toplevel function. this simplifies much of the closure conversion code because nothing is outside of a function. This function is what gets invoked at runtime when a file is required().
-
HoiseFuncDecls
Hoists nested function declarations to the top of the containing function.
-
FuncDeclsToVars
Converts function declarations to variable assignment. i.e. from this:
function foo () { }to this:
var foo = function foo () { };-
HoistVars
Hoists vars to the top of the containing functions, leaving initializers where they were. That is, from:
{
....
var x = 5;
....
}to:
{
let x;
....
x = 5;
....
}note the switch from var to let above. After this phase there should be no var declarations.
-
ComputeFree
Compute free and declared variables for each node and stores them on the nodes.
-
LocateEnv
Computes where in the tree we need to add environments, and also computes which variables need to be moved into which environment. This stage computes closures in the top down manner as described on Matt Might's awesome site.
-
SubstituteVariables
Replaces variable references with environment property references. After this pass the only free variables are references to globals. This phase also replaces function expressions,
newexpressions, and call expressions with%makeClosure,%invokeClosure, and%invokeClosureintrinsics, respectively.so from:
var f = function f () { }
g = f()
h = new f();to
var f;
f = %makeClosure(%current_env, "f", function f () { })
g = %invokeClosure(f, undefined, 0, [])
h = new %invokeClosure(f, undefined, 0, [])This phase might be nicer if the new expression could be further decomposed into 2 intrinsics, %createObject and %invokeClosure. Then
the LLVM IR generator wouldn't need to support new expressions at all.
This phase also keeps track of the maximum number of call args required for any invocation in a given function, so we can allocate a scratch buffer once.
-
LambdaLift
After SubstituteVariables, it's safe to move all function expressions out to the toplevel, since they have no free variables except global references. After this phase there are no nested functions at all.
This phase also prepends
%createArgScratchAreaintrinsic calls to the beginning of any function that needs it.
-
AddFunctions
Adds the toplevel functions to the LLVM IR module so that when we walk the tree generating code, references are resolved to the proper functions.
-
LLVMIR
Walks the tree one last time emitting the actual IR.