8057588: Lots of trivial (empty) classes were generated by the Nashorn compiler as part of restOf-method generation
authorlagergren
Fri, 05 Sep 2014 16:28:17 +0200
changeset 26500 85ea77a73bb8
parent 26499 2c45298da366
child 26501 3a1da7b354c1
8057588: Lots of trivial (empty) classes were generated by the Nashorn compiler as part of restOf-method generation Reviewed-by: attila, sundar, hannesw
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CompileUnitHolder.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Fri Sep 05 16:28:02 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/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<LexicalContext>(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()));
             }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java	Fri Sep 05 16:28:02 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/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
      *
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Fri Sep 05 16:28:02 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Fri Sep 05 16:28:17 2014 +0200
@@ -171,13 +171,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 =
@@ -248,6 +249,15 @@
             return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
         }
 
+        private CompilationPhases replace(final CompilationPhase phase, final CompilationPhase newPhase) {
+            final LinkedList<CompilationPhase> 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<CompilationPhase> list = new LinkedList<>();
             for (final CompilationPhase p : phases) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/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();
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Fri Sep 05 16:28:02 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/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;
@@ -57,7 +55,7 @@
  * IR representation for function (or script.)
  */
 @Immutable
-public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode> {
+public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode>, CompileUnitHolder {
     /** Type used for all FunctionNodes */
     public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
 
@@ -1102,6 +1100,7 @@
      * @see Compiler
      * @return the compile unit
      */
+    @Override
     public CompileUnit getCompileUnit() {
         return compileUnit;
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java	Fri Sep 05 16:28:02 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/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;
             }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java	Fri Sep 05 16:28:02 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/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;
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Fri Sep 05 16:28:02 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/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;