8059321: Decrease warmup time by caching common structures that were reused during parse
Reviewed-by: attila, shade
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Fri Sep 26 18:47:20 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Mon Sep 29 14:39:58 2014 -0700
@@ -32,7 +32,6 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
-
import java.io.File;
import java.lang.invoke.MethodType;
import java.util.Arrays;
@@ -154,6 +153,13 @@
private RecompilableScriptFunctionData compiledFunction;
/**
+ * Most compile unit names are longer than the default StringBuilder buffer,
+ * worth startup performance when massive class generation is going on to increase
+ * this
+ */
+ private static final int COMPILE_UNIT_NAME_BUFFER_SIZE = 32;
+
+ /**
* Compilation phases that a compilation goes through
*/
public static class CompilationPhases implements Iterable<CompilationPhase> {
@@ -631,7 +637,8 @@
}
String nextCompileUnitName() {
- final StringBuilder sb = new StringBuilder(firstCompileUnitName);
+ final StringBuilder sb = new StringBuilder(COMPILE_UNIT_NAME_BUFFER_SIZE);
+ sb.append(firstCompileUnitName);
final int cuid = nextCompileUnitId.getAndIncrement();
if (cuid > 0) {
sb.append("$cu").append(cuid);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Label.java Fri Sep 26 18:47:20 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Label.java Mon Sep 29 14:39:58 2014 -0700
@@ -590,8 +590,13 @@
return label.getOffset() > other.label.getOffset();
}
+ private String str;
+
@Override
public String toString() {
- return name + '_' + id;
+ if (str == null) {
+ str = name + '_' + id;
+ }
+ return str;
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Fri Sep 26 18:47:20 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Mon Sep 29 14:39:58 2014 -0700
@@ -2576,12 +2576,55 @@
*
* @param args debug information to print
*/
+ @SuppressWarnings("unused")
private void debug(final Object... args) {
if (debug) {
debug(30, args);
}
}
+ private void debug(final String arg) {
+ if (debug) {
+ debug(30, arg);
+ }
+ }
+
+ private void debug(final Object arg0, final Object arg1) {
+ if (debug) {
+ debug(30, new Object[] { arg0, arg1 });
+ }
+ }
+
+ private void debug(final Object arg0, final Object arg1, final Object arg2) {
+ if (debug) {
+ debug(30, new Object[] { arg0, arg1, arg2 });
+ }
+ }
+
+ private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3) {
+ if (debug) {
+ debug(30, new Object[] { arg0, arg1, arg2, arg3 });
+ }
+ }
+
+ private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4) {
+ if (debug) {
+ debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4 });
+ }
+ }
+
+ private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5) {
+ if (debug) {
+ debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4, arg5 });
+ }
+ }
+
+ private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5, final Object arg6) {
+ if (debug) {
+ debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4, arg5, arg6 });
+ }
+ }
+
/**
* Debug function that outputs generated bytecode and stack contents
* for a label - indentation is currently the only thing that differs
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Fri Sep 26 18:47:20 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Mon Sep 29 14:39:58 2014 -0700
@@ -54,8 +54,10 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
+import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import jdk.internal.org.objectweb.asm.Handle;
@@ -103,6 +105,16 @@
/** The class for this type */
private final Class<?> clazz;
+ /**
+ * Cache for internal types - this is a query that requires complex stringbuilding inside
+ * ASM and it saves startup time to cache the type mappings
+ */
+ private static final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> INTERNAL_TYPE_CACHE =
+ Collections.synchronizedMap(new WeakHashMap<Class<?>, jdk.internal.org.objectweb.asm.Type>());
+
+ /** Internal ASM type for this Type - computed once at construction */
+ private final jdk.internal.org.objectweb.asm.Type internalType;
+
/** Weights are used to decide which types are "wider" than other types */
protected static final int MIN_WEIGHT = -1;
@@ -121,12 +133,13 @@
* @param slots how many bytecode slots the type takes up
*/
Type(final String name, final Class<?> clazz, final int weight, final int slots) {
- this.name = name;
- this.clazz = clazz;
- this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz);
- this.weight = weight;
+ this.name = name;
+ this.clazz = clazz;
+ this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz);
+ this.weight = weight;
assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight;
- this.slots = slots;
+ this.slots = slots;
+ this.internalType = getInternalType(clazz);
}
/**
@@ -356,11 +369,22 @@
}
private jdk.internal.org.objectweb.asm.Type getInternalType() {
- return jdk.internal.org.objectweb.asm.Type.getType(getTypeClass());
+ return internalType;
+ }
+
+ private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class<?> type) {
+ final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> cache = INTERNAL_TYPE_CACHE;
+ jdk.internal.org.objectweb.asm.Type itype = cache.get(type);
+ if (itype != null) {
+ return itype;
+ }
+ itype = jdk.internal.org.objectweb.asm.Type.getType(type);
+ cache.put(type, itype);
+ return itype;
}
private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) {
- return jdk.internal.org.objectweb.asm.Type.getType(type);
+ return lookupInternalType(type);
}
static void invokestatic(final MethodVisitor method, final Call call) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java Fri Sep 26 18:47:20 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java Mon Sep 29 14:39:58 2014 -0700
@@ -30,7 +30,6 @@
import static jdk.nashorn.internal.parser.TokenType.EOF;
import static jdk.nashorn.internal.parser.TokenType.EOL;
import static jdk.nashorn.internal.parser.TokenType.IDENT;
-
import java.util.HashMap;
import java.util.Map;
import jdk.nashorn.internal.ir.IdentNode;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Fri Sep 26 18:47:20 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Mon Sep 29 14:39:58 2014 -0700
@@ -589,7 +589,9 @@
}
MethodHandle lookupCodeMethod(final Class<?> codeClass, final MethodType targetType) {
- log.info("Looking up ", DebugLogger.quote(name), " type=", targetType);
+ if (log.isEnabled()) {
+ log.info("Looking up ", DebugLogger.quote(name), " type=", targetType);
+ }
return MH.findStatic(LOOKUP, codeClass, functionName, targetType);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Fri Sep 26 18:47:20 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Mon Sep 29 14:39:58 2014 -0700
@@ -25,6 +25,9 @@
package jdk.nashorn.internal.runtime.regexp;
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
import jdk.nashorn.internal.runtime.ParserException;
import jdk.nashorn.internal.runtime.options.Options;
@@ -39,6 +42,15 @@
private final static String JDK = "jdk";
private final static String JONI = "joni";
+ /** Weak cache of already validated regexps - when reparsing, we don't, for example
+ * need to recompile (reverify) all regexps that have previously been parsed by this
+ * RegExpFactory in a previous compilation. This saves significant time in e.g. avatar
+ * startup */
+ private static final Set<String> VALID_CACHE_SET =
+ Collections.newSetFromMap(
+ Collections.synchronizedMap(
+ new WeakHashMap<String, Boolean>()));
+
static {
final String impl = Options.getStringProperty("nashorn.regexp.impl", JONI);
switch (impl) {
@@ -88,7 +100,9 @@
*/
// @SuppressWarnings({"unused"})
public static void validate(final String pattern, final String flags) throws ParserException {
- instance.compile(pattern, flags);
+ if (VALID_CACHE_SET.add(pattern + flags)) {
+ instance.compile(pattern, flags);
+ }
}
/**