Mon, 29 Sep 2014 14:39:58 -0700
8059321: Decrease warmup time by caching common structures that were reused during parse
Reviewed-by: attila, hannesw
1.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java Thu Sep 25 15:53:47 2014 +0200 1.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Mon Sep 29 14:39:58 2014 -0700 1.3 @@ -32,7 +32,6 @@ 1.4 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 1.5 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 1.6 import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote; 1.7 - 1.8 import java.io.File; 1.9 import java.lang.invoke.MethodType; 1.10 import java.util.Arrays; 1.11 @@ -154,6 +153,13 @@ 1.12 private RecompilableScriptFunctionData compiledFunction; 1.13 1.14 /** 1.15 + * Most compile unit names are longer than the default StringBuilder buffer, 1.16 + * worth startup performance when massive class generation is going on to increase 1.17 + * this 1.18 + */ 1.19 + private static final int COMPILE_UNIT_NAME_BUFFER_SIZE = 32; 1.20 + 1.21 + /** 1.22 * Compilation phases that a compilation goes through 1.23 */ 1.24 public static class CompilationPhases implements Iterable<CompilationPhase> { 1.25 @@ -631,7 +637,8 @@ 1.26 } 1.27 1.28 String nextCompileUnitName() { 1.29 - final StringBuilder sb = new StringBuilder(firstCompileUnitName); 1.30 + final StringBuilder sb = new StringBuilder(COMPILE_UNIT_NAME_BUFFER_SIZE); 1.31 + sb.append(firstCompileUnitName); 1.32 final int cuid = nextCompileUnitId.getAndIncrement(); 1.33 if (cuid > 0) { 1.34 sb.append("$cu").append(cuid);
2.1 --- a/src/jdk/nashorn/internal/codegen/Label.java Thu Sep 25 15:53:47 2014 +0200 2.2 +++ b/src/jdk/nashorn/internal/codegen/Label.java Mon Sep 29 14:39:58 2014 -0700 2.3 @@ -590,8 +590,13 @@ 2.4 return label.getOffset() > other.label.getOffset(); 2.5 } 2.6 2.7 + private String str; 2.8 + 2.9 @Override 2.10 public String toString() { 2.11 - return name + '_' + id; 2.12 + if (str == null) { 2.13 + str = name + '_' + id; 2.14 + } 2.15 + return str; 2.16 } 2.17 }
3.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Thu Sep 25 15:53:47 2014 +0200 3.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Mon Sep 29 14:39:58 2014 -0700 3.3 @@ -2586,12 +2586,55 @@ 3.4 * 3.5 * @param args debug information to print 3.6 */ 3.7 + @SuppressWarnings("unused") 3.8 private void debug(final Object... args) { 3.9 if (debug) { 3.10 debug(30, args); 3.11 } 3.12 } 3.13 3.14 + private void debug(final String arg) { 3.15 + if (debug) { 3.16 + debug(30, arg); 3.17 + } 3.18 + } 3.19 + 3.20 + private void debug(final Object arg0, final Object arg1) { 3.21 + if (debug) { 3.22 + debug(30, new Object[] { arg0, arg1 }); 3.23 + } 3.24 + } 3.25 + 3.26 + private void debug(final Object arg0, final Object arg1, final Object arg2) { 3.27 + if (debug) { 3.28 + debug(30, new Object[] { arg0, arg1, arg2 }); 3.29 + } 3.30 + } 3.31 + 3.32 + private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3) { 3.33 + if (debug) { 3.34 + debug(30, new Object[] { arg0, arg1, arg2, arg3 }); 3.35 + } 3.36 + } 3.37 + 3.38 + private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4) { 3.39 + if (debug) { 3.40 + debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4 }); 3.41 + } 3.42 + } 3.43 + 3.44 + private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5) { 3.45 + if (debug) { 3.46 + debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4, arg5 }); 3.47 + } 3.48 + } 3.49 + 3.50 + private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5, final Object arg6) { 3.51 + if (debug) { 3.52 + debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4, arg5, arg6 }); 3.53 + } 3.54 + } 3.55 + 3.56 /** 3.57 * Debug function that outputs generated bytecode and stack contents 3.58 * for a label - indentation is currently the only thing that differs
4.1 --- a/src/jdk/nashorn/internal/codegen/types/Type.java Thu Sep 25 15:53:47 2014 +0200 4.2 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java Mon Sep 29 14:39:58 2014 -0700 4.3 @@ -54,8 +54,10 @@ 4.4 import java.lang.invoke.MethodHandle; 4.5 import java.lang.invoke.MethodHandles; 4.6 import java.lang.invoke.MethodType; 4.7 +import java.util.Collections; 4.8 import java.util.Map; 4.9 import java.util.TreeMap; 4.10 +import java.util.WeakHashMap; 4.11 import java.util.concurrent.ConcurrentHashMap; 4.12 import java.util.concurrent.ConcurrentMap; 4.13 import jdk.internal.org.objectweb.asm.Handle; 4.14 @@ -103,6 +105,16 @@ 4.15 /** The class for this type */ 4.16 private final Class<?> clazz; 4.17 4.18 + /** 4.19 + * Cache for internal types - this is a query that requires complex stringbuilding inside 4.20 + * ASM and it saves startup time to cache the type mappings 4.21 + */ 4.22 + private static final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> INTERNAL_TYPE_CACHE = 4.23 + Collections.synchronizedMap(new WeakHashMap<Class<?>, jdk.internal.org.objectweb.asm.Type>()); 4.24 + 4.25 + /** Internal ASM type for this Type - computed once at construction */ 4.26 + private final jdk.internal.org.objectweb.asm.Type internalType; 4.27 + 4.28 /** Weights are used to decide which types are "wider" than other types */ 4.29 protected static final int MIN_WEIGHT = -1; 4.30 4.31 @@ -121,12 +133,13 @@ 4.32 * @param slots how many bytecode slots the type takes up 4.33 */ 4.34 Type(final String name, final Class<?> clazz, final int weight, final int slots) { 4.35 - this.name = name; 4.36 - this.clazz = clazz; 4.37 - this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz); 4.38 - this.weight = weight; 4.39 + this.name = name; 4.40 + this.clazz = clazz; 4.41 + this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz); 4.42 + this.weight = weight; 4.43 assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight; 4.44 - this.slots = slots; 4.45 + this.slots = slots; 4.46 + this.internalType = getInternalType(clazz); 4.47 } 4.48 4.49 /** 4.50 @@ -356,11 +369,22 @@ 4.51 } 4.52 4.53 private jdk.internal.org.objectweb.asm.Type getInternalType() { 4.54 - return jdk.internal.org.objectweb.asm.Type.getType(getTypeClass()); 4.55 + return internalType; 4.56 + } 4.57 + 4.58 + private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class<?> type) { 4.59 + final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> cache = INTERNAL_TYPE_CACHE; 4.60 + jdk.internal.org.objectweb.asm.Type itype = cache.get(type); 4.61 + if (itype != null) { 4.62 + return itype; 4.63 + } 4.64 + itype = jdk.internal.org.objectweb.asm.Type.getType(type); 4.65 + cache.put(type, itype); 4.66 + return itype; 4.67 } 4.68 4.69 private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) { 4.70 - return jdk.internal.org.objectweb.asm.Type.getType(type); 4.71 + return lookupInternalType(type); 4.72 } 4.73 4.74 static void invokestatic(final MethodVisitor method, final Call call) {
5.1 --- a/src/jdk/nashorn/internal/parser/AbstractParser.java Thu Sep 25 15:53:47 2014 +0200 5.2 +++ b/src/jdk/nashorn/internal/parser/AbstractParser.java Mon Sep 29 14:39:58 2014 -0700 5.3 @@ -30,7 +30,6 @@ 5.4 import static jdk.nashorn.internal.parser.TokenType.EOF; 5.5 import static jdk.nashorn.internal.parser.TokenType.EOL; 5.6 import static jdk.nashorn.internal.parser.TokenType.IDENT; 5.7 - 5.8 import java.util.HashMap; 5.9 import java.util.Map; 5.10 import jdk.nashorn.internal.ir.IdentNode;
6.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu Sep 25 15:53:47 2014 +0200 6.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Mon Sep 29 14:39:58 2014 -0700 6.3 @@ -589,7 +589,9 @@ 6.4 } 6.5 6.6 MethodHandle lookupCodeMethod(final Class<?> codeClass, final MethodType targetType) { 6.7 - log.info("Looking up ", DebugLogger.quote(name), " type=", targetType); 6.8 + if (log.isEnabled()) { 6.9 + log.info("Looking up ", DebugLogger.quote(name), " type=", targetType); 6.10 + } 6.11 return MH.findStatic(LOOKUP, codeClass, functionName, targetType); 6.12 } 6.13
7.1 --- a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Thu Sep 25 15:53:47 2014 +0200 7.2 +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Mon Sep 29 14:39:58 2014 -0700 7.3 @@ -25,6 +25,9 @@ 7.4 7.5 package jdk.nashorn.internal.runtime.regexp; 7.6 7.7 +import java.util.Collections; 7.8 +import java.util.Set; 7.9 +import java.util.WeakHashMap; 7.10 import jdk.nashorn.internal.runtime.ParserException; 7.11 import jdk.nashorn.internal.runtime.options.Options; 7.12 7.13 @@ -39,6 +42,15 @@ 7.14 private final static String JDK = "jdk"; 7.15 private final static String JONI = "joni"; 7.16 7.17 + /** Weak cache of already validated regexps - when reparsing, we don't, for example 7.18 + * need to recompile (reverify) all regexps that have previously been parsed by this 7.19 + * RegExpFactory in a previous compilation. This saves significant time in e.g. avatar 7.20 + * startup */ 7.21 + private static final Set<String> VALID_CACHE_SET = 7.22 + Collections.newSetFromMap( 7.23 + Collections.synchronizedMap( 7.24 + new WeakHashMap<String, Boolean>())); 7.25 + 7.26 static { 7.27 final String impl = Options.getStringProperty("nashorn.regexp.impl", JONI); 7.28 switch (impl) { 7.29 @@ -88,7 +100,9 @@ 7.30 */ 7.31 // @SuppressWarnings({"unused"}) 7.32 public static void validate(final String pattern, final String flags) throws ParserException { 7.33 - instance.compile(pattern, flags); 7.34 + if (VALID_CACHE_SET.add(pattern + flags)) { 7.35 + instance.compile(pattern, flags); 7.36 + } 7.37 } 7.38 7.39 /**