8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.org.objectweb.asm.ClassWriter;
29 import jdk.internal.org.objectweb.asm.Label;
30 import jdk.internal.org.objectweb.asm.MethodVisitor;
31 import jdk.internal.org.objectweb.asm.Opcodes;
32 import jdk.internal.vm.annotation.ForceInline;
33 import jdk.internal.misc.Unsafe;
34
35 import java.lang.invoke.MethodHandles.Lookup;
36 import java.util.*;
37 import java.util.concurrent.ConcurrentHashMap;
38 import java.util.concurrent.ConcurrentMap;
39 import java.util.function.Function;
40 import sun.security.action.GetPropertyAction;
41
42 import static jdk.internal.org.objectweb.asm.Opcodes.*;
43
44 /**
45 * <p>Methods to facilitate the creation of String concatenation methods, that
46 * can be used to efficiently concatenate a known number of arguments of known
47 * types, possibly after type adaptation and partial evaluation of arguments.
48 * These methods are typically used as <em>bootstrap methods</em> for {@code
49 * invokedynamic} call sites, to support the <em>string concatenation</em>
50 * feature of the Java Programming Language.
51 *
52 * <p>Indirect access to the behavior specified by the provided {@code
53 * MethodHandle} proceeds in order through two phases:
54 *
55 * <ol>
56 * <li><em>Linkage</em> occurs when the methods in this class are invoked.
57 * They take as arguments a method type describing the concatenated arguments
58 * count and types, and optionally the String <em>recipe</em>, plus the
59 * constants that participate in the String concatenation. The details on
60 * accepted recipe shapes are described further below. Linkage may involve
907
908 // Prepare StringBuilder instance
909 mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
910 mv.visitInsn(DUP);
911
912 if (mode.isSized()) {
913 /*
914 Sized mode requires us to walk through the arguments, and estimate the final length.
915 In exact mode, this will operate on Strings only. This code would accumulate the
916 final length on stack.
917 */
918 int len = 0;
919 int off = 0;
920
921 mv.visitInsn(ICONST_0);
922
923 for (RecipeElement el : recipe.getElements()) {
924 switch (el.getTag()) {
925 case TAG_CONST:
926 Object cnst = el.getValue();
927 len += cnst.toString().length();
928 break;
929 case TAG_ARG:
930 /*
931 If an argument is String, then we can call .length() on it. Sized/Exact modes have
932 converted arguments for us. If an argument is primitive, we can provide a guess
933 for its String representation size.
934 */
935 Class<?> cl = arr[el.getArgPos()];
936 if (cl == String.class) {
937 mv.visitIntInsn(ALOAD, off);
938 mv.visitMethodInsn(
939 INVOKEVIRTUAL,
940 "java/lang/String",
941 "length",
942 "()I",
943 false
944 );
945 mv.visitInsn(IADD);
946 } else if (cl.isPrimitive()) {
967 false
968 );
969 } else {
970 mv.visitMethodInsn(
971 INVOKESPECIAL,
972 "java/lang/StringBuilder",
973 "<init>",
974 "()V",
975 false
976 );
977 }
978
979 // At this point, we have a blank StringBuilder on stack, fill it in with .append calls.
980 {
981 int off = 0;
982 for (RecipeElement el : recipe.getElements()) {
983 String desc;
984 switch (el.getTag()) {
985 case TAG_CONST:
986 Object cnst = el.getValue();
987 mv.visitLdcInsn(cnst);
988 desc = getSBAppendDesc(cnst.getClass());
989 break;
990 case TAG_ARG:
991 Class<?> cl = arr[el.getArgPos()];
992 mv.visitVarInsn(getLoadOpcode(cl), off);
993 off += getParameterSize(cl);
994 desc = getSBAppendDesc(cl);
995 break;
996 default:
997 throw new StringConcatException("Unhandled tag: " + el.getTag());
998 }
999
1000 mv.visitMethodInsn(
1001 INVOKEVIRTUAL,
1002 "java/lang/StringBuilder",
1003 "append",
1004 desc,
1005 false
1006 );
1007 }
1008 }
1604 private static byte[] newArray(int length, byte coder) {
1605 return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, length << coder);
1606 }
1607
1608 private static MethodHandle prepender(Class<?> cl) {
1609 return PREPENDERS.computeIfAbsent(cl, PREPEND);
1610 }
1611
1612 private static MethodHandle coderMixer(Class<?> cl) {
1613 return CODER_MIXERS.computeIfAbsent(cl, CODER_MIX);
1614 }
1615
1616 private static MethodHandle lengthMixer(Class<?> cl) {
1617 return LENGTH_MIXERS.computeIfAbsent(cl, LENGTH_MIX);
1618 }
1619
1620 // This one is deliberately non-lambdified to optimize startup time:
1621 private static final Function<Class<?>, MethodHandle> PREPEND = new Function<Class<?>, MethodHandle>() {
1622 @Override
1623 public MethodHandle apply(Class<?> c) {
1624 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", int.class, int.class, byte[].class, byte.class, c);
1625 }
1626 };
1627
1628 // This one is deliberately non-lambdified to optimize startup time:
1629 private static final Function<Class<?>, MethodHandle> CODER_MIX = new Function<Class<?>, MethodHandle>() {
1630 @Override
1631 public MethodHandle apply(Class<?> c) {
1632 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixCoder", byte.class, byte.class, c);
1633 }
1634 };
1635
1636 // This one is deliberately non-lambdified to optimize startup time:
1637 private static final Function<Class<?>, MethodHandle> LENGTH_MIX = new Function<Class<?>, MethodHandle>() {
1638 @Override
1639 public MethodHandle apply(Class<?> c) {
1640 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixLen", int.class, int.class, c);
1641 }
1642 };
1643
1644 private static final MethodHandle NEW_STRING;
1645 private static final MethodHandle NEW_ARRAY;
1646 private static final ConcurrentMap<Class<?>, MethodHandle> PREPENDERS;
1647 private static final ConcurrentMap<Class<?>, MethodHandle> LENGTH_MIXERS;
1648 private static final ConcurrentMap<Class<?>, MethodHandle> CODER_MIXERS;
1649 private static final byte INITIAL_CODER;
1650 static final Class<?> STRING_HELPER;
1651
1652 static {
1653 try {
1654 STRING_HELPER = Class.forName("java.lang.StringConcatHelper");
1655 MethodHandle initCoder = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "initialCoder", byte.class);
1656 INITIAL_CODER = (byte) initCoder.invoke();
1657 } catch (Throwable e) {
1658 throw new AssertionError(e);
1659 }
1660
|
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.misc.Unsafe;
29 import jdk.internal.org.objectweb.asm.ClassWriter;
30 import jdk.internal.org.objectweb.asm.Label;
31 import jdk.internal.org.objectweb.asm.MethodVisitor;
32 import jdk.internal.org.objectweb.asm.Opcodes;
33 import jdk.internal.vm.annotation.ForceInline;
34 import sun.invoke.util.Wrapper;
35 import sun.security.action.GetPropertyAction;
36
37 import java.lang.invoke.MethodHandles.Lookup;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 import java.util.Objects;
42 import java.util.Properties;
43 import java.util.concurrent.ConcurrentHashMap;
44 import java.util.concurrent.ConcurrentMap;
45 import java.util.function.Function;
46
47 import static jdk.internal.org.objectweb.asm.Opcodes.*;
48
49 /**
50 * <p>Methods to facilitate the creation of String concatenation methods, that
51 * can be used to efficiently concatenate a known number of arguments of known
52 * types, possibly after type adaptation and partial evaluation of arguments.
53 * These methods are typically used as <em>bootstrap methods</em> for {@code
54 * invokedynamic} call sites, to support the <em>string concatenation</em>
55 * feature of the Java Programming Language.
56 *
57 * <p>Indirect access to the behavior specified by the provided {@code
58 * MethodHandle} proceeds in order through two phases:
59 *
60 * <ol>
61 * <li><em>Linkage</em> occurs when the methods in this class are invoked.
62 * They take as arguments a method type describing the concatenated arguments
63 * count and types, and optionally the String <em>recipe</em>, plus the
64 * constants that participate in the String concatenation. The details on
65 * accepted recipe shapes are described further below. Linkage may involve
912
913 // Prepare StringBuilder instance
914 mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
915 mv.visitInsn(DUP);
916
917 if (mode.isSized()) {
918 /*
919 Sized mode requires us to walk through the arguments, and estimate the final length.
920 In exact mode, this will operate on Strings only. This code would accumulate the
921 final length on stack.
922 */
923 int len = 0;
924 int off = 0;
925
926 mv.visitInsn(ICONST_0);
927
928 for (RecipeElement el : recipe.getElements()) {
929 switch (el.getTag()) {
930 case TAG_CONST:
931 Object cnst = el.getValue();
932 String s = (cnst != null) ? cnst.toString() : "null";
933 len += cnst.toString().length();
934 break;
935 case TAG_ARG:
936 /*
937 If an argument is String, then we can call .length() on it. Sized/Exact modes have
938 converted arguments for us. If an argument is primitive, we can provide a guess
939 for its String representation size.
940 */
941 Class<?> cl = arr[el.getArgPos()];
942 if (cl == String.class) {
943 mv.visitIntInsn(ALOAD, off);
944 mv.visitMethodInsn(
945 INVOKEVIRTUAL,
946 "java/lang/String",
947 "length",
948 "()I",
949 false
950 );
951 mv.visitInsn(IADD);
952 } else if (cl.isPrimitive()) {
973 false
974 );
975 } else {
976 mv.visitMethodInsn(
977 INVOKESPECIAL,
978 "java/lang/StringBuilder",
979 "<init>",
980 "()V",
981 false
982 );
983 }
984
985 // At this point, we have a blank StringBuilder on stack, fill it in with .append calls.
986 {
987 int off = 0;
988 for (RecipeElement el : recipe.getElements()) {
989 String desc;
990 switch (el.getTag()) {
991 case TAG_CONST:
992 Object cnst = el.getValue();
993 String s = (cnst != null) ? cnst.toString() : "null";
994 mv.visitLdcInsn(s);
995 desc = getSBAppendDesc(String.class);
996 break;
997 case TAG_ARG:
998 Class<?> cl = arr[el.getArgPos()];
999 mv.visitVarInsn(getLoadOpcode(cl), off);
1000 off += getParameterSize(cl);
1001 desc = getSBAppendDesc(cl);
1002 break;
1003 default:
1004 throw new StringConcatException("Unhandled tag: " + el.getTag());
1005 }
1006
1007 mv.visitMethodInsn(
1008 INVOKEVIRTUAL,
1009 "java/lang/StringBuilder",
1010 "append",
1011 desc,
1012 false
1013 );
1014 }
1015 }
1611 private static byte[] newArray(int length, byte coder) {
1612 return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, length << coder);
1613 }
1614
1615 private static MethodHandle prepender(Class<?> cl) {
1616 return PREPENDERS.computeIfAbsent(cl, PREPEND);
1617 }
1618
1619 private static MethodHandle coderMixer(Class<?> cl) {
1620 return CODER_MIXERS.computeIfAbsent(cl, CODER_MIX);
1621 }
1622
1623 private static MethodHandle lengthMixer(Class<?> cl) {
1624 return LENGTH_MIXERS.computeIfAbsent(cl, LENGTH_MIX);
1625 }
1626
1627 // This one is deliberately non-lambdified to optimize startup time:
1628 private static final Function<Class<?>, MethodHandle> PREPEND = new Function<Class<?>, MethodHandle>() {
1629 @Override
1630 public MethodHandle apply(Class<?> c) {
1631 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", int.class, int.class, byte[].class, byte.class,
1632 Wrapper.asPrimitiveType(c));
1633 }
1634 };
1635
1636 // This one is deliberately non-lambdified to optimize startup time:
1637 private static final Function<Class<?>, MethodHandle> CODER_MIX = new Function<Class<?>, MethodHandle>() {
1638 @Override
1639 public MethodHandle apply(Class<?> c) {
1640 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixCoder", byte.class, byte.class,
1641 Wrapper.asPrimitiveType(c));
1642 }
1643 };
1644
1645 // This one is deliberately non-lambdified to optimize startup time:
1646 private static final Function<Class<?>, MethodHandle> LENGTH_MIX = new Function<Class<?>, MethodHandle>() {
1647 @Override
1648 public MethodHandle apply(Class<?> c) {
1649 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixLen", int.class, int.class,
1650 Wrapper.asPrimitiveType(c));
1651 }
1652 };
1653
1654 private static final MethodHandle NEW_STRING;
1655 private static final MethodHandle NEW_ARRAY;
1656 private static final ConcurrentMap<Class<?>, MethodHandle> PREPENDERS;
1657 private static final ConcurrentMap<Class<?>, MethodHandle> LENGTH_MIXERS;
1658 private static final ConcurrentMap<Class<?>, MethodHandle> CODER_MIXERS;
1659 private static final byte INITIAL_CODER;
1660 static final Class<?> STRING_HELPER;
1661
1662 static {
1663 try {
1664 STRING_HELPER = Class.forName("java.lang.StringConcatHelper");
1665 MethodHandle initCoder = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "initialCoder", byte.class);
1666 INITIAL_CODER = (byte) initCoder.invoke();
1667 } catch (Throwable e) {
1668 throw new AssertionError(e);
1669 }
1670
|