8013203: A collection of smaller speedups to compilation pipeline
authorattila
Thu, 25 Apr 2013 14:47:17 +0200
changeset 17246 a1bcf4d2bff1
parent 17245 c49b17cd464b
child 17247 607f6372b21b
8013203: A collection of smaller speedups to compilation pipeline Reviewed-by: hannesw, jlaskey
nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
nashorn/src/jdk/nashorn/internal/parser/Lexer.java
nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Apr 25 14:20:23 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Apr 25 14:47:17 2013 +0200
@@ -1120,7 +1120,7 @@
 
     @Override
     public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
-        final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getLexicalContext().getCurrentFunction().getName() + ")");
+        final Label label = new Label((String)null);
         method.label(label);
         method.lineNumber(lineNumberNode.getLineNumber(), label);
         return false;
--- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Thu Apr 25 14:20:23 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Thu Apr 25 14:47:17 2013 +0200
@@ -32,7 +32,6 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.Assignment;
--- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Apr 25 14:20:23 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Apr 25 14:47:17 2013 +0200
@@ -71,7 +71,6 @@
 import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.List;
-
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.internal.org.objectweb.asm.Handle;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -674,7 +673,7 @@
      * @return the method emitter
      */
     MethodEmitter loadUndefined(final Type type) {
-        debug("load undefined " + type);
+        debug("load undefined ", type);
         pushType(type.loadUndefined(method));
         return this;
     }
@@ -686,7 +685,7 @@
      * @return the method emitter
      */
     MethodEmitter loadEmpty(final Type type) {
-        debug("load empty " + type);
+        debug("load empty ", type);
         pushType(type.loadEmpty(method));
         return this;
     }
@@ -1076,7 +1075,7 @@
      * @return the method emitter
      */
     MethodEmitter newarray(final ArrayType arrayType) {
-        debug("newarray ", "arrayType=" + arrayType);
+        debug("newarray ", "arrayType=", arrayType);
         popType(Type.INT); //LENGTH
         pushType(arrayType.newarray(method));
         return this;
@@ -1155,7 +1154,7 @@
      * @return the method emitter
      */
     MethodEmitter invokespecial(final String className, final String methodName, final String methodDescriptor) {
-        debug("invokespecial", className + "." + methodName + methodDescriptor);
+        debug("invokespecial", className, ".", methodName, methodDescriptor);
         return invoke(INVOKESPECIAL, className, methodName, methodDescriptor, true);
     }
 
@@ -1169,7 +1168,7 @@
      * @return the method emitter
      */
     MethodEmitter invokevirtual(final String className, final String methodName, final String methodDescriptor) {
-        debug("invokevirtual", className + "." + methodName + methodDescriptor + " " + stack);
+        debug("invokevirtual", className, ".", methodName, methodDescriptor, " ", stack);
         return invoke(INVOKEVIRTUAL, className, methodName, methodDescriptor, true);
     }
 
@@ -1183,7 +1182,7 @@
      * @return the method emitter
      */
     MethodEmitter invokestatic(final String className, final String methodName, final String methodDescriptor) {
-        debug("invokestatic", className + "." + methodName + methodDescriptor);
+        debug("invokestatic", className, ".", methodName, methodDescriptor);
         invoke(INVOKESTATIC, className, methodName, methodDescriptor, false);
         return this;
     }
@@ -1216,7 +1215,7 @@
      * @return the method emitter
      */
     MethodEmitter invokeinterface(final String className, final String methodName, final String methodDescriptor) {
-        debug("invokeinterface", className + "." + methodName + methodDescriptor);
+        debug("invokeinterface", className, ".", methodName, methodDescriptor);
         return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
     }
 
@@ -1268,11 +1267,11 @@
      */
     void conditionalJump(final Condition cond, final boolean isCmpG, final Label trueLabel) {
         if (peekType().isCategory2()) {
-            debug("[ld]cmp isCmpG=" + isCmpG);
+            debug("[ld]cmp isCmpG=", isCmpG);
             pushType(get2n().cmp(method, isCmpG));
             jump(Condition.toUnary(cond), trueLabel, 1);
         } else {
-            debug("if" + cond);
+            debug("if", cond);
             jump(Condition.toBinary(cond, peekType().isObject()), trueLabel, 2);
         }
     }
@@ -1517,7 +1516,7 @@
      */
     private void mergeStackTo(final Label label) {
         final ArrayDeque<Type> labelStack = label.getStack();
-        //debug(labelStack == null ? " >> Control flow - first visit " + label : " >> Control flow - JOIN with " + labelStack + " at " + label);
+        //debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label);
         if (labelStack == null) {
             assert stack != null;
             label.setStack(stack.clone());
@@ -1710,7 +1709,7 @@
      * @return the method emitter
      */
     MethodEmitter dynamicNew(final int argCount, final int flags) {
-        debug("dynamic_new", "argcount=" + argCount);
+        debug("dynamic_new", "argcount=", argCount);
         final String signature = getDynamicSignature(Type.OBJECT, argCount);
         method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags);
         pushType(Type.OBJECT); //TODO fix result type
@@ -1727,7 +1726,7 @@
      * @return the method emitter
      */
     MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) {
-        debug("dynamic_call", "args=" + argCount, "returnType=" + returnType);
+        debug("dynamic_call", "args=", argCount, "returnType=", returnType);
         final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
         debug("   signature", signature);
         method.visitInvokeDynamicInsn("dyn:call", signature, LINKERBOOTSTRAP, flags);
@@ -1746,7 +1745,7 @@
      * @return the method emitter
      */
     MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) {
-        debug("dynamic_runtime_call", name, "args=" + request.getArity(), "returnType=" + returnType);
+        debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType);
         final String signature = getDynamicSignature(returnType, request.getArity());
         debug("   signature", signature);
         method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP);
@@ -1817,7 +1816,7 @@
      * @return the method emitter
      */
     MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
-        debug("dynamic_get_index", peekType(1) + "[" + peekType() + "]");
+        debug("dynamic_get_index", peekType(1), "[", peekType(), "]");
 
         Type resultType = result;
         if (result.isBoolean()) {
@@ -1853,7 +1852,7 @@
      * @param flags call site flags for setter
      */
     void dynamicSetIndex(final int flags) {
-        debug("dynamic_set_index", peekType(2) + "[" + peekType(1) + "] =", peekType());
+        debug("dynamic_set_index", peekType(2), "[", peekType(1), "] =", peekType());
 
         Type value = peekType();
         if (value.isObject() || value.isBoolean()) {
@@ -1953,7 +1952,7 @@
      * @return the method emitter
      */
     MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) {
-        debug("getfield", "receiver=" + peekType(), className + "." + fieldName + fieldDescriptor);
+        debug("getfield", "receiver=", peekType(), className, ".", fieldName, fieldDescriptor);
         final Type receiver = popType();
         assert receiver.isObject();
         method.visitFieldInsn(GETFIELD, className, fieldName, fieldDescriptor);
@@ -1971,7 +1970,7 @@
      * @return the method emitter
      */
     MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) {
-        debug("getstatic", className + "." + fieldName + "." + fieldDescriptor);
+        debug("getstatic", className, ".", fieldName, ".", fieldDescriptor);
         method.visitFieldInsn(GETSTATIC, className, fieldName, fieldDescriptor);
         pushType(fieldType(fieldDescriptor));
         return this;
@@ -1985,7 +1984,7 @@
      * @param fieldDescriptor field descriptor
      */
     void putField(final String className, final String fieldName, final String fieldDescriptor) {
-        debug("putfield", "receiver=" + peekType(1), "value=" + peekType());
+        debug("putfield", "receiver=", peekType(1), "value=", peekType());
         popType(fieldType(fieldDescriptor));
         popType(Type.OBJECT);
         method.visitFieldInsn(PUTFIELD, className, fieldName, fieldDescriptor);
@@ -1999,7 +1998,7 @@
      * @param fieldDescriptor field descriptor
      */
     void putStatic(final String className, final String fieldName, final String fieldDescriptor) {
-        debug("putfield", "value=" + peekType());
+        debug("putfield", "value=", peekType());
         popType(fieldType(fieldDescriptor));
         method.visitFieldInsn(PUTSTATIC, className, fieldName, fieldDescriptor);
     }
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Thu Apr 25 14:20:23 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Thu Apr 25 14:47:17 2013 +0200
@@ -222,6 +222,22 @@
     }
 
     /**
+     * Returns the number of fields in the JavaScript scope class. Its name had to be generated using either
+     * {@link #getClassName(int)} or {@link #getClassName(int, int)}.
+     * @param clazz the JavaScript scope class.
+     * @return the number of fields in the scope class.
+     */
+    public static int getFieldCount(Class<?> clazz) {
+        final String name = clazz.getSimpleName();
+        final String prefix = JS_OBJECT_PREFIX.symbolName();
+        if(prefix.equals(name)) {
+            return 0;
+        }
+        final int scopeMarker = name.indexOf(SCOPE_MARKER);
+        return Integer.parseInt(scopeMarker == -1 ? name.substring(prefix.length()) : name.substring(prefix.length(), scopeMarker));
+    }
+
+    /**
      * Returns the name of a field based on number and type.
      *
      * @param fieldIndex Ordinal of field.
--- a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java	Thu Apr 25 14:20:23 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java	Thu Apr 25 14:47:17 2013 +0200
@@ -57,6 +57,9 @@
  */
 @SuppressWarnings("fallthrough")
 public class Lexer extends Scanner {
+    private static final long MIN_INT_L = Integer.MIN_VALUE;
+    private static final long MAX_INT_L = Integer.MAX_VALUE;
+
     private static final boolean XML_LITERALS = Options.getBooleanProperty("nashorn.lexer.xmlliterals");
 
     /** Content source. */
@@ -984,27 +987,27 @@
      */
     private static Number valueOf(final String valueString, final int radix) throws NumberFormatException {
         try {
-            return Integer.valueOf(valueString, radix);
+            final long value = Long.parseLong(valueString, radix);
+            if(value >= MIN_INT_L && value <= MAX_INT_L) {
+                return Integer.valueOf((int)value);
+            }
+            return Long.valueOf(value);
         } catch (final NumberFormatException e) {
-            try {
-                return Long.valueOf(valueString, radix);
-            } catch (final NumberFormatException e2) {
-                if (radix == 10) {
-                    return Double.valueOf(valueString);
-                }
-
-                double value = 0.0;
+            if (radix == 10) {
+                return Double.valueOf(valueString);
+            }
 
-                for (int i = 0; i < valueString.length(); i++) {
-                    final char ch = valueString.charAt(i);
-                    // Preverified, should always be a valid digit.
-                    final int digit = convertDigit(ch, radix);
-                    value *= radix;
-                    value += digit;
-                }
+            double value = 0.0;
 
-                return value;
+            for (int i = 0; i < valueString.length(); i++) {
+                final char ch = valueString.charAt(i);
+                // Preverified, should always be a valid digit.
+                final int digit = convertDigit(ch, radix);
+                value *= radix;
+                value += digit;
             }
+
+            return value;
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Apr 25 14:20:23 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Apr 25 14:47:17 2013 +0200
@@ -54,10 +54,24 @@
  * @see SpillProperty
  */
 public class AccessorProperty extends Property {
+    private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
     private static final MethodHandle REPLACE_MAP = findOwnMH("replaceMap", Object.class, Object.class, PropertyMap.class, String.class, Class.class, Class.class);
 
     private static final int NOOF_TYPES = getNumberOfAccessorTypes();
 
+    /**
+     * Properties in different maps for the same structure class will share their field getters and setters. This could
+     * be further extended to other method handles that are looked up in the AccessorProperty constructor, but right now
+     * these are the most frequently retrieved ones, and lookup of method handle natives only registers in the profiler
+     * for them.
+     */
+    private static ClassValue<GettersSetters> GETTERS_SETTERS = new ClassValue<GettersSetters>() {
+        @Override
+        protected GettersSetters computeValue(Class<?> structure) {
+            return new GettersSetters(structure);
+        }
+    };
+
     /** Property getter cache */
     private MethodHandle[] getters = new MethodHandle[NOOF_TYPES];
 
@@ -152,6 +166,22 @@
         setCurrentType(getterType);
     }
 
+    private static class GettersSetters {
+        final MethodHandle[] getters;
+        final MethodHandle[] setters;
+
+        public GettersSetters(Class<?> structure) {
+            final int fieldCount = ObjectClassGenerator.getFieldCount(structure);
+            getters = new MethodHandle[fieldCount];
+            setters = new MethodHandle[fieldCount];
+            for(int i = 0; i < fieldCount; ++i) {
+                final String fieldName = ObjectClassGenerator.getFieldName(i, Type.OBJECT);
+                getters[i] = MH.getter(lookup, structure, fieldName, Type.OBJECT.getTypeClass());
+                setters[i] = MH.setter(lookup, structure, fieldName, Type.OBJECT.getTypeClass());
+            }
+        }
+    }
+
     /**
      * Constructor for dual field AccessorPropertys.
      *
@@ -171,22 +201,19 @@
         primitiveGetter = null;
         primitiveSetter = null;
 
-        final MethodHandles.Lookup lookup = MethodHandles.lookup();
-
         if (isParameter() && hasArguments()) {
-            final MethodHandle arguments   = MH.getter(MethodHandles.lookup(), structure, "arguments", Object.class);
+            final MethodHandle arguments   = MH.getter(lookup, structure, "arguments", Object.class);
             final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class));
 
             objectGetter = MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot);
             objectSetter = MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot);
         } else {
-            final String fieldNameObject    = ObjectClassGenerator.getFieldName(slot, Type.OBJECT);
-            final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(slot, ObjectClassGenerator.PRIMITIVE_TYPE);
-
-            objectGetter = MH.getter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
-            objectSetter = MH.setter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
+            final GettersSetters gs = GETTERS_SETTERS.get(structure);
+            objectGetter = gs.getters[slot];
+            objectSetter = gs.setters[slot];
 
             if (!OBJECT_FIELDS_ONLY) {
+                final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(slot, ObjectClassGenerator.PRIMITIVE_TYPE);
                 primitiveGetter = MH.getter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
                 primitiveSetter = MH.setter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
             }
@@ -365,7 +392,7 @@
     }
 
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
-        return MH.findStatic(MethodHandles.lookup(), AccessorProperty.class, name, MH.type(rtype, types));
+        return MH.findStatic(lookup, AccessorProperty.class, name, MH.type(rtype, types));
     }
 
 }