< prev index next >

src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java

Print this page
rev 15320 : 8163370: Reduce number of classes loaded by common usage of java.lang.invoke
Reviewed-by: igerasim, psandoz

@@ -279,12 +279,11 @@
                         acc.setLength(0);
                     }
                     if (c == TAG_CONST) {
                         Object cnst = constants[constC++];
                         el.add(new RecipeElement(cnst));
-                    }
-                    if (c == TAG_ARG) {
+                    } else if (c == TAG_ARG) {
                         el.add(new RecipeElement(argC++));
                     }
                 } else {
                     // Not a special characters, this is a constant embedded into
                     // the recipe itself.

@@ -320,59 +319,54 @@
     }
 
     private static final class RecipeElement {
         private final Object value;
         private final int argPos;
-        private final Tag tag;
 
         public RecipeElement(Object cnst) {
             this.value = Objects.requireNonNull(cnst);
             this.argPos = -1;
-            this.tag = Tag.CONST;
         }
 
         public RecipeElement(int arg) {
             this.value = null;
+            assert (arg >= 0);
             this.argPos = arg;
-            this.tag = Tag.ARG;
         }
 
         public Object getValue() {
-            assert (tag == Tag.CONST);
+            assert (isConst());
             return value;
         }
 
         public int getArgPos() {
-            assert (tag == Tag.ARG);
+            assert (!isConst());
             return argPos;
         }
 
-        public Tag getTag() {
-            return tag;
+        public boolean isConst() {
+            return argPos == -1;
         }
 
         @Override
         public boolean equals(Object o) {
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
 
             RecipeElement that = (RecipeElement) o;
 
-            if (tag != that.tag) return false;
-            if (tag == Tag.CONST && (!value.equals(that.value))) return false;
-            if (tag == Tag.ARG && (argPos != that.argPos)) return false;
+            boolean isConst = isConst();
+            if (isConst != that.isConst()) return false;
+            if (isConst && (!value.equals(that.value))) return false;
+            if (!isConst && (argPos != that.argPos)) return false;
             return true;
         }
 
         @Override
         public int hashCode() {
-            return tag.hashCode();
-        }
+            return argPos;
     }
-
-    private enum Tag {
-        CONST, ARG
     }
 
     /**
      * Facilitates the creation of optimized String concatenation methods, that
      * can be used to efficiently concatenate a known number of arguments of

@@ -878,16 +872,13 @@
                     need to do null-checks early, not make the append chain shape simpler.
                  */
 
                 int off = 0;
                 for (RecipeElement el : recipe.getElements()) {
-                    switch (el.getTag()) {
-                        case CONST: {
+                    if (el.isConst()) {
                             // Guaranteed non-null, no null check required.
-                            break;
-                        }
-                        case ARG: {
+                    } else {
                             // Null-checks are needed only for String arguments, and when a previous stage
                             // did not do implicit null-checks. If a String is null, we eagerly replace it
                             // with "null" constant. Note, we omit Objects here, because we don't call
                             // .length() on them down below.
                             int ac = el.getArgPos();

@@ -899,14 +890,10 @@
                                 mv.visitLdcInsn("null");
                                 mv.visitIntInsn(ASTORE, off);
                                 mv.visitLabel(l0);
                             }
                             off += getParameterSize(cl);
-                            break;
-                        }
-                        default:
-                            throw new StringConcatException("Unhandled tag: " + el.getTag());
                     }
                 }
             }
 
             // Prepare StringBuilder instance

@@ -923,17 +910,14 @@
                 int off = 0;
 
                 mv.visitInsn(ICONST_0);
 
                 for (RecipeElement el : recipe.getElements()) {
-                    switch (el.getTag()) {
-                        case CONST: {
+                    if (el.isConst()) {
                             Object cnst = el.getValue();
                             len += cnst.toString().length();
-                            break;
-                        }
-                        case ARG: {
+                    } else {
                             /*
                                 If an argument is String, then we can call .length() on it. Sized/Exact modes have
                                 converted arguments for us. If an argument is primitive, we can provide a guess
                                 for its String representation size.
                             */

@@ -950,14 +934,10 @@
                                 mv.visitInsn(IADD);
                             } else if (cl.isPrimitive()) {
                                 len += estimateSize(cl);
                             }
                             off += getParameterSize(cl);
-                            break;
-                        }
-                        default:
-                            throw new StringConcatException("Unhandled tag: " + el.getTag());
                     }
                 }
 
                 // Constants have non-zero length, mix in
                 if (len > 0) {

@@ -985,27 +965,21 @@
             // At this point, we have a blank StringBuilder on stack, fill it in with .append calls.
             {
                 int off = 0;
                 for (RecipeElement el : recipe.getElements()) {
                     String desc;
-                    switch (el.getTag()) {
-                        case CONST: {
+                    if (el.isConst()) {
                             Object cnst = el.getValue();
                             mv.visitLdcInsn(cnst);
                             desc = getSBAppendDesc(cnst.getClass());
-                            break;
-                        }
-                        case ARG: {
+                    } else {
                             Class<?> cl = arr[el.getArgPos()];
                             mv.visitVarInsn(getLoadOpcode(cl), off);
                             off += getParameterSize(cl);
                             desc = getSBAppendDesc(cl);
-                            break;
-                        }
-                        default:
-                            throw new StringConcatException("Unhandled tag: " + el.getTag());
                     }
+
                     mv.visitMethodInsn(
                             INVOKEVIRTUAL,
                             "java/lang/StringBuilder",
                             "append",
                             desc,

@@ -1277,30 +1251,23 @@
             // Figure out lengths: constants' lengths can be deduced on the spot.
             // All reference arguments were filtered to String in the combinators below, so we can
             // call the usual String.length(). Primitive values string sizes can be estimated.
             int initial = 0;
             for (RecipeElement el : recipe.getElements()) {
-                switch (el.getTag()) {
-                    case CONST: {
+                if (el.isConst()) {
                         Object cnst = el.getValue();
                         initial += cnst.toString().length();
-                        break;
-                    }
-                    case ARG: {
+                } else {
                         final int i = el.getArgPos();
                         Class<?> type = ptypesList.get(i);
                         if (type.isPrimitive()) {
                             MethodHandle est = MethodHandles.constant(int.class, estimateSize(type));
                             est = MethodHandles.dropArguments(est, 0, type);
                             lengthers[i] = est;
                         } else {
                             lengthers[i] = STRING_LENGTH;
                         }
-                        break;
-                    }
-                    default:
-                        throw new StringConcatException("Unhandled tag: " + el.getTag());
                 }
             }
 
             // Create (StringBuilder, <args>) shape for appending:
             MethodHandle builder = MethodHandles.dropArguments(MethodHandles.identity(StringBuilder.class), 1, ptypesList);

@@ -1309,30 +1276,23 @@
             // reverse as well.
             List<RecipeElement> elements = recipe.getElements();
             for (int i = elements.size() - 1; i >= 0; i--) {
                 RecipeElement el = elements.get(i);
                 MethodHandle appender;
-                switch (el.getTag()) {
-                    case CONST: {
+                if (el.isConst()) {
                         Object constant = el.getValue();
                         MethodHandle mh = appender(adaptToStringBuilder(constant.getClass()));
                         appender = MethodHandles.insertArguments(mh, 1, constant);
-                        break;
-                    }
-                    case ARG: {
+                } else {
                         int ac = el.getArgPos();
                         appender = appender(ptypesList.get(ac));
 
                         // Insert dummy arguments to match the prefix in the signature.
                         // The actual appender argument will be the ac-ith argument.
                         if (ac != 0) {
                             appender = MethodHandles.dropArguments(appender, 1, ptypesList.subList(0, ac));
                         }
-                        break;
-                    }
-                    default:
-                        throw new StringConcatException("Unhandled tag: " + el.getTag());
                 }
                 builder = MethodHandles.foldArguments(builder, appender);
             }
 
             // Build the sub-tree that adds the sizes and produces a StringBuilder:

@@ -1519,23 +1479,16 @@
             // Mix in prependers. This happens when (int, byte[], byte) = (index, storage, coder) is already
             // known from the combinators below. We are assembling the string backwards, so "index" is the
             // *ending* index.
             for (RecipeElement el : recipe.getElements()) {
                 MethodHandle prepender;
-                switch (el.getTag()) {
-                    case CONST: {
+                if (el.isConst()) {
                         Object cnst = el.getValue();
                         prepender = MethodHandles.insertArguments(prepender(cnst.getClass()), 3, cnst);
-                        break;
-                    }
-                    case ARG: {
+                } else {
                         int pos = el.getArgPos();
                         prepender = selectArgument(prepender(ptypesList.get(pos)), 3, ptypesList, pos);
-                        break;
-                    }
-                    default:
-                        throw new StringConcatException("Unhandled tag: " + el.getTag());
                 }
 
                 // Remove "old" index from arguments
                 mh = MethodHandles.dropArguments(mh, 1, int.class);
 

@@ -1571,19 +1524,16 @@
             // The method handle shape after all length and coder mixers is:
             //   (int, byte, <args>)String = ("index", "coder", <args>)
             byte initialCoder = INITIAL_CODER;
             int initialLen = 0;    // initial length, in characters
             for (RecipeElement el : recipe.getElements()) {
-                switch (el.getTag()) {
-                    case CONST: {
+                if (el.isConst()) {
                         Object constant = el.getValue();
                         String s = constant.toString();
                         initialCoder = (byte) coderMixer(String.class).invoke(initialCoder, s);
                         initialLen += s.length();
-                        break;
-                    }
-                    case ARG: {
+                } else {
                         int ac = el.getArgPos();
 
                         Class<?> argClass = ptypesList.get(ac);
                         MethodHandle lm = selectArgument(lengthMixer(argClass), 1, ptypesList, ac);
                         lm = MethodHandles.dropArguments(lm, 0, byte.class); // (*)

@@ -1604,14 +1554,10 @@
                         // 2. Compute "new-coder", producing ("new-coder", "old-index", "old-coder", <args>)
                         //    Coder mixer ignores the "old-index" arg due to dropArguments above (**)
                         mh = MethodHandles.foldArguments(mh, cm);
 
                         // 1. The mh shape here is ("old-index", "old-coder", <args>)
-                        break;
-                    }
-                    default:
-                        throw new StringConcatException("Unhandled tag: " + el.getTag());
                 }
             }
 
             // Insert initial lengths and coders here.
             // The method handle shape here is (<args>).
< prev index next >