8057703: More empty classes generated by Nashorn

Wed, 10 Sep 2014 12:37:44 +0200

author
lagergren
date
Wed, 10 Sep 2014 12:37:44 +0200
changeset 1004
698280da463a
parent 1003
3f49db18721f
child 1005
2cad9bf911a4

8057703: More empty classes generated by Nashorn
Reviewed-by: attila, sundar

src/jdk/nashorn/internal/codegen/ClassEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CompilationPhase.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CompileUnit.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Compiler.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Timing.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Fri Sep 05 16:28:17 2014 +0200
     1.2 +++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Wed Sep 10 12:37:44 2014 +0200
     1.3 @@ -59,6 +59,7 @@
     1.4  import java.util.EnumSet;
     1.5  import java.util.HashSet;
     1.6  import java.util.Set;
     1.7 +
     1.8  import jdk.internal.org.objectweb.asm.ClassWriter;
     1.9  import jdk.internal.org.objectweb.asm.MethodVisitor;
    1.10  import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
    1.11 @@ -135,6 +136,16 @@
    1.12      /** Set of constants access methods required. */
    1.13      private Set<Class<?>> constantMethodNeeded;
    1.14  
    1.15 +    private int methodCount;
    1.16 +
    1.17 +    private int initCount;
    1.18 +
    1.19 +    private int clinitCount;
    1.20 +
    1.21 +    private int fieldCount;
    1.22 +
    1.23 +    private final Set<String> methodNames;
    1.24 +
    1.25      /**
    1.26       * Constructor - only used internally in this class as it breaks
    1.27       * abstraction towards ASM or other code generator below
    1.28 @@ -146,6 +157,11 @@
    1.29          this.context        = context;
    1.30          this.cw             = cw;
    1.31          this.methodsStarted = new HashSet<>();
    1.32 +        this.methodNames    = new HashSet<>();
    1.33 +    }
    1.34 +
    1.35 +    public Set<String> getMethodNames() {
    1.36 +        return methodNames;
    1.37      }
    1.38  
    1.39      /**
    1.40 @@ -209,6 +225,38 @@
    1.41      }
    1.42  
    1.43      /**
    1.44 +     * Get the method count, including init and clinit methods
    1.45 +     * @return method count
    1.46 +     */
    1.47 +    public int getMethodCount() {
    1.48 +        return methodCount;
    1.49 +    }
    1.50 +
    1.51 +    /**
    1.52 +     * Get the clinit count
    1.53 +     * @return clinit count
    1.54 +     */
    1.55 +    public int getClinitCount() {
    1.56 +        return clinitCount;
    1.57 +    }
    1.58 +
    1.59 +    /**
    1.60 +     * Get the init count
    1.61 +     * @return init count
    1.62 +     */
    1.63 +    public int getInitCount() {
    1.64 +        return initCount;
    1.65 +    }
    1.66 +
    1.67 +    /**
    1.68 +     * Get the field count
    1.69 +     * @return field count
    1.70 +     */
    1.71 +    public int getFieldCount() {
    1.72 +        return fieldCount;
    1.73 +    }
    1.74 +
    1.75 +    /**
    1.76       * Convert a binary name to a package/class name.
    1.77       *
    1.78       * @param name Binary name.
    1.79 @@ -359,9 +407,16 @@
    1.80       */
    1.81      @Override
    1.82      public void end() {
    1.83 -        assert classStarted;
    1.84 +        assert classStarted : "class not started for " + unitClassName;
    1.85  
    1.86          if (unitClassName != null) {
    1.87 +            final MethodEmitter initMethod = init(EnumSet.of(Flag.PRIVATE));
    1.88 +            initMethod.begin();
    1.89 +            initMethod.load(Type.OBJECT, 0);
    1.90 +            initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class);
    1.91 +            initMethod.returnVoid();
    1.92 +            initMethod.end();
    1.93 +
    1.94              defineCommonUtilities();
    1.95          }
    1.96  
    1.97 @@ -419,6 +474,8 @@
    1.98      }
    1.99  
   1.100      SplitMethodEmitter method(final SplitNode splitNode, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
   1.101 +        methodCount++;
   1.102 +        methodNames.add(methodName);
   1.103          return new SplitMethodEmitter(this, methodVisitor(EnumSet.of(Flag.PUBLIC, Flag.STATIC), methodName, rtype, ptypes), splitNode);
   1.104      }
   1.105  
   1.106 @@ -446,6 +503,8 @@
   1.107       * @return method emitter to use for weaving this method
   1.108       */
   1.109      MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
   1.110 +        methodCount++;
   1.111 +        methodNames.add(methodName);
   1.112          return new MethodEmitter(this, methodVisitor(methodFlags, methodName, rtype, ptypes));
   1.113      }
   1.114  
   1.115 @@ -471,6 +530,8 @@
   1.116       * @return method emitter to use for weaving this method
   1.117       */
   1.118      MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final String descriptor) {
   1.119 +        methodCount++;
   1.120 +        methodNames.add(methodName);
   1.121          return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, descriptor, null, null));
   1.122      }
   1.123  
   1.124 @@ -481,6 +542,8 @@
   1.125       * @return method emitter to use for weaving this method
   1.126       */
   1.127      MethodEmitter method(final FunctionNode functionNode) {
   1.128 +        methodCount++;
   1.129 +        methodNames.add(functionNode.getName());
   1.130          final FunctionSignature signature = new FunctionSignature(functionNode);
   1.131          final MethodVisitor mv = cw.visitMethod(
   1.132              ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0),
   1.133 @@ -499,6 +562,8 @@
   1.134       * @return method emitter to use for weaving this method
   1.135       */
   1.136      MethodEmitter restOfMethod(final FunctionNode functionNode) {
   1.137 +        methodCount++;
   1.138 +        methodNames.add(functionNode.getName());
   1.139          final MethodVisitor mv = cw.visitMethod(
   1.140              ACC_PUBLIC | ACC_STATIC,
   1.141              functionNode.getName(),
   1.142 @@ -516,6 +581,7 @@
   1.143       * @return method emitter to use for weaving <clinit>
   1.144       */
   1.145      MethodEmitter clinit() {
   1.146 +        clinitCount++;
   1.147          return method(EnumSet.of(Flag.STATIC), CLINIT.symbolName(), void.class);
   1.148      }
   1.149  
   1.150 @@ -525,6 +591,7 @@
   1.151       * @return method emitter to use for weaving <init>()V
   1.152       */
   1.153      MethodEmitter init() {
   1.154 +        initCount++;
   1.155          return method(INIT.symbolName(), void.class);
   1.156      }
   1.157  
   1.158 @@ -535,6 +602,7 @@
   1.159       * @return method emitter to use for weaving <init>()V
   1.160       */
   1.161      MethodEmitter init(final Class<?>... ptypes) {
   1.162 +        initCount++;
   1.163          return method(INIT.symbolName(), void.class, ptypes);
   1.164      }
   1.165  
   1.166 @@ -547,6 +615,7 @@
   1.167       * @return method emitter to use for weaving <init>(...)V
   1.168       */
   1.169      MethodEmitter init(final EnumSet<Flag> flags, final Class<?>... ptypes) {
   1.170 +        initCount++;
   1.171          return method(flags, INIT.symbolName(), void.class, ptypes);
   1.172      }
   1.173  
   1.174 @@ -561,6 +630,7 @@
   1.175       * @see ClassEmitter.Flag
   1.176       */
   1.177      final void field(final EnumSet<Flag> fieldFlags, final String fieldName, final Class<?> fieldType, final Object value) {
   1.178 +        fieldCount++;
   1.179          cw.visitField(Flag.getValue(fieldFlags), fieldName, typeDescriptor(fieldType), null, value).visitEnd();
   1.180      }
   1.181  
     2.1 --- a/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java	Fri Sep 05 16:28:17 2014 +0200
     2.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java	Wed Sep 10 12:37:44 2014 +0200
     2.3 @@ -31,6 +31,7 @@
     2.4  import java.util.Deque;
     2.5  import java.util.HashMap;
     2.6  import java.util.Map;
     2.7 +
     2.8  import jdk.nashorn.internal.IntDeque;
     2.9  import jdk.nashorn.internal.codegen.types.Type;
    2.10  import jdk.nashorn.internal.ir.Block;
    2.11 @@ -158,7 +159,9 @@
    2.12  
    2.13      CompileUnit popCompileUnit(final CompileUnit oldUnit) {
    2.14          assert compileUnits.peek() == oldUnit;
    2.15 -        compileUnits.pop();
    2.16 +        final CompileUnit unit = compileUnits.pop();
    2.17 +        assert unit.hasCode() : "compile unit popped without code";
    2.18 +        unit.setUsed();
    2.19          return compileUnits.isEmpty() ? null : compileUnits.peek();
    2.20      }
    2.21  
     3.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Fri Sep 05 16:28:17 2014 +0200
     3.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Sep 10 12:37:44 2014 +0200
     3.3 @@ -53,7 +53,6 @@
     3.4  import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
     3.5  import jdk.nashorn.internal.ir.FunctionNode;
     3.6  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
     3.7 -import jdk.nashorn.internal.ir.CompileUnitHolder;
     3.8  import jdk.nashorn.internal.ir.LexicalContext;
     3.9  import jdk.nashorn.internal.ir.LiteralNode;
    3.10  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    3.11 @@ -302,70 +301,6 @@
    3.12          }
    3.13      },
    3.14  
    3.15 -    /**
    3.16 -     * Mark compile units used in the method tree. Used for non-rest compilation only
    3.17 -     */
    3.18 -    MARK_USED_COMPILE_UNITS(
    3.19 -            EnumSet.of(
    3.20 -                    INITIALIZED,
    3.21 -                    PARSED,
    3.22 -                    CONSTANT_FOLDED,
    3.23 -                    LOWERED,
    3.24 -                    BUILTINS_TRANSFORMED,
    3.25 -                    SPLIT,
    3.26 -                    SYMBOLS_ASSIGNED,
    3.27 -                    SCOPE_DEPTHS_COMPUTED,
    3.28 -                    OPTIMISTIC_TYPES_ASSIGNED,
    3.29 -                    LOCAL_VARIABLE_TYPES_CALCULATED)) {
    3.30 -
    3.31 -        @Override
    3.32 -        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
    3.33 -            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
    3.34 -                private void tagUsed(final CompileUnitHolder node) {
    3.35 -                    assert node.getCompileUnit() != null : "no compile unit in " + node;
    3.36 -                    node.getCompileUnit().setUsed();
    3.37 -                }
    3.38 -
    3.39 -                @Override
    3.40 -                public Node leaveFunctionNode(final FunctionNode node) {
    3.41 -                    tagUsed(node);
    3.42 -                    return node;
    3.43 -                }
    3.44 -
    3.45 -                @Override
    3.46 -                public Node leaveSplitNode(final SplitNode node) {
    3.47 -                    tagUsed(node);
    3.48 -                    return node;
    3.49 -                }
    3.50 -
    3.51 -                @Override
    3.52 -                public Node leaveLiteralNode(final LiteralNode<?> node) {
    3.53 -                    if (node instanceof ArrayLiteralNode) {
    3.54 -                        final ArrayLiteralNode aln = (ArrayLiteralNode)node;
    3.55 -                        if (aln.getUnits() != null) {
    3.56 -                            for (final ArrayUnit au : aln.getUnits()) {
    3.57 -                                tagUsed(au);
    3.58 -                            }
    3.59 -                        }
    3.60 -                        return aln;
    3.61 -                    }
    3.62 -                    return node;
    3.63 -                }
    3.64 -
    3.65 -                @Override
    3.66 -                public Node leaveDefault(final Node node) {
    3.67 -                    return node.ensureUniqueLabels(lc);
    3.68 -                }
    3.69 -            });
    3.70 -
    3.71 -            return newFunctionNode;
    3.72 -        }
    3.73 -
    3.74 -        @Override
    3.75 -        public String toString() {
    3.76 -            return "'Tag Compile Units Used'";
    3.77 -        }
    3.78 -    },
    3.79  
    3.80      /**
    3.81       * Reuse compile units, if they are already present. We are using the same compiler
    3.82 @@ -401,6 +336,8 @@
    3.83                  if (phases.isRestOfCompilation()) {
    3.84                      sb.append("$restOf");
    3.85                  }
    3.86 +                //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what
    3.87 +                //fills those out anyway. Thus no need for a copy constructor
    3.88                  final CompileUnit newUnit = compiler.createCompileUnit(sb.toString(), oldUnit.getWeight());
    3.89                  log.fine("Creating new compile unit ", oldUnit, " => ", newUnit);
    3.90                  map.put(oldUnit, newUnit);
    3.91 @@ -425,7 +362,6 @@
    3.92                      assert newUnit != null : "old unit has no mapping to new unit " + oldUnit;
    3.93  
    3.94                      log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName()));
    3.95 -                    newUnit.setUsed();
    3.96                      return node.setCompileUnit(lc, newUnit).setState(lc, CompilationState.COMPILE_UNITS_REUSED);
    3.97                  }
    3.98  
    3.99 @@ -438,7 +374,6 @@
   3.100                      assert newUnit != null : "old unit has no mapping to new unit " + oldUnit;
   3.101  
   3.102                      log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName()));
   3.103 -                    newUnit.setUsed();
   3.104                      return node.setCompileUnit(lc, newUnit);
   3.105                  }
   3.106  
   3.107 @@ -453,7 +388,6 @@
   3.108                          for (final ArrayUnit au : aln.getUnits()) {
   3.109                              final CompileUnit newUnit = map.get(au.getCompileUnit());
   3.110                              assert newUnit != null;
   3.111 -                            newUnit.setUsed();
   3.112                              newArrayUnits.add(new ArrayUnit(newUnit, au.getLo(), au.getHi()));
   3.113                          }
   3.114                          return aln.setUnits(lc, newArrayUnits);
   3.115 @@ -500,8 +434,14 @@
   3.116  
   3.117              FunctionNode newFunctionNode = fn;
   3.118  
   3.119 +            //root class is special, as it is bootstrapped from createProgramFunction, thus it's skipped
   3.120 +            //in CodeGeneration - the rest can be used as a working "is compile unit used" metric
   3.121 +            fn.getCompileUnit().setUsed();
   3.122 +
   3.123              compiler.getLogger().fine("Starting bytecode generation for ", quote(fn.getName()), " - restOf=", phases.isRestOfCompilation());
   3.124 +
   3.125              final CodeGenerator codegen = new CodeGenerator(compiler, phases.isRestOfCompilation() ? compiler.getContinuationEntryPoints() : null);
   3.126 +
   3.127              try {
   3.128                  // Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program
   3.129                  // in the lazy + optimistic world. See CodeGenerator.skipFunction().
   3.130 @@ -522,19 +462,21 @@
   3.131              }
   3.132  
   3.133              for (final CompileUnit compileUnit : compiler.getCompileUnits()) {
   3.134 +                final ClassEmitter classEmitter = compileUnit.getClassEmitter();
   3.135 +                classEmitter.end();
   3.136 +
   3.137                  if (!compileUnit.isUsed()) {
   3.138                      compiler.getLogger().fine("Skipping unused compile unit ", compileUnit);
   3.139                      continue;
   3.140                  }
   3.141  
   3.142 -                final ClassEmitter classEmitter = compileUnit.getClassEmitter();
   3.143 -                classEmitter.end();
   3.144 -
   3.145                  final byte[] bytecode = classEmitter.toByteArray();
   3.146                  assert bytecode != null;
   3.147  
   3.148                  final String className = compileUnit.getUnitClassName();
   3.149 -                compiler.addClass(className, bytecode);
   3.150 +                compiler.addClass(className, bytecode); //classes are only added to the bytecode map if compile unit is used
   3.151 +
   3.152 +                CompileUnit.increaseEmitCount();
   3.153  
   3.154                  // should we verify the generated code?
   3.155                  if (senv._verify_code) {
     4.1 --- a/src/jdk/nashorn/internal/codegen/CompileUnit.java	Fri Sep 05 16:28:17 2014 +0200
     4.2 +++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java	Wed Sep 10 12:37:44 2014 +0200
     4.3 @@ -44,6 +44,8 @@
     4.4  
     4.5      private boolean isUsed;
     4.6  
     4.7 +    private static int emittedUnitCount;
     4.8 +
     4.9      CompileUnit(final String className, final ClassEmitter classEmitter, final long initialWeight) {
    4.10          this.className    = className;
    4.11          this.weight       = initialWeight;
    4.12 @@ -54,6 +56,14 @@
    4.13          return new TreeSet<>();
    4.14      }
    4.15  
    4.16 +    static void increaseEmitCount() {
    4.17 +        emittedUnitCount++;
    4.18 +    }
    4.19 +
    4.20 +    public static int getEmittedUnitCount() {
    4.21 +        return emittedUnitCount;
    4.22 +    }
    4.23 +
    4.24      /**
    4.25       * Check if this compile unit is used
    4.26       * @return true if tagged as in use - i.e active code that needs to be generated
    4.27 @@ -62,6 +72,10 @@
    4.28          return isUsed;
    4.29      }
    4.30  
    4.31 +    public boolean hasCode() {
    4.32 +        return (classEmitter.getMethodCount() - classEmitter.getInitCount() - classEmitter.getClinitCount()) > 0;
    4.33 +    }
    4.34 +
    4.35      /**
    4.36       * Tag this compile unit as used
    4.37       */
    4.38 @@ -138,7 +152,8 @@
    4.39  
    4.40      @Override
    4.41      public String toString() {
    4.42 -        return "[CompileUnit className=" + shortName(className) + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']';
    4.43 +        final String methods = classEmitter != null ? classEmitter.getMethodNames().toString() : "<anon>";
    4.44 +        return "[CompileUnit className=" + shortName(className) + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + " hasCode=" + methods + ']';
    4.45      }
    4.46  
    4.47      @Override
     5.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java	Fri Sep 05 16:28:17 2014 +0200
     5.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Wed Sep 10 12:37:44 2014 +0200
     5.3 @@ -38,7 +38,6 @@
     5.4  import java.util.Arrays;
     5.5  import java.util.Collections;
     5.6  import java.util.Comparator;
     5.7 -import java.util.EnumSet;
     5.8  import java.util.HashMap;
     5.9  import java.util.Iterator;
    5.10  import java.util.LinkedHashMap;
    5.11 @@ -51,7 +50,6 @@
    5.12  import java.util.function.Consumer;
    5.13  import java.util.logging.Level;
    5.14  import jdk.internal.dynalink.support.NameCodec;
    5.15 -import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
    5.16  import jdk.nashorn.internal.codegen.types.Type;
    5.17  import jdk.nashorn.internal.ir.Expression;
    5.18  import jdk.nashorn.internal.ir.FunctionNode;
    5.19 @@ -173,14 +171,13 @@
    5.20                          CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
    5.21                          CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
    5.22                          CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE,
    5.23 -                        CompilationPhase.MARK_USED_COMPILE_UNITS,
    5.24                          CompilationPhase.BYTECODE_GENERATION_PHASE,
    5.25                          CompilationPhase.INSTALL_PHASE
    5.26                  });
    5.27  
    5.28          /** Compile all for a rest of method */
    5.29          public final static CompilationPhases COMPILE_ALL_RESTOF =
    5.30 -                COMPILE_ALL.setDescription("Compile all, rest of").replace(CompilationPhase.MARK_USED_COMPILE_UNITS, CompilationPhase.REUSE_COMPILE_UNITS_PHASE);
    5.31 +                COMPILE_ALL.setDescription("Compile all, rest of").addAfter(CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, CompilationPhase.REUSE_COMPILE_UNITS_PHASE);
    5.32  
    5.33          /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
    5.34          public final static CompilationPhases COMPILE_ALL_NO_INSTALL =
    5.35 @@ -251,6 +248,7 @@
    5.36              return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
    5.37          }
    5.38  
    5.39 +        @SuppressWarnings("unused") //TODO I'll use this soon
    5.40          private CompilationPhases replace(final CompilationPhase phase, final CompilationPhase newPhase) {
    5.41              final LinkedList<CompilationPhase> list = new LinkedList<>();
    5.42              for (final CompilationPhase p : phases) {
    5.43 @@ -259,7 +257,6 @@
    5.44              return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
    5.45          }
    5.46  
    5.47 -        @SuppressWarnings("unused") //TODO I'll use this soon
    5.48          private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) {
    5.49              final LinkedList<CompilationPhase> list = new LinkedList<>();
    5.50              for (final CompilationPhase p : phases) {
    5.51 @@ -700,16 +697,8 @@
    5.52      CompileUnit createCompileUnit(final String unitClassName, final long initialWeight) {
    5.53          final ClassEmitter classEmitter = new ClassEmitter(context, sourceName, unitClassName, isStrict());
    5.54          final CompileUnit  compileUnit  = new CompileUnit(unitClassName, classEmitter, initialWeight);
    5.55 -
    5.56          classEmitter.begin();
    5.57  
    5.58 -        final MethodEmitter initMethod = classEmitter.init(EnumSet.of(Flag.PRIVATE));
    5.59 -        initMethod.begin();
    5.60 -        initMethod.load(Type.OBJECT, 0);
    5.61 -        initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class);
    5.62 -        initMethod.returnVoid();
    5.63 -        initMethod.end();
    5.64 -
    5.65          return compileUnit;
    5.66      }
    5.67  
     6.1 --- a/src/jdk/nashorn/internal/runtime/Timing.java	Fri Sep 05 16:28:17 2014 +0200
     6.2 +++ b/src/jdk/nashorn/internal/runtime/Timing.java	Wed Sep 10 12:37:44 2014 +0200
     6.3 @@ -33,6 +33,8 @@
     6.4  import java.util.Map;
     6.5  import java.util.concurrent.TimeUnit;
     6.6  import java.util.function.Supplier;
     6.7 +
     6.8 +import jdk.nashorn.internal.codegen.CompileUnit;
     6.9  import jdk.nashorn.internal.runtime.logging.DebugLogger;
    6.10  import jdk.nashorn.internal.runtime.logging.Loggable;
    6.11  import jdk.nashorn.internal.runtime.logging.Logger;
    6.12 @@ -224,6 +226,9 @@
    6.13                  append((int)(knownTime * 100.0 / total)).
    6.14                  append("%])");
    6.15  
    6.16 +            sb.append("\n\nEmitted compile units: ").
    6.17 +                append(CompileUnit.getEmittedUnitCount());
    6.18 +
    6.19              return sb.toString();
    6.20          }
    6.21  

mercurial