1/*
2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.codegen;
27
28import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
29
30import java.io.PrintWriter;
31import java.util.HashMap;
32import java.util.LinkedHashMap;
33import java.util.Map;
34import java.util.Map.Entry;
35import java.util.Set;
36import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
37import jdk.nashorn.internal.ir.Block;
38import jdk.nashorn.internal.ir.FunctionNode;
39import jdk.nashorn.internal.ir.LiteralNode;
40import jdk.nashorn.internal.ir.Node;
41import jdk.nashorn.internal.ir.Symbol;
42import jdk.nashorn.internal.ir.debug.ASTWriter;
43import jdk.nashorn.internal.ir.debug.PrintVisitor;
44import jdk.nashorn.internal.ir.visitor.NodeVisitor;
45import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
46import jdk.nashorn.internal.runtime.CodeInstaller;
47import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
48import jdk.nashorn.internal.runtime.ScriptEnvironment;
49import jdk.nashorn.internal.runtime.logging.DebugLogger;
50
51/**
52 * A compilation phase is a step in the processes of turning a JavaScript
53 * FunctionNode into bytecode. It has an optional return value.
54 */
55abstract class CompilationPhase {
56
57    private static final class ConstantFoldingPhase extends CompilationPhase {
58        @Override
59        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
60            return transformFunction(fn, new FoldConstants(compiler));
61        }
62
63        @Override
64        public String toString() {
65            return "'Constant Folding'";
66        }
67    }
68
69    /**
70     * Constant folding pass Simple constant folding that will make elementary
71     * constructs go away
72     */
73    static final CompilationPhase CONSTANT_FOLDING_PHASE = new ConstantFoldingPhase();
74
75    private static final class LoweringPhase extends CompilationPhase {
76        @Override
77        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
78            return transformFunction(fn, new Lower(compiler));
79        }
80
81        @Override
82        public String toString() {
83            return "'Control Flow Lowering'";
84        }
85    }
86
87    /**
88     * Lower (Control flow pass) Finalizes the control flow. Clones blocks for
89     * finally constructs and similar things. Establishes termination criteria
90     * for nodes Guarantee return instructions to method making sure control
91     * flow cannot fall off the end. Replacing high level nodes with lower such
92     * as runtime nodes where applicable.
93     */
94    static final CompilationPhase LOWERING_PHASE = new LoweringPhase();
95
96    private static final class ApplySpecializationPhase extends CompilationPhase {
97        @Override
98        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
99            return transformFunction(fn, new ApplySpecialization(compiler));
100        }
101
102        @Override
103        public String toString() {
104            return "'Builtin Replacement'";
105        }
106    };
107
108    /**
109     * Phase used to transform Function.prototype.apply.
110     */
111    static final CompilationPhase APPLY_SPECIALIZATION_PHASE = new ApplySpecializationPhase();
112
113    private static final class SplittingPhase extends CompilationPhase {
114        @Override
115        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
116            final CompileUnit  outermostCompileUnit = compiler.addCompileUnit(0L);
117
118            FunctionNode newFunctionNode;
119
120            //ensure elementTypes, postsets and presets exist for splitter and arraynodes
121            newFunctionNode = transformFunction(fn, new SimpleNodeVisitor() {
122                @Override
123                public LiteralNode<?> leaveLiteralNode(final LiteralNode<?> literalNode) {
124                    return literalNode.initialize(lc);
125                }
126            });
127
128            newFunctionNode = new Splitter(compiler, newFunctionNode, outermostCompileUnit).split(newFunctionNode, true);
129            newFunctionNode = transformFunction(newFunctionNode, new SplitIntoFunctions(compiler));
130            assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn=" + fn.getName() + ", fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
131            assert newFunctionNode.isStrict() == compiler.isStrict() : "functionNode.isStrict() != compiler.isStrict() for " + quote(newFunctionNode.getName());
132
133            return newFunctionNode;
134        }
135
136        @Override
137        public String toString() {
138            return "'Code Splitting'";
139        }
140    };
141
142    /**
143     * Splitter Split the AST into several compile units based on a heuristic size calculation.
144     * Split IR can lead to scope information being changed.
145     */
146    static final CompilationPhase SPLITTING_PHASE = new SplittingPhase();
147
148    private static final class ProgramPointPhase extends CompilationPhase {
149        @Override
150        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
151            return transformFunction(fn, new ProgramPoints());
152        }
153
154        @Override
155        public String toString() {
156            return "'Program Point Calculation'";
157        }
158    };
159
160    /**
161     * Phase used only when doing optimistic code generation. It assigns all potentially
162     * optimistic ops a program point so that an UnwarrantedException knows from where
163     * a guess went wrong when creating the continuation to roll back this execution
164     */
165    static final CompilationPhase PROGRAM_POINT_PHASE = new ProgramPointPhase();
166
167    private static final class CacheAstPhase extends CompilationPhase {
168        @Override
169        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
170            if (!compiler.isOnDemandCompilation()) {
171                // Only do this on initial preprocessing of the source code. For on-demand compilations from
172                // source, FindScopeDepths#leaveFunctionNode() calls data.setCachedAst() for the sole function
173                // being compiled.
174                transformFunction(fn, new CacheAst(compiler));
175            }
176            // NOTE: we're returning the original fn as we have destructively modified the cached functions by
177            // removing their bodies. This step is associating FunctionNode objects with
178            // RecompilableScriptFunctionData; it's not really modifying the AST.
179            return fn;
180        }
181
182        @Override
183        public String toString() {
184            return "'Cache ASTs'";
185        }
186    };
187
188    static final CompilationPhase CACHE_AST_PHASE = new CacheAstPhase();
189
190    private static final class SymbolAssignmentPhase extends CompilationPhase {
191        @Override
192        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
193            return transformFunction(fn, new AssignSymbols(compiler));
194        }
195
196        @Override
197        public String toString() {
198            return "'Symbol Assignment'";
199        }
200    };
201
202    static final CompilationPhase SYMBOL_ASSIGNMENT_PHASE = new SymbolAssignmentPhase();
203
204    private static final class ScopeDepthComputationPhase extends CompilationPhase {
205        @Override
206        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
207            return transformFunction(fn, new FindScopeDepths(compiler));
208        }
209
210        @Override
211        public String toString() {
212            return "'Scope Depth Computation'";
213        }
214    }
215
216    static final CompilationPhase SCOPE_DEPTH_COMPUTATION_PHASE = new ScopeDepthComputationPhase();
217
218    private static final class DeclareLocalSymbolsPhase extends CompilationPhase {
219        @Override
220        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
221            // It's not necessary to guard the marking of symbols as locals with this "if" condition for
222            // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
223            // is not an on-demand optimistic compilation, so we can skip locals marking then.
224            if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
225                fn.getBody().accept(new SimpleNodeVisitor() {
226                    @Override
227                    public boolean enterFunctionNode(final FunctionNode functionNode) {
228                        // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
229                        // compilation, and we're skipping parsing the function bodies for nested functions, this
230                        // basically only means their parameters. It'd be enough to mistakenly declare to be a local a
231                        // symbol in the outer function named the same as one of the parameters, though.
232                        return false;
233                    };
234                    @Override
235                    public boolean enterBlock(final Block block) {
236                        for (final Symbol symbol: block.getSymbols()) {
237                            if (!symbol.isScope()) {
238                                compiler.declareLocalSymbol(symbol.getName());
239                            }
240                        }
241                        return true;
242                    };
243                });
244            }
245            return fn;
246        }
247
248        @Override
249        public String toString() {
250            return "'Local Symbols Declaration'";
251        }
252    };
253
254    static final CompilationPhase DECLARE_LOCAL_SYMBOLS_PHASE = new DeclareLocalSymbolsPhase();
255
256    private static final class OptimisticTypeAssignmentPhase extends CompilationPhase {
257        @Override
258        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
259            if (compiler.useOptimisticTypes()) {
260                return transformFunction(fn, new OptimisticTypesCalculator(compiler));
261            }
262            return fn;
263        }
264
265        @Override
266        public String toString() {
267            return "'Optimistic Type Assignment'";
268        }
269    }
270
271    static final CompilationPhase OPTIMISTIC_TYPE_ASSIGNMENT_PHASE = new OptimisticTypeAssignmentPhase();
272
273    private static final class LocalVariableTypeCalculationPhase extends CompilationPhase {
274        @Override
275        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
276            final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler));
277            final ScriptEnvironment senv = compiler.getScriptEnvironment();
278            final PrintWriter       err  = senv.getErr();
279
280            //TODO separate phase for the debug printouts for abstraction and clarity
281            if (senv._print_lower_ast || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_AST)) {
282                err.println("Lower AST for: " + quote(newFunctionNode.getName()));
283                err.println(new ASTWriter(newFunctionNode));
284            }
285
286            if (senv._print_lower_parse || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_PARSE)) {
287                err.println("Lower AST for: " + quote(newFunctionNode.getName()));
288                err.println(new PrintVisitor(newFunctionNode));
289            }
290
291            return newFunctionNode;
292        }
293
294        @Override
295        public String toString() {
296            return "'Local Variable Type Calculation'";
297        }
298    };
299
300    static final CompilationPhase LOCAL_VARIABLE_TYPE_CALCULATION_PHASE = new LocalVariableTypeCalculationPhase();
301
302    private static final class ReuseCompileUnitsPhase extends CompilationPhase {
303        @Override
304        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
305            assert phases.isRestOfCompilation() : "reuse compile units currently only used for Rest-Of methods";
306
307            final Map<CompileUnit, CompileUnit> map = new HashMap<>();
308            final Set<CompileUnit> newUnits = CompileUnit.createCompileUnitSet();
309
310            final DebugLogger log = compiler.getLogger();
311
312            log.fine("Clearing bytecode cache");
313            compiler.clearBytecode();
314
315            for (final CompileUnit oldUnit : compiler.getCompileUnits()) {
316                assert map.get(oldUnit) == null;
317                final CompileUnit newUnit = createNewCompileUnit(compiler, phases);
318                log.fine("Creating new compile unit ", oldUnit, " => ", newUnit);
319                map.put(oldUnit, newUnit);
320                assert newUnit != null;
321                newUnits.add(newUnit);
322            }
323
324            log.fine("Replacing compile units in Compiler...");
325            compiler.replaceCompileUnits(newUnits);
326            log.fine("Done");
327
328            //replace old compile units in function nodes, if any are assigned,
329            //for example by running the splitter on this function node in a previous
330            //partial code generation
331            final FunctionNode newFunctionNode = transformFunction(fn, new ReplaceCompileUnits() {
332                @Override
333                CompileUnit getReplacement(final CompileUnit original) {
334                    return map.get(original);
335                }
336
337                @Override
338                public Node leaveDefault(final Node node) {
339                    return node.ensureUniqueLabels(lc);
340                }
341            });
342
343            return newFunctionNode;
344        }
345
346        @Override
347        public String toString() {
348            return "'Reuse Compile Units'";
349        }
350    }
351
352    /**
353     * Reuse compile units, if they are already present. We are using the same compiler
354     * to recompile stuff
355     */
356    static final CompilationPhase REUSE_COMPILE_UNITS_PHASE = new ReuseCompileUnitsPhase();
357
358    private static final class ReinitializeCachedPhase extends CompilationPhase {
359        @Override
360        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
361            final Set<CompileUnit> unitSet = CompileUnit.createCompileUnitSet();
362            final Map<CompileUnit, CompileUnit> unitMap = new HashMap<>();
363
364            // Ensure that the FunctionNode's compile unit is the first in the list of new units. Install phase
365            // will use that as the root class.
366            createCompileUnit(fn.getCompileUnit(), unitSet, unitMap, compiler, phases);
367
368            final FunctionNode newFn = transformFunction(fn, new ReplaceCompileUnits() {
369                @Override
370                CompileUnit getReplacement(final CompileUnit oldUnit) {
371                    final CompileUnit existing = unitMap.get(oldUnit);
372                    if (existing != null) {
373                        return existing;
374                    }
375                    return createCompileUnit(oldUnit, unitSet, unitMap, compiler, phases);
376                }
377
378                @Override
379                public Node leaveFunctionNode(final FunctionNode fn2) {
380                    return super.leaveFunctionNode(
381                            // restore flags for deserialized nested function nodes
382                            compiler.getScriptFunctionData(fn2.getId()).restoreFlags(lc, fn2));
383                };
384            });
385            compiler.replaceCompileUnits(unitSet);
386            return newFn;
387        }
388
389        private CompileUnit createCompileUnit(final CompileUnit oldUnit, final Set<CompileUnit> unitSet,
390                final Map<CompileUnit, CompileUnit> unitMap, final Compiler compiler, final CompilationPhases phases) {
391            final CompileUnit newUnit = createNewCompileUnit(compiler, phases);
392            unitMap.put(oldUnit, newUnit);
393            unitSet.add(newUnit);
394            return newUnit;
395        }
396
397        @Override
398        public String toString() {
399            return "'Reinitialize cached'";
400        }
401    }
402
403    static final CompilationPhase REINITIALIZE_CACHED = new ReinitializeCachedPhase();
404
405    private static final class BytecodeGenerationPhase extends CompilationPhase {
406        @Override
407        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
408            final ScriptEnvironment senv = compiler.getScriptEnvironment();
409
410            FunctionNode newFunctionNode = fn;
411
412            //root class is special, as it is bootstrapped from createProgramFunction, thus it's skipped
413            //in CodeGeneration - the rest can be used as a working "is compile unit used" metric
414            fn.getCompileUnit().setUsed();
415
416            compiler.getLogger().fine("Starting bytecode generation for ", quote(fn.getName()), " - restOf=", phases.isRestOfCompilation());
417
418            final CodeGenerator codegen = new CodeGenerator(compiler, phases.isRestOfCompilation() ? compiler.getContinuationEntryPoints() : null);
419
420            try {
421                // Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program
422                // in the lazy + optimistic world. See CodeGenerator.skipFunction().
423                newFunctionNode = transformFunction(newFunctionNode, codegen);
424                codegen.generateScopeCalls();
425            } catch (final VerifyError e) {
426                if (senv._verify_code || senv._print_code) {
427                    senv.getErr().println(e.getClass().getSimpleName() + ": "  + e.getMessage());
428                    if (senv._dump_on_error) {
429                        e.printStackTrace(senv.getErr());
430                    }
431                } else {
432                    throw e;
433                }
434            } catch (final Throwable e) {
435                // Provide source file and line number being compiled when the assertion occurred
436                throw new AssertionError("Failed generating bytecode for " + fn.getSourceName() + ":" + codegen.getLastLineNumber(), e);
437            }
438
439            for (final CompileUnit compileUnit : compiler.getCompileUnits()) {
440                final ClassEmitter classEmitter = compileUnit.getClassEmitter();
441                classEmitter.end();
442
443                if (!compileUnit.isUsed()) {
444                    compiler.getLogger().fine("Skipping unused compile unit ", compileUnit);
445                    continue;
446                }
447
448                final byte[] bytecode = classEmitter.toByteArray();
449                assert bytecode != null;
450
451                final String className = compileUnit.getUnitClassName();
452                compiler.addClass(className, bytecode); //classes are only added to the bytecode map if compile unit is used
453
454                CompileUnit.increaseEmitCount();
455
456                // should we verify the generated code?
457                if (senv._verify_code) {
458                    compiler.getCodeInstaller().verify(bytecode);
459                }
460
461                DumpBytecode.dumpBytecode(senv, compiler.getLogger(), bytecode, className);
462            }
463
464            return newFunctionNode;
465        }
466
467        @Override
468        public String toString() {
469            return "'Bytecode Generation'";
470        }
471    }
472
473    /**
474     * Bytecode generation:
475     *
476     * Generate the byte code class(es) resulting from the compiled FunctionNode
477     */
478    static final CompilationPhase BYTECODE_GENERATION_PHASE = new BytecodeGenerationPhase();
479
480    private static final class InstallPhase extends CompilationPhase {
481        @Override
482        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
483            final DebugLogger log = compiler.getLogger();
484
485            final Map<String, Class<?>> installedClasses = new LinkedHashMap<>();
486
487            boolean first = true;
488            Class<?> rootClass = null;
489            long length = 0L;
490
491            final CodeInstaller origCodeInstaller = compiler.getCodeInstaller();
492            final Map<String, byte[]> bytecode = compiler.getBytecode();
493            final CodeInstaller codeInstaller = bytecode.size() > 1 ? origCodeInstaller.getMultiClassCodeInstaller() : origCodeInstaller;
494
495            for (final Entry<String, byte[]> entry : bytecode.entrySet()) {
496                final String className = entry.getKey();
497                //assert !first || className.equals(compiler.getFirstCompileUnit().getUnitClassName()) : "first=" + first + " className=" + className + " != " + compiler.getFirstCompileUnit().getUnitClassName();
498                final byte[] code = entry.getValue();
499                length += code.length;
500
501                final Class<?> clazz = codeInstaller.install(className, code);
502                if (first) {
503                    rootClass = clazz;
504                    first = false;
505                }
506                installedClasses.put(className, clazz);
507            }
508
509            if (rootClass == null) {
510                throw new CompilationException("Internal compiler error: root class not found!");
511            }
512
513            final Object[] constants = compiler.getConstantData().toArray();
514            codeInstaller.initialize(installedClasses.values(), compiler.getSource(), constants);
515
516            // initialize transient fields on recompilable script function data
517            for (final Object constant: constants) {
518                if (constant instanceof RecompilableScriptFunctionData) {
519                    ((RecompilableScriptFunctionData)constant).initTransients(compiler.getSource(), codeInstaller);
520                }
521            }
522
523            // initialize function in the compile units
524            for (final CompileUnit unit : compiler.getCompileUnits()) {
525                if (!unit.isUsed()) {
526                    continue;
527                }
528                unit.setCode(installedClasses.get(unit.getUnitClassName()));
529                unit.initializeFunctionsCode();
530            }
531
532            if (log.isEnabled()) {
533                final StringBuilder sb = new StringBuilder();
534
535                sb.append("Installed class '").
536                    append(rootClass.getSimpleName()).
537                    append('\'').
538                    append(" [").
539                    append(rootClass.getName()).
540                    append(", size=").
541                    append(length).
542                    append(" bytes, ").
543                    append(compiler.getCompileUnits().size()).
544                    append(" compile unit(s)]");
545
546                log.fine(sb.toString());
547            }
548
549            return fn.setRootClass(null, rootClass);
550        }
551
552        @Override
553        public String toString() {
554            return "'Class Installation'";
555        }
556    }
557
558    static final CompilationPhase INSTALL_PHASE = new InstallPhase();
559
560    /** start time of transform - used for timing, see {@link jdk.nashorn.internal.runtime.Timing} */
561    private long startTime;
562
563    /** start time of transform - used for timing, see {@link jdk.nashorn.internal.runtime.Timing} */
564    private long endTime;
565
566    /** boolean that is true upon transform completion */
567    private boolean isFinished;
568
569    private CompilationPhase() {}
570
571    /**
572     * Start a compilation phase
573     * @param compiler the compiler to use
574     * @param functionNode function to compile
575     * @return function node
576     */
577    protected FunctionNode begin(final Compiler compiler, final FunctionNode functionNode) {
578        compiler.getLogger().indent();
579        startTime = System.nanoTime();
580
581         return functionNode;
582     }
583
584    /**
585     * End a compilation phase
586     * @param compiler the compiler
587     * @param functionNode function node to compile
588     * @return function node
589     */
590    protected FunctionNode end(final Compiler compiler, final FunctionNode functionNode) {
591        compiler.getLogger().unindent();
592        endTime = System.nanoTime();
593        compiler.getScriptEnvironment()._timing.accumulateTime(toString(), endTime - startTime);
594
595        isFinished = true;
596        return functionNode;
597    }
598
599    boolean isFinished() {
600        return isFinished;
601    }
602
603    long getStartTime() {
604        return startTime;
605    }
606
607    long getEndTime() {
608        return endTime;
609    }
610
611    abstract FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode functionNode) throws CompilationException;
612
613    /**
614     * Apply a transform to a function node, returning the transformed function node. If the transform is not
615     * applicable, an exception is thrown. Every transform requires the function to have a certain number of
616     * states to operate. It can have more states set, but not fewer. The state list, i.e. the constructor
617     * arguments to any of the CompilationPhase enum entries, is a set of REQUIRED states.
618     *
619     * @param compiler     compiler
620     * @param phases       current complete pipeline of which this phase is one
621     * @param functionNode function node to transform
622     *
623     * @return transformed function node
624     *
625     * @throws CompilationException if function node lacks the state required to run the transform on it
626     */
627    final FunctionNode apply(final Compiler compiler, final CompilationPhases phases, final FunctionNode functionNode) throws CompilationException {
628        assert phases.contains(this);
629
630        return end(compiler, transform(compiler, phases, begin(compiler, functionNode)));
631    }
632
633    private static FunctionNode transformFunction(final FunctionNode fn, final NodeVisitor<?> visitor) {
634        return (FunctionNode) fn.accept(visitor);
635    }
636
637    private static CompileUnit createNewCompileUnit(final Compiler compiler, final CompilationPhases phases) {
638        final StringBuilder sb = new StringBuilder(compiler.nextCompileUnitName());
639        if (phases.isRestOfCompilation()) {
640            sb.append("$restOf");
641        }
642        //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what
643        //fills those out anyway. Thus no need for a copy constructor
644        return compiler.createCompileUnit(sb.toString(), 0);
645    }
646}
647