# HG changeset patch # User lagergren # Date 1409927297 -7200 # Node ID 3f49db18721f0c2e7408ebedfff5bf8dbba00490 # Parent afdad86ffddec21bf8d58089988d3f6a71cdb2ee 8057588: Lots of trivial (empty) classes were generated by the Nashorn compiler as part of restOf-method generation Reviewed-by: attila, sundar, hannesw diff -r afdad86ffdde -r 3f49db18721f src/jdk/nashorn/internal/codegen/CompilationPhase.java --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java Fri Sep 05 16:28:02 2014 +0200 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java Fri Sep 05 16:28:17 2014 +0200 @@ -48,10 +48,12 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; + import jdk.nashorn.internal.AssertsEnabled; import jdk.nashorn.internal.codegen.Compiler.CompilationPhases; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; +import jdk.nashorn.internal.ir.CompileUnitHolder; import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; @@ -301,6 +303,71 @@ }, /** + * Mark compile units used in the method tree. Used for non-rest compilation only + */ + MARK_USED_COMPILE_UNITS( + EnumSet.of( + INITIALIZED, + PARSED, + CONSTANT_FOLDED, + LOWERED, + BUILTINS_TRANSFORMED, + SPLIT, + SYMBOLS_ASSIGNED, + SCOPE_DEPTHS_COMPUTED, + OPTIMISTIC_TYPES_ASSIGNED, + LOCAL_VARIABLE_TYPES_CALCULATED)) { + + @Override + FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { + final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new NodeVisitor(new LexicalContext()) { + private void tagUsed(final CompileUnitHolder node) { + assert node.getCompileUnit() != null : "no compile unit in " + node; + node.getCompileUnit().setUsed(); + } + + @Override + public Node leaveFunctionNode(final FunctionNode node) { + tagUsed(node); + return node; + } + + @Override + public Node leaveSplitNode(final SplitNode node) { + tagUsed(node); + return node; + } + + @Override + public Node leaveLiteralNode(final LiteralNode node) { + if (node instanceof ArrayLiteralNode) { + final ArrayLiteralNode aln = (ArrayLiteralNode)node; + if (aln.getUnits() != null) { + for (final ArrayUnit au : aln.getUnits()) { + tagUsed(au); + } + } + return aln; + } + return node; + } + + @Override + public Node leaveDefault(final Node node) { + return node.ensureUniqueLabels(lc); + } + }); + + return newFunctionNode; + } + + @Override + public String toString() { + return "'Tag Compile Units Used'"; + } + }, + + /** * Reuse compile units, if they are already present. We are using the same compiler * to recompile stuff */ @@ -358,6 +425,7 @@ assert newUnit != null : "old unit has no mapping to new unit " + oldUnit; log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName())); + newUnit.setUsed(); return node.setCompileUnit(lc, newUnit).setState(lc, CompilationState.COMPILE_UNITS_REUSED); } @@ -370,6 +438,7 @@ assert newUnit != null : "old unit has no mapping to new unit " + oldUnit; log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName())); + newUnit.setUsed(); return node.setCompileUnit(lc, newUnit); } @@ -384,6 +453,7 @@ for (final ArrayUnit au : aln.getUnits()) { final CompileUnit newUnit = map.get(au.getCompileUnit()); assert newUnit != null; + newUnit.setUsed(); newArrayUnits.add(new ArrayUnit(newUnit, au.getLo(), au.getHi())); } return aln.setUnits(lc, newArrayUnits); @@ -452,6 +522,11 @@ } for (final CompileUnit compileUnit : compiler.getCompileUnits()) { + if (!compileUnit.isUsed()) { + compiler.getLogger().fine("Skipping unused compile unit ", compileUnit); + continue; + } + final ClassEmitter classEmitter = compileUnit.getClassEmitter(); classEmitter.end(); @@ -459,7 +534,6 @@ assert bytecode != null; final String className = compileUnit.getUnitClassName(); - compiler.addClass(className, bytecode); // should we verify the generated code? @@ -536,6 +610,9 @@ // initialize function in the compile units for (final CompileUnit unit : compiler.getCompileUnits()) { + if (!unit.isUsed()) { + continue; + } unit.setCode(installedClasses.get(unit.getUnitClassName())); } diff -r afdad86ffdde -r 3f49db18721f src/jdk/nashorn/internal/codegen/CompileUnit.java --- a/src/jdk/nashorn/internal/codegen/CompileUnit.java Fri Sep 05 16:28:02 2014 +0200 +++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java Fri Sep 05 16:28:17 2014 +0200 @@ -42,6 +42,8 @@ private Class clazz; + private boolean isUsed; + CompileUnit(final String className, final ClassEmitter classEmitter, final long initialWeight) { this.className = className; this.weight = initialWeight; @@ -53,6 +55,21 @@ } /** + * Check if this compile unit is used + * @return true if tagged as in use - i.e active code that needs to be generated + */ + public boolean isUsed() { + return isUsed; + } + + /** + * Tag this compile unit as used + */ + public void setUsed() { + this.isUsed = true; + } + + /** * Return the class that contains the code for this unit, null if not * generated yet * diff -r afdad86ffdde -r 3f49db18721f src/jdk/nashorn/internal/codegen/Compiler.java --- a/src/jdk/nashorn/internal/codegen/Compiler.java Fri Sep 05 16:28:02 2014 +0200 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Fri Sep 05 16:28:17 2014 +0200 @@ -173,13 +173,14 @@ CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE, CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE, CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, + CompilationPhase.MARK_USED_COMPILE_UNITS, CompilationPhase.BYTECODE_GENERATION_PHASE, CompilationPhase.INSTALL_PHASE }); /** Compile all for a rest of method */ public final static CompilationPhases COMPILE_ALL_RESTOF = - COMPILE_ALL.setDescription("Compile all, rest of").addAfter(CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, CompilationPhase.REUSE_COMPILE_UNITS_PHASE); + COMPILE_ALL.setDescription("Compile all, rest of").replace(CompilationPhase.MARK_USED_COMPILE_UNITS, CompilationPhase.REUSE_COMPILE_UNITS_PHASE); /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */ public final static CompilationPhases COMPILE_ALL_NO_INSTALL = @@ -250,6 +251,15 @@ return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); } + private CompilationPhases replace(final CompilationPhase phase, final CompilationPhase newPhase) { + final LinkedList list = new LinkedList<>(); + for (final CompilationPhase p : phases) { + list.add(p == phase ? newPhase : p); + } + return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); + } + + @SuppressWarnings("unused") //TODO I'll use this soon private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) { final LinkedList list = new LinkedList<>(); for (final CompilationPhase p : phases) { diff -r afdad86ffdde -r 3f49db18721f src/jdk/nashorn/internal/ir/CompileUnitHolder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/ir/CompileUnitHolder.java Fri Sep 05 16:28:17 2014 +0200 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.ir; + +import jdk.nashorn.internal.codegen.CompileUnit; + +/** + * Marker interface for things in the IR that can hold compile units. + * {@link CompileUnit} + */ +public interface CompileUnitHolder { + /** + * Return the compile unit held by this instance + * @return compile unit + */ + public CompileUnit getCompileUnit(); +} diff -r afdad86ffdde -r 3f49db18721f src/jdk/nashorn/internal/ir/FunctionNode.java --- a/src/jdk/nashorn/internal/ir/FunctionNode.java Fri Sep 05 16:28:02 2014 +0200 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java Fri Sep 05 16:28:17 2014 +0200 @@ -34,10 +34,8 @@ import java.util.Collections; import java.util.EnumSet; -import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Set; import java.util.function.Function; import jdk.nashorn.internal.AssertsEnabled; import jdk.nashorn.internal.codegen.CompileUnit; @@ -58,7 +56,7 @@ * IR representation for function (or script.) */ @Immutable -public final class FunctionNode extends LexicalContextExpression implements Flags { +public final class FunctionNode extends LexicalContextExpression implements Flags, CompileUnitHolder { /** Type used for all FunctionNodes */ public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class); @@ -1158,6 +1156,7 @@ * @see Compiler * @return the compile unit */ + @Override public CompileUnit getCompileUnit() { return compileUnit; } diff -r afdad86ffdde -r 3f49db18721f src/jdk/nashorn/internal/ir/LiteralNode.java --- a/src/jdk/nashorn/internal/ir/LiteralNode.java Fri Sep 05 16:28:02 2014 +0200 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java Fri Sep 05 16:28:17 2014 +0200 @@ -603,7 +603,7 @@ * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can * be split if they are too large, for bytecode generation reasons */ - public static final class ArrayUnit { + public static final class ArrayUnit implements CompileUnitHolder { /** Compile unit associated with the postsets range. */ private final CompileUnit compileUnit; @@ -642,6 +642,7 @@ * The array compile unit * @return array compile unit */ + @Override public CompileUnit getCompileUnit() { return compileUnit; } diff -r afdad86ffdde -r 3f49db18721f src/jdk/nashorn/internal/ir/SplitNode.java --- a/src/jdk/nashorn/internal/ir/SplitNode.java Fri Sep 05 16:28:02 2014 +0200 +++ b/src/jdk/nashorn/internal/ir/SplitNode.java Fri Sep 05 16:28:17 2014 +0200 @@ -39,7 +39,7 @@ * Node indicating code is split across classes. */ @Immutable -public class SplitNode extends LexicalContextStatement implements Labels { +public class SplitNode extends LexicalContextStatement implements Labels, CompileUnitHolder { /** Split node method name. */ private final String name; @@ -116,6 +116,7 @@ * Get the compile unit for this split node * @return compile unit */ + @Override public CompileUnit getCompileUnit() { return compileUnit; } diff -r afdad86ffdde -r 3f49db18721f src/jdk/nashorn/internal/runtime/CompiledFunction.java --- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java Fri Sep 05 16:28:02 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java Fri Sep 05 16:28:17 2014 +0200 @@ -38,6 +38,7 @@ import java.util.TreeMap; import java.util.function.Supplier; import java.util.logging.Level; + import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;