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 sun.misc.Unsafe;
34
35 import java.lang.invoke.MethodHandles.Lookup;
36 import java.security.AccessController;
37 import java.security.PrivilegedAction;
38 import java.util.*;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.ConcurrentMap;
41 import java.util.function.Function;
42
43 import static jdk.internal.org.objectweb.asm.Opcodes.*;
44
45 /**
46 * <p>Methods to facilitate the creation of String concatenation methods, that
47 * can be used to efficiently concatenate a known number of arguments of known
48 * types, possibly after type adaptation and partial evaluation of arguments.
49 * These methods are typically used as <em>bootstrap methods</em> for {@code
50 * invokedynamic} call sites, to support the <em>string concatenation</em>
51 * feature of the Java Programming Language.
52 *
53 * <p>Indirect access to the behavior specified by the provided {@code
1480 mh = MethodHandles.permuteArguments(mh, nmt, swap10(nmt.parameterCount()));
1481 }
1482
1483 // Fold in byte[] instantiation at argument 0.
1484 MethodHandle combiner = MethodHandles.dropArguments(NEW_ARRAY, 2, ptypesList);
1485 mh = MethodHandles.foldArguments(mh, combiner);
1486
1487 // Start combining length and coder mixers.
1488 //
1489 // Length is easy: constant lengths can be computed on the spot, and all non-constant
1490 // shapes have been either converted to Strings, or explicit methods for getting the
1491 // string length out of primitives are provided.
1492 //
1493 // Coders are more interesting. Only Object, String and char arguments (and constants)
1494 // can have non-Latin1 encoding. It is easier to blindly convert constants to String,
1495 // and deduce the coder from there. Arguments would be either converted to Strings
1496 // during the initial filtering, or handled by primitive specializations in CODER_MIXERS.
1497 //
1498 // The method handle shape after all length and coder mixers is:
1499 // (int, byte, <args>)String = ("index", "coder", <args>)
1500 byte initialCoder = 0; // initial coder
1501 int initialLen = 0; // initial length, in characters
1502 for (RecipeElement el : recipe.getElements()) {
1503 switch (el.getTag()) {
1504 case CONST: {
1505 Object constant = el.getValue();
1506 String s = constant.toString();
1507 initialCoder = (byte) coderMixer(String.class).invoke(initialCoder, s);
1508 initialLen += s.length();
1509 break;
1510 }
1511 case ARG: {
1512 int ac = el.getArgPos();
1513
1514 Class<?> argClass = ptypesList.get(ac);
1515 MethodHandle lm = selectArgument(lengthMixer(argClass), 1, ptypesList, ac);
1516 lm = MethodHandles.dropArguments(lm, 0, byte.class); // (*)
1517 lm = MethodHandles.dropArguments(lm, 2, byte.class);
1518
1519 MethodHandle cm = selectArgument(coderMixer(argClass), 1, ptypesList, ac);
1520 cm = MethodHandles.dropArguments(cm, 0, int.class); // (**)
1613 public MethodHandle apply(Class<?> c) {
1614 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixCoder", byte.class, byte.class, c);
1615 }
1616 };
1617
1618 // This one is deliberately non-lambdified to optimize startup time:
1619 private static final Function<Class<?>, MethodHandle> LENGTH_MIX = new Function<Class<?>, MethodHandle>() {
1620 @Override
1621 public MethodHandle apply(Class<?> c) {
1622 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixLen", int.class, int.class, c);
1623 }
1624 };
1625
1626 private static final MethodHandle NEW_STRING;
1627 private static final MethodHandle CHECK_INDEX;
1628 private static final MethodHandle NEW_ARRAY;
1629 private static final ConcurrentMap<Class<?>, MethodHandle> PREPENDERS;
1630 private static final ConcurrentMap<Class<?>, MethodHandle> LENGTH_MIXERS;
1631 private static final ConcurrentMap<Class<?>, MethodHandle> CODER_MIXERS;
1632 private static final Class<?> STRING_HELPER;
1633
1634 static {
1635 try {
1636 STRING_HELPER = Class.forName("java.lang.StringConcatHelper");
1637 } catch (ClassNotFoundException e) {
1638 throw new AssertionError(e);
1639 }
1640
1641 PREPENDERS = new ConcurrentHashMap<>();
1642 LENGTH_MIXERS = new ConcurrentHashMap<>();
1643 CODER_MIXERS = new ConcurrentHashMap<>();
1644
1645 NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, byte.class);
1646 NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, int.class, byte.class);
1647
1648 if (DEBUG) {
1649 CHECK_INDEX = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "checkIndex", int.class, int.class);
1650 } else {
1651 CHECK_INDEX = null;
1652 }
1653 }
1654 }
1655
1656 /**
1657 * Public gateways to public "stringify" methods. These methods have the form String apply(T obj), and normally
|
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.security.AccessController;
37 import java.security.PrivilegedAction;
38 import java.util.*;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.ConcurrentMap;
41 import java.util.function.Function;
42
43 import static jdk.internal.org.objectweb.asm.Opcodes.*;
44
45 /**
46 * <p>Methods to facilitate the creation of String concatenation methods, that
47 * can be used to efficiently concatenate a known number of arguments of known
48 * types, possibly after type adaptation and partial evaluation of arguments.
49 * These methods are typically used as <em>bootstrap methods</em> for {@code
50 * invokedynamic} call sites, to support the <em>string concatenation</em>
51 * feature of the Java Programming Language.
52 *
53 * <p>Indirect access to the behavior specified by the provided {@code
1480 mh = MethodHandles.permuteArguments(mh, nmt, swap10(nmt.parameterCount()));
1481 }
1482
1483 // Fold in byte[] instantiation at argument 0.
1484 MethodHandle combiner = MethodHandles.dropArguments(NEW_ARRAY, 2, ptypesList);
1485 mh = MethodHandles.foldArguments(mh, combiner);
1486
1487 // Start combining length and coder mixers.
1488 //
1489 // Length is easy: constant lengths can be computed on the spot, and all non-constant
1490 // shapes have been either converted to Strings, or explicit methods for getting the
1491 // string length out of primitives are provided.
1492 //
1493 // Coders are more interesting. Only Object, String and char arguments (and constants)
1494 // can have non-Latin1 encoding. It is easier to blindly convert constants to String,
1495 // and deduce the coder from there. Arguments would be either converted to Strings
1496 // during the initial filtering, or handled by primitive specializations in CODER_MIXERS.
1497 //
1498 // The method handle shape after all length and coder mixers is:
1499 // (int, byte, <args>)String = ("index", "coder", <args>)
1500 byte initialCoder = INITIAL_CODER;
1501 int initialLen = 0; // initial length, in characters
1502 for (RecipeElement el : recipe.getElements()) {
1503 switch (el.getTag()) {
1504 case CONST: {
1505 Object constant = el.getValue();
1506 String s = constant.toString();
1507 initialCoder = (byte) coderMixer(String.class).invoke(initialCoder, s);
1508 initialLen += s.length();
1509 break;
1510 }
1511 case ARG: {
1512 int ac = el.getArgPos();
1513
1514 Class<?> argClass = ptypesList.get(ac);
1515 MethodHandle lm = selectArgument(lengthMixer(argClass), 1, ptypesList, ac);
1516 lm = MethodHandles.dropArguments(lm, 0, byte.class); // (*)
1517 lm = MethodHandles.dropArguments(lm, 2, byte.class);
1518
1519 MethodHandle cm = selectArgument(coderMixer(argClass), 1, ptypesList, ac);
1520 cm = MethodHandles.dropArguments(cm, 0, int.class); // (**)
1613 public MethodHandle apply(Class<?> c) {
1614 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixCoder", byte.class, byte.class, c);
1615 }
1616 };
1617
1618 // This one is deliberately non-lambdified to optimize startup time:
1619 private static final Function<Class<?>, MethodHandle> LENGTH_MIX = new Function<Class<?>, MethodHandle>() {
1620 @Override
1621 public MethodHandle apply(Class<?> c) {
1622 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixLen", int.class, int.class, c);
1623 }
1624 };
1625
1626 private static final MethodHandle NEW_STRING;
1627 private static final MethodHandle CHECK_INDEX;
1628 private static final MethodHandle NEW_ARRAY;
1629 private static final ConcurrentMap<Class<?>, MethodHandle> PREPENDERS;
1630 private static final ConcurrentMap<Class<?>, MethodHandle> LENGTH_MIXERS;
1631 private static final ConcurrentMap<Class<?>, MethodHandle> CODER_MIXERS;
1632 private static final Class<?> STRING_HELPER;
1633 private static final byte INITIAL_CODER;
1634
1635 static {
1636 try {
1637 STRING_HELPER = Class.forName("java.lang.StringConcatHelper");
1638 MethodHandle initCoder = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "initialCoder", byte.class);
1639 INITIAL_CODER = (byte) initCoder.invoke();
1640 } catch (Throwable e) {
1641 throw new AssertionError(e);
1642 }
1643
1644 PREPENDERS = new ConcurrentHashMap<>();
1645 LENGTH_MIXERS = new ConcurrentHashMap<>();
1646 CODER_MIXERS = new ConcurrentHashMap<>();
1647
1648 NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, byte.class);
1649 NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, int.class, byte.class);
1650
1651 if (DEBUG) {
1652 CHECK_INDEX = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "checkIndex", int.class, int.class);
1653 } else {
1654 CHECK_INDEX = null;
1655 }
1656 }
1657 }
1658
1659 /**
1660 * Public gateways to public "stringify" methods. These methods have the form String apply(T obj), and normally
|