8016267: javac, TypeTag refactoring has provoked performance issues
authorvromero
Tue, 18 Jun 2013 19:02:48 +0100
changeset 18395 d56a5fbf0b32
parent 18394 e7e0700732ad
child 18409 9eb097b4e41c
8016267: javac, TypeTag refactoring has provoked performance issues Reviewed-by: jjg
langtools/src/share/classes/com/sun/tools/javac/code/Type.java
langtools/src/share/classes/com/sun/tools/javac/code/TypeTag.java
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Tue Jun 18 18:57:52 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Tue Jun 18 19:02:48 2013 +0100
@@ -110,49 +110,27 @@
     }
 
     public boolean isNumeric() {
-        switch (tag) {
-            case BYTE: case CHAR:
-            case SHORT:
-            case INT: case LONG:
-            case FLOAT: case DOUBLE:
-                return true;
-            default:
-                return false;
-        }
+        return tag.isNumeric;
     }
 
     public boolean isPrimitive() {
-        return (isNumeric() || tag == BOOLEAN);
+        return tag.isPrimitive;
     }
 
     public boolean isPrimitiveOrVoid() {
-        return (isPrimitive() || tag == VOID);
+        return tag.isPrimitiveOrVoid;
     }
 
     public boolean isReference() {
-        switch (tag) {
-        case CLASS:
-        case ARRAY:
-        case TYPEVAR:
-        case WILDCARD:
-        case ERROR:
-            return true;
-        default:
-            return false;
-        }
+        return tag.isReference;
     }
 
     public boolean isNullOrReference() {
-        return (tag == BOT || isReference());
+        return (tag.isReference || tag == BOT);
     }
 
     public boolean isPartial() {
-        switch(tag) {
-            case ERROR: case UNKNOWN: case UNDETVAR:
-                return true;
-            default:
-                return false;
-        }
+        return tag.isPartial;
     }
 
     /**
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeTag.java	Tue Jun 18 18:57:52 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeTag.java	Tue Jun 18 19:02:48 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -29,6 +29,8 @@
 
 import javax.lang.model.type.TypeKind;
 
+import static com.sun.tools.javac.code.TypeTag.NumericClasses.*;
+
 /** An interface for type tag values, which distinguish between different
  *  sorts of types.
  *
@@ -40,113 +42,170 @@
 public enum TypeTag {
     /** The tag of the basic type `byte'.
      */
-    BYTE(1),
+    BYTE(BYTE_CLASS, BYTE_SUPERCLASSES,
+            TypeTagKind.PRIMITIVE | TypeTagKind.NUMERIC),
 
     /** The tag of the basic type `char'.
      */
-    CHAR(2),
+    CHAR(CHAR_CLASS, CHAR_SUPERCLASSES,
+            TypeTagKind.PRIMITIVE | TypeTagKind.NUMERIC),
 
     /** The tag of the basic type `short'.
      */
-    SHORT(3),
+    SHORT(SHORT_CLASS, SHORT_SUPERCLASSES,
+            TypeTagKind.PRIMITIVE | TypeTagKind.NUMERIC),
 
     /** The tag of the basic type `int'.
      */
-    INT(4),
+    INT(INT_CLASS, INT_SUPERCLASSES,
+            TypeTagKind.PRIMITIVE | TypeTagKind.NUMERIC),
 
     /** The tag of the basic type `long'.
      */
-    LONG(5),
+    LONG(LONG_CLASS, LONG_SUPERCLASSES, TypeTagKind.PRIMITIVE | TypeTagKind.NUMERIC),
 
     /** The tag of the basic type `float'.
      */
-    FLOAT(6),
+    FLOAT(FLOAT_CLASS, FLOAT_SUPERCLASSES, TypeTagKind.PRIMITIVE | TypeTagKind.NUMERIC),
 
     /** The tag of the basic type `double'.
      */
-    DOUBLE(7),
+    DOUBLE(DOUBLE_CLASS, DOUBLE_CLASS, TypeTagKind.PRIMITIVE | TypeTagKind.NUMERIC),
 
     /** The tag of the basic type `boolean'.
      */
-    BOOLEAN,
+    BOOLEAN(TypeTagKind.PRIMITIVE),
 
     /** The tag of the type `void'.
      */
-    VOID,
+    VOID(TypeTagKind.VOID),
 
     /** The tag of all class and interface types.
      */
-    CLASS,
+    CLASS(TypeTagKind.REFERENCE),
 
     /** The tag of all array types.
      */
-    ARRAY,
+    ARRAY(TypeTagKind.REFERENCE),
 
     /** The tag of all (monomorphic) method types.
      */
-    METHOD,
+    METHOD(TypeTagKind.OTHER),
 
     /** The tag of all package "types".
      */
-    PACKAGE,
+    PACKAGE(TypeTagKind.OTHER),
 
     /** The tag of all (source-level) type variables.
      */
-    TYPEVAR,
+    TYPEVAR(TypeTagKind.REFERENCE),
 
     /** The tag of all type arguments.
      */
-    WILDCARD,
+    WILDCARD(TypeTagKind.REFERENCE),
 
     /** The tag of all polymorphic (method-) types.
      */
-    FORALL,
+    FORALL(TypeTagKind.OTHER),
 
     /** The tag of deferred expression types in method context
      */
-    DEFERRED,
+    DEFERRED(TypeTagKind.OTHER),
 
     /** The tag of the bottom type {@code <null>}.
      */
-    BOT,
+    BOT(TypeTagKind.OTHER),
 
     /** The tag of a missing type.
      */
-    NONE,
+    NONE(TypeTagKind.OTHER),
 
     /** The tag of the error type.
      */
-    ERROR,
+    ERROR(TypeTagKind.REFERENCE | TypeTagKind.PARTIAL),
 
     /** The tag of an unknown type
      */
-    UNKNOWN,
+    UNKNOWN(TypeTagKind.PARTIAL),
 
     /** The tag of all instantiatable type variables.
      */
-    UNDETVAR,
+    UNDETVAR(TypeTagKind.PARTIAL),
 
     /** Pseudo-types, these are special tags
      */
-    UNINITIALIZED_THIS,
+    UNINITIALIZED_THIS(TypeTagKind.OTHER),
+
+    UNINITIALIZED_OBJECT(TypeTagKind.OTHER);
 
-    UNINITIALIZED_OBJECT;
+    final boolean isPrimitive;
+    final boolean isNumeric;
+    final boolean isPartial;
+    final boolean isReference;
+    final boolean isPrimitiveOrVoid;
+    final int superClasses;
+    final int numericClass;
+
+    private TypeTag(int kind) {
+        this(0, 0, kind);
+    }
 
-    /** This field will only be used for tags related with numeric types for
-     *  optimization reasons.
-     */
-    private final int order;
+    private TypeTag(int numericClass, int superClasses, int kind) {
+         isPrimitive = (kind & TypeTagKind.PRIMITIVE) != 0;
+         isNumeric = (kind & TypeTagKind.NUMERIC) != 0;
+         isPartial = (kind & TypeTagKind.PARTIAL) != 0;
+         isReference = (kind & TypeTagKind.REFERENCE) != 0;
+         isPrimitiveOrVoid = ((kind & TypeTagKind.PRIMITIVE) != 0) ||
+                 ((kind & TypeTagKind.VOID) != 0);
+         this.superClasses = superClasses;
+         this.numericClass = numericClass;
+     }
 
-    private TypeTag() {
-        this(0);
+    static class TypeTagKind {
+        static final int PRIMITIVE = 1;
+        static final int NUMERIC = 2;
+        static final int REFERENCE = 4;
+        static final int PARTIAL = 8;
+        static final int OTHER = 16;
+        static final int VOID = 32;
     }
 
-    private TypeTag(int order) {
-        this.order = order;
+    public static class NumericClasses {
+        public static final int BYTE_CLASS = 1;
+        public static final int CHAR_CLASS = 2;
+        public static final int SHORT_CLASS = 4;
+        public static final int INT_CLASS = 8;
+        public static final int LONG_CLASS = 16;
+        public static final int FLOAT_CLASS = 32;
+        public static final int DOUBLE_CLASS = 64;
+
+        static final int BYTE_SUPERCLASSES = BYTE_CLASS | SHORT_CLASS | INT_CLASS |
+                LONG_CLASS | FLOAT_CLASS | DOUBLE_CLASS;
+
+        static final int CHAR_SUPERCLASSES = CHAR_CLASS | INT_CLASS |
+                LONG_CLASS | FLOAT_CLASS | DOUBLE_CLASS;
+
+        static final int SHORT_SUPERCLASSES = SHORT_CLASS | INT_CLASS |
+                LONG_CLASS | FLOAT_CLASS | DOUBLE_CLASS;
+
+        static final int INT_SUPERCLASSES = INT_CLASS | LONG_CLASS | FLOAT_CLASS | DOUBLE_CLASS;
+
+        static final int LONG_SUPERCLASSES = LONG_CLASS | FLOAT_CLASS | DOUBLE_CLASS;
+
+        static final int FLOAT_SUPERCLASSES = FLOAT_CLASS | DOUBLE_CLASS;
     }
 
-    private static final int MIN_NUMERIC_TAG_ORDER = 1;
-    private static final int MAX_NUMERIC_TAG_ORDER = 7;
+    public boolean isStrictSubRangeOf(TypeTag tag) {
+        /*  Please don't change the implementation of this method to call method
+         *  isSubRangeOf. Both methods are called from hotspot code, the current
+         *  implementation is better performance-wise than the commented modification.
+         */
+        return (this.superClasses & tag.numericClass) != 0 && this != tag;
+    }
+
+    public boolean isSubRangeOf(TypeTag tag) {
+        return (this.superClasses & tag.numericClass) != 0;
+    }
 
     /** Returns the number of type tags.
      */
@@ -155,29 +214,6 @@
         return (UNDETVAR.ordinal() + 1);
     }
 
-    public boolean isSubRangeOf(TypeTag range) {
-        return (this == range) || isStrictSubRangeOf(range);
-    }
-
-    public boolean isStrictSubRangeOf(TypeTag range) {
-        if (this.order >= MIN_NUMERIC_TAG_ORDER && this.order <= MAX_NUMERIC_TAG_ORDER &&
-            range.order >= MIN_NUMERIC_TAG_ORDER && this.order <= MAX_NUMERIC_TAG_ORDER) {
-            if (this == range)
-                return false;
-            switch (this) {
-                case BYTE:
-                    return true;
-                case CHAR: case SHORT: case INT:
-                case LONG: case FLOAT:
-                    return this.order < range.order && range.order <= MAX_NUMERIC_TAG_ORDER;
-                default:
-                    return false;
-            }
-        }
-        else
-            return false;
-    }
-
     public Kind getKindLiteral() {
         switch (this) {
         case INT:
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jun 18 18:57:52 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jun 18 19:02:48 2013 +0100
@@ -1532,21 +1532,23 @@
                 // If one arm has an integer subrange type (i.e., byte,
                 // short, or char), and the other is an integer constant
                 // that fits into the subrange, return the subrange type.
-                if (thenUnboxed.getTag().isStrictSubRangeOf(INT) && elseUnboxed.hasTag(INT) &&
-                    types.isAssignable(elseUnboxed, thenUnboxed))
+                if (thenUnboxed.getTag().isStrictSubRangeOf(INT) &&
+                    elseUnboxed.hasTag(INT) &&
+                    types.isAssignable(elseUnboxed, thenUnboxed)) {
                     return thenUnboxed.baseType();
-                if (elseUnboxed.getTag().isStrictSubRangeOf(INT) && thenUnboxed.hasTag(INT) &&
-                    types.isAssignable(thenUnboxed, elseUnboxed))
+                }
+                if (elseUnboxed.getTag().isStrictSubRangeOf(INT) &&
+                    thenUnboxed.hasTag(INT) &&
+                    types.isAssignable(thenUnboxed, elseUnboxed)) {
                     return elseUnboxed.baseType();
-
-                for (TypeTag tag : TypeTag.values()) {
-                    if (tag.ordinal() >= TypeTag.getTypeTagCount()) break;
+                }
+
+                for (TypeTag tag : primitiveTags) {
                     Type candidate = syms.typeOfTag[tag.ordinal()];
-                    if (candidate != null &&
-                        candidate.isPrimitive() &&
-                        types.isSubtype(thenUnboxed, candidate) &&
-                        types.isSubtype(elseUnboxed, candidate))
+                    if (types.isSubtype(thenUnboxed, candidate) &&
+                        types.isSubtype(elseUnboxed, candidate)) {
                         return candidate;
+                    }
                 }
             }
 
@@ -1575,6 +1577,17 @@
             return types.lub(thentype.baseType(), elsetype.baseType());
         }
 
+    final static TypeTag[] primitiveTags = new TypeTag[]{
+        BYTE,
+        CHAR,
+        SHORT,
+        INT,
+        LONG,
+        FLOAT,
+        DOUBLE,
+        BOOLEAN,
+    };
+
     public void visitIf(JCIf tree) {
         attribExpr(tree.cond, env, syms.booleanType);
         attribStat(tree.thenpart, env);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Jun 18 18:57:52 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Jun 18 19:02:48 2013 +0100
@@ -544,7 +544,7 @@
         if (checkContext.compatible(found, req, checkContext.checkWarner(pos, found, req))) {
             return found;
         } else {
-            if (found.getTag().isSubRangeOf(DOUBLE) && req.getTag().isSubRangeOf(DOUBLE)) {
+            if (found.isNumeric() && req.isNumeric()) {
                 checkContext.report(pos, diags.fragment("possible.loss.of.precision", found, req));
                 return types.createErrorType(found);
             }
@@ -754,7 +754,7 @@
      *  @param t             The type to be checked.
      */
     Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
-        if (t.isNullOrReference())
+        if (t.isReference() || t.hasTag(BOT))
             return t;
         else
             return typeTagError(pos,
@@ -3228,7 +3228,7 @@
     void checkDivZero(DiagnosticPosition pos, Symbol operator, Type operand) {
         if (operand.constValue() != null
             && lint.isEnabled(LintCategory.DIVZERO)
-            && (operand.getTag().isSubRangeOf(LONG))
+            && operand.getTag().isSubRangeOf(LONG)
             && ((Number) (operand.constValue())).longValue() == 0) {
             int opc = ((OperatorSymbol)operator).opcode;
             if (opc == ByteCodes.idiv || opc == ByteCodes.imod
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Tue Jun 18 18:57:52 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Tue Jun 18 19:02:48 2013 +0100
@@ -952,8 +952,9 @@
             Type solve(UndetVar uv, InferenceContext inferenceContext) {
                 Infer infer = inferenceContext.infer();
                 List<Type> lobounds = filterBounds(uv, inferenceContext);
-                Type owntype = infer.types.lub(lobounds);
-                if (owntype.hasTag(ERROR)) {
+                //note: lobounds should have at least one element
+                Type owntype = lobounds.tail.tail == null  ? lobounds.head : infer.types.lub(lobounds);
+                if (owntype.isPrimitive() || owntype.hasTag(ERROR)) {
                     throw infer.inferenceException
                         .setMessage("no.unique.minimal.instance.exists",
                                     uv.qtype, lobounds);
@@ -971,8 +972,9 @@
             Type solve(UndetVar uv, InferenceContext inferenceContext) {
                 Infer infer = inferenceContext.infer();
                 List<Type> hibounds = filterBounds(uv, inferenceContext);
-                Type owntype = infer.types.glb(hibounds);
-                if (owntype.isErroneous()) {
+                //note: lobounds should have at least one element
+                Type owntype = hibounds.tail.tail == null  ? hibounds.head : infer.types.glb(hibounds);
+                if (owntype.isPrimitive() || owntype.hasTag(ERROR)) {
                     throw infer.inferenceException
                         .setMessage("no.unique.maximal.instance.exists",
                                     uv.qtype, hibounds);
@@ -1100,10 +1102,11 @@
                             }
                         }
                         //no progress
-                        throw inferenceException;
+                        throw inferenceException.setMessage();
                     }
                 }
                 catch (InferenceException ex) {
+                    //did we fail because of interdependent ivars?
                     inferenceContext.rollback();
                     instantiateAsUninferredVars(varsToSolve, inferenceContext);
                     checkWithinBounds(inferenceContext, warn);