< prev index next >

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

Print this page




  37 import sun.invoke.empty.Empty;
  38 import sun.invoke.util.ValueConversions;
  39 import sun.invoke.util.VerifyType;
  40 import sun.invoke.util.Wrapper;
  41 
  42 import java.lang.invoke.MethodHandles.Lookup;
  43 import java.lang.reflect.Array;
  44 import java.nio.ByteOrder;
  45 import java.util.Arrays;
  46 import java.util.Collections;
  47 import java.util.HashMap;
  48 import java.util.Iterator;
  49 import java.util.List;
  50 import java.util.Map;
  51 import java.util.function.Function;
  52 import java.util.stream.Stream;
  53 
  54 import static java.lang.invoke.LambdaForm.*;
  55 import static java.lang.invoke.MethodHandleStatics.*;
  56 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
  57 import static java.lang.invoke.MethodHandleNatives.Constants.HIDDEN_CLASS;
  58 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  59 
  60 /**
  61  * Trusted implementation code for MethodHandle.
  62  * @author jrose
  63  */
  64 /*non-public*/
  65 abstract class MethodHandleImpl {
  66 
  67     /// Factory methods to create method handles:
  68 
  69     static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, ArrayAccess access) {
  70         if (arrayClass == Object[].class) {
  71             return ArrayAccess.objectAccessor(access);
  72         }
  73         if (!arrayClass.isArray())
  74             throw newIllegalArgumentException("not an array: "+arrayClass);
  75         MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass);
  76         int cacheIndex = ArrayAccess.cacheIndex(access);
  77         MethodHandle mh = cache[cacheIndex];


1156             // Cache the result of makeInjectedInvoker once per argument class.
1157             MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
1158             return restoreToType(bccInvoker.bindTo(vamh), mh, hostClass);
1159         }
1160 
1161         private static MethodHandle makeInjectedInvoker(Class<?> targetClass) {
1162             try {
1163                 /*
1164                  * The invoker class defined to the same class loader as the lookup class
1165                  * but in an unnamed package so that the class bytes can be cached and
1166                  * reused for any @CSM.
1167                  *
1168                  * @CSM must be public and exported if called by any module.
1169                  */
1170                 String name = targetClass.getName() + "$$InjectedInvoker";
1171                 if (targetClass.isHiddenClass()) {
1172                     // use the original class name
1173                     name = name.replace('/', '_');
1174                 }
1175                 Class<?> invokerClass = new Lookup(targetClass)
1176                         .makeHiddenClassDefiner(name, INJECTED_INVOKER_TEMPLATE, 0).defineClass(true);

1177                 assert checkInjectedInvoker(targetClass, invokerClass);
1178                 return IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
1179             } catch (ReflectiveOperationException ex) {
1180                 throw uncaughtException(ex);
1181             }
1182         }
1183 
1184         private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() {
1185             @Override protected MethodHandle computeValue(Class<?> hostClass) {
1186                 return makeInjectedInvoker(hostClass);
1187             }
1188         };
1189 
1190         // Adapt mh so that it can be called directly from an injected invoker:
1191         private static MethodHandle prepareForInvoker(MethodHandle mh) {
1192             mh = mh.asFixedArity();
1193             MethodType mt = mh.type();
1194             int arity = mt.parameterCount();
1195             MethodHandle vamh = mh.asType(mt.generic());
1196             vamh.internalForm().compileToBytecode();  // eliminate LFI stack frames




  37 import sun.invoke.empty.Empty;
  38 import sun.invoke.util.ValueConversions;
  39 import sun.invoke.util.VerifyType;
  40 import sun.invoke.util.Wrapper;
  41 
  42 import java.lang.invoke.MethodHandles.Lookup;
  43 import java.lang.reflect.Array;
  44 import java.nio.ByteOrder;
  45 import java.util.Arrays;
  46 import java.util.Collections;
  47 import java.util.HashMap;
  48 import java.util.Iterator;
  49 import java.util.List;
  50 import java.util.Map;
  51 import java.util.function.Function;
  52 import java.util.stream.Stream;
  53 
  54 import static java.lang.invoke.LambdaForm.*;
  55 import static java.lang.invoke.MethodHandleStatics.*;
  56 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;

  57 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  58 
  59 /**
  60  * Trusted implementation code for MethodHandle.
  61  * @author jrose
  62  */
  63 /*non-public*/
  64 abstract class MethodHandleImpl {
  65 
  66     /// Factory methods to create method handles:
  67 
  68     static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, ArrayAccess access) {
  69         if (arrayClass == Object[].class) {
  70             return ArrayAccess.objectAccessor(access);
  71         }
  72         if (!arrayClass.isArray())
  73             throw newIllegalArgumentException("not an array: "+arrayClass);
  74         MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass);
  75         int cacheIndex = ArrayAccess.cacheIndex(access);
  76         MethodHandle mh = cache[cacheIndex];


1155             // Cache the result of makeInjectedInvoker once per argument class.
1156             MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
1157             return restoreToType(bccInvoker.bindTo(vamh), mh, hostClass);
1158         }
1159 
1160         private static MethodHandle makeInjectedInvoker(Class<?> targetClass) {
1161             try {
1162                 /*
1163                  * The invoker class defined to the same class loader as the lookup class
1164                  * but in an unnamed package so that the class bytes can be cached and
1165                  * reused for any @CSM.
1166                  *
1167                  * @CSM must be public and exported if called by any module.
1168                  */
1169                 String name = targetClass.getName() + "$$InjectedInvoker";
1170                 if (targetClass.isHiddenClass()) {
1171                     // use the original class name
1172                     name = name.replace('/', '_');
1173                 }
1174                 Class<?> invokerClass = new Lookup(targetClass)
1175                         .makeHiddenClassDefiner(name, INJECTED_INVOKER_TEMPLATE)
1176                         .defineClass(true);
1177                 assert checkInjectedInvoker(targetClass, invokerClass);
1178                 return IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
1179             } catch (ReflectiveOperationException ex) {
1180                 throw uncaughtException(ex);
1181             }
1182         }
1183 
1184         private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() {
1185             @Override protected MethodHandle computeValue(Class<?> hostClass) {
1186                 return makeInjectedInvoker(hostClass);
1187             }
1188         };
1189 
1190         // Adapt mh so that it can be called directly from an injected invoker:
1191         private static MethodHandle prepareForInvoker(MethodHandle mh) {
1192             mh = mh.asFixedArity();
1193             MethodType mt = mh.type();
1194             int arity = mt.parameterCount();
1195             MethodHandle vamh = mh.asType(mt.generic());
1196             vamh.internalForm().compileToBytecode();  // eliminate LFI stack frames


< prev index next >