com.google.javascript.jscomp
Class SpecializeModule
java.lang.Object
com.google.javascript.jscomp.SpecializeModule
- All Implemented Interfaces:
- CompilerPass
public class SpecializeModule
- extends Object
- implements CompilerPass
Beginnings of an optimization to specialize the initial module at the cost of
increasing code in later modules. This is still very experimental.
High-level overview:
This optimization replaces functions in the initial module with specialized
versions that are only safe in the initial module. The original, general,
versions of the functions are "fixed up" in later modules. This optimization
can shrink the initial module significantly but the fixup code in later
modules increases overall code size.
Implementation approach:
We take a ridiculously naive approach: remove the initial module
from the rest of the AST, optimize it with existing optimization passes
(recording which functions have been specialized), put it back in the AST,
and add fixups restoring the general versions of the functions in each module
that depends on the initial module.
Since it is only safe to specialize functions that can be fixed up, we
don't allow specialization of local functions and functions that
are aliased.
We currently run three optimizations on the isolated AST: InlineFunctions,
DevirtualizePrototypeMethods, and RemoveUnusedPrototypeProperties.
These optimizations rely on a coarse-grained name-based analysis to
maintain safety properties and thus are likely to see some benefit when
applied in isolation.
InlineFunctions is truly specializing -- it replaces functions with
versions that have calls to other functions inlined into them, while
RemoveUnusedPrototypeProperties is really just removing properties that
aren't used in the initial module and adding copies further down in the
module graph. It would probably be more elegant to give
CrossModuleMethodMotion permission to make copies of methods instead.
There are additional passes that might benefit from being made
specialization-aware:
- OptimizeParameters
- Any pass that is too slow to run over the entire AST but might
be acceptable on only the initial module:
- RemoveUnusedNames
- Also, any pass that uses the results of PureFunctionIdentifier to
determine when it is safe to remove code might benefit (e.g. the peephole
passes), since PureFunctionIdentifier relies on SimpleDefinitionFinder,
which would be more precise when running on only the initial module.
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
SpecializeModule
public SpecializeModule(AbstractCompiler compiler,
PassFactory... specializationPassFactories)
process
public void process(Node externs,
Node root)
- Performs initial module specialization.
The process is as follows:
1) Make a copy of each of the inputs in the initial root and put them
in a fake AST that looks like it is the whole program.
2) Run the specializing compiler passes over the fake initial module AST
until it reaches a fixed point, recording which functions are specialized
or removed.
3) Replace the original input roots with the specialized input roots
4) For each module that directly depends on the initial module, add
fixups for the specialized and removed functions. Right now we add
fixups for for every function that was specialzed or removed -- we could
be smarter about this and for each dependent module only add the functions
that it needs.
5) Add dummy variables declaring the removed function to the end of
the now-specialized initial module. This is needed to keep
VarCheck
from complaining.
- Specified by:
process
in interface CompilerPass
- Parameters:
externs
- Top of external JS treeroot
- Top of JS tree
getDirectDependents
public Collection<JSModule> getDirectDependents(JSModule module)
- Returns a list of modules that directly depend on the given module.
This probably deserves to be in JSModuleGraph.