static { try { MethodHandles.Lookup lookup = MethodHandles.lookup(); BIND_CALL_SITE = lookup.findStatic( InvokeDynamicSupport.class, "bindCallSite", methodType(MethodHandle.class, MethodCallSite.class)); BIND_INIT_CALL_SITE = lookup.findStatic( InvokeDynamicSupport.class, "bindInitCallSite", methodType(MethodHandle.class, RoboCallSite.class)); MethodHandle cleanStackTrace = lookup.findStatic( RobolectricInternals.class, "cleanStackTrace", methodType(Throwable.class, Throwable.class)); EXCEPTION_HANDLER = filterArguments(throwException(void.class, Throwable.class), 0, cleanStackTrace); GET_SHADOW = lookup.findVirtual(ShadowedObject.class, "$$robo$getData", methodType(Object.class)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new AssertionError(e); } }
public static int add5(int a) throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodType type = MethodType.methodType(int.class, int.class, int.class); MethodHandle mhAdd = lookup.findStatic(FunctionProgramming.class, "add", type); MethodHandle mh = curry(mhAdd, 5); return (int) mh.invoke(a); }
public static Object call(InterfaceCallSite ics, Object o, Object[] args) throws Throwable { final Class<?> receiverClass = o.getClass(); // drop the 'this' (locals[0]) parameter from the signature // since that is implicit in a virtual method MethodHandle handle = lookup.findVirtual( receiverClass, ics.methodName, ics.methodType.dropParameterTypes(0, 1)); // cache receiver type as long as the CallSite // is not megamorphic if (ics.cacheDepth != -1) { // figure out what kind of an upgrade we're doing if (ics.cacheDepth < MAX_CACHE_DEPTH) { // upgrade, from either uninitialized or mono/polymorphic, // add class to polymorphic tree MethodHandle test = lookup .findVirtual( Class.class, "isInstance", MethodType.methodType(boolean.class, Object.class)) .bindTo(receiverClass); ics.cacheDepth++; // the new receiver type becomes the root // of the cache tree ics.setTarget( MethodHandles.guardWithTest( test, handle.asType(ics.getTarget().type()), ics.getTarget())); } else { // call site has become megamorphic. // don't use a cache tree anymore, set cacheDepth // to indicate megamorphic call site ics.setTarget(ics.rootHandle); ics.cacheDepth = -1; // TODO: since rootHandle points to this method, // every megmorphic invocation pays for // the branch above with ics.cacheDepth != -1 // really another static method needs to be // created that just does the invocation // without the upgrade logic } } // cache is now setup for next invocation, but we still need // to handle this invocation, so spread arguments array // over resolved receiver method and invoke handle = MethodHandles.insertArguments(handle, 0, o) .asSpreader(Object[].class, ics.methodType.parameterCount() - 1); return handle.invoke(args); }
static { final MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle methodHandle = null; try { methodHandle = lookup.findStatic(Thread.class, "onSpinWait", methodType(void.class)); } catch (final Exception ignore) { } ON_SPIN_WAIT_METHOD_HANDLE = methodHandle; }
public static void main(String[] args) throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle handle = lookup.findStatic(FunctionProgramming.class, "print", typeCallback); forEach(new Object[] {1, 2, 4}, handle); MethodHandle handle2 = lookup.findStatic(FunctionProgramming.class, "add", typeCallback2); Object[] result = map(new Object[] {1, 2, 4}, handle2); forEach(result, handle); MethodHandle handle3 = lookup.findStatic(FunctionProgramming.class, "reduce", typeCallback3); System.out.println(reduce(new Object[] {1, 2, 4}, 0, handle3)); System.out.println(FunctionProgramming.add5(8)); }
public static void main(String[] args) throws Throwable { Object x, y; String s; int i; MethodType mt; MethodHandle mh; MethodHandles.Lookup lookup = MethodHandles.lookup(); // mt is (char,char)String mt = MethodType.methodType(String.class, char.class, char.class); mh = lookup.findVirtual(String.class, "replace", mt); s = (String) mh.invokeExact("daddy", 'd', 'n'); System.out.println("Result: " + s); // invokeExact(Ljava/lang/String;CC)Ljava/lang/String; // weakly typed invocation (using MHs.invoke) s = (String) mh.invokeWithArguments("sappy", 'p', 'v'); System.out.println("Result: " + s); // mt is (Object[])List mt = MethodType.methodType(java.util.List.class, Object[].class); mh = lookup.findStatic(java.util.Arrays.class, "asList", mt); assert (mh.isVarargsCollector()); x = mh.invoke("one", "two"); // ArrayList System.out.println("x: " + x + " type: " + x.getClass().getCanonicalName()); // invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; // assertEquals(x, java.util.Arrays.asList("one","two")); // mt is (Object,Object,Object)Object mt = MethodType.genericMethodType(3); mh = mh.asType(mt); x = mh.invokeExact((Object) 1, (Object) 2, (Object) 3); // invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; // 1,2,3 System.out.println("x: " + x + " type: " + x.getClass().getCanonicalName()); // assertEquals(x, java.util.Arrays.asList(1,2,3)); // mt is ()int mt = MethodType.methodType(int.class); mh = lookup.findVirtual(java.util.List.class, "size", mt); i = (int) mh.invokeExact(java.util.Arrays.asList(1, 2, 3)); // invokeExact(Ljava/util/List;)I assert (i == 3); mt = MethodType.methodType(void.class, String.class); mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt); mh.invokeExact(System.out, "Hello, world."); // invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V }
public static MethodHandle getMH(Class<?> c) { try { return lookup.findStatic(C.class, "m_" + c.getSimpleName(), methodType(c, String.class)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new RuntimeException(e); } }
private static MethodHandle lookupSpecial(Method method) { final Class<?> declaringClass = method.getDeclaringClass(); MethodHandles.Lookup lookup = MethodHandles.publicLookup().in(declaringClass); return tryReflection( () -> { final Field f = MethodHandles.Lookup.class.getDeclaredField("allowedModes"); final int modifiers = f.getModifiers(); if (Modifier.isFinal(modifiers)) { final Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(f, modifiers & ~Modifier.FINAL); f.setAccessible(true); f.set(lookup, MethodHandles.Lookup.PRIVATE); } return lookup.unreflectSpecial(method, declaringClass); }); }
@SuppressWarnings("UnusedDeclaration") public static CallSite bootstrapInit(MethodHandles.Lookup caller, String name, MethodType type) { RoboCallSite site = new RoboCallSite(type, caller.lookupClass()); bindInitCallSite(site); return site; }
@SuppressWarnings("UnusedDeclaration") public static CallSite bootstrapStatic( MethodHandles.Lookup caller, String name, MethodType type, MethodHandle original) throws IllegalAccessException { MethodCallSite site = new MethodCallSite(type, caller.lookupClass(), name, original, STATIC); bindCallSite(site); return site; }
static { try { MethodHandles.Lookup lookup = MethodHandles.lookup(); THROW_OR_RETURN = lookup.findStatic( TestCase.class, "throwOrReturn", MethodType.methodType(Object.class, Object.class, Throwable.class)); CATCHER = lookup.findStatic( TestCase.class, "catcher", MethodType.methodType(Object.class, Object.class)); FAKE_IDENTITY = lookup.findVirtual( TestCase.class, "fakeIdentity", MethodType.methodType(Object.class, Object.class)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new Error(e); } PartialConstructor[] constructors = { create(Object.class, Object.class::cast), create(String.class, Objects::toString), create(int[].class, x -> new int[] {Objects.hashCode(x)}), create(long.class, x -> Objects.hashCode(x) & (-1L >>> 32)), create(void.class, TestCase::noop) }; Throwable[] throwables = { new ClassCastException("testing"), new java.io.IOException("testing"), new LinkageError("testing") }; List<Supplier<TestCase>> list = new ArrayList<>(constructors.length * throwables.length * ThrowMode.values().length); //noinspection unchecked for (PartialConstructor f : constructors) { for (ThrowMode mode : ThrowMode.values()) { for (Throwable t : throwables) { list.add(f.apply(mode, t)); } } } CONSTRUCTORS = Collections.unmodifiableList(list); }
public static MethodHandle resolveCallHandle() { try { return lookup.findStatic( InterfaceCallSite.class, "call", MethodType.methodType( Object.class, // return type InterfaceCallSite.class, // interface method being invoked Object.class, // receiver Object[].class) // args ); } catch (Throwable e) { throw new IllegalStateException(e); } }
public static CallSite bootstrap( MethodHandles.Lookup caller, String name, MethodType type, String targetType) throws NoSuchMethodException, IllegalAccessException, ClassNotFoundException { // lookup the target type within the ClassLoader of the // calling class, otherwise this bootstrap class may not // have visibility (if loaded through AnonymousClassLoader, etc) Class<?> targetClass = Class.forName(targetType, true, caller.lookupClass().getClassLoader()); InterfaceCallSite ics = new InterfaceCallSite(targetClass, name, type); // set the interface class, method name, and method type // as the first arguments of the handle, then have // it collect whatever arguments are sent at runtime // into a trailing Object[] ics.rootHandle = MethodHandles.insertArguments(callHandle, 0, ics) .asVarargsCollector(Object[].class) .asType(type); ics.setTarget(ics.rootHandle); return ics; }
public static void main(String[] arg) throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); Class thisClass = lookup.lookupClass(); // (who am I?) MethodType methodType; MethodHandle methodHandle; Employee employee = new Employee(); String name; Field fieldName = null; for (Field field : Employee.class.getDeclaredFields()) { if (field.getName().equals("name")) { fieldName = field; fieldName.setAccessible(true); break; } } // Lookup invoke dynamic methodType = MethodType.methodType(String.class); methodHandle = lookup.findVirtual(Employee.class, "getName", methodType); name = (String) methodHandle.invokeExact(new Employee()); System.out.println("invoke dynamic " + name); // Lookup reflection Method method = Employee.class.getMethod("getName", new Class<?>[] {}); name = (String) method.invoke(new Employee()); System.out.println("reflection " + name); // Lookup Handle Field Direct MethodHandle methodHandleFieldDirect = lookup.unreflectGetter(fieldName); name = (String) methodHandleFieldDirect.invokeExact(new Employee()); System.out.println("method handle for field direct " + name); long start = 0; long end = 0; long times = 10_000; long regularTime; long invokeDynamicTime; long reflectionTime; long count = 0; long invokeDynamicTimeUsingField; long fieldDirect; // warm up for (int index = 0; index < times; index++) { employee.getName(); name = (String) methodHandle.invokeExact(employee); name = (String) method.invoke(employee); name = (String) methodHandleFieldDirect.invokeExact(employee); } // regular method call time start = System.nanoTime(); for (int index = 0; index < times; index++) { name = employee.getName(); count += name.hashCode(); } count = 0; end = System.nanoTime(); regularTime = end - start; System.out.printf("regular method call time = %d\n", regularTime / times); // invoke dynamic method call time start = System.nanoTime(); for (int index = 0; index < times; index++) { name = (String) methodHandle.invokeExact(employee); count += name.hashCode(); } count = 0; end = System.nanoTime(); invokeDynamicTime = end - start; System.out.printf("invoke dynamic method call time = %d\n", invokeDynamicTime / times); // reflection method call time start = System.nanoTime(); for (int index = 0; index < times; index++) { name = (String) method.invoke(employee); count += name.hashCode(); } count = 0; end = System.nanoTime(); reflectionTime = end - start; System.out.printf("reflection method call time = %d\n", reflectionTime / times); // start = System.nanoTime(); for (int index = 0; index < times; index++) { name = (String) methodHandleFieldDirect.invokeExact(employee); count += name.hashCode(); } count = 0; end = System.nanoTime(); invokeDynamicTimeUsingField = end - start; System.out.printf( "field method invoke dynamic call time = %d\n", invokeDynamicTimeUsingField / times); // start = System.nanoTime(); for (int index = 0; index < times; index++) { name = (String) fieldName.get(employee); count += name.hashCode(); } count = 0; end = System.nanoTime(); fieldDirect = end - start; System.out.printf("field method reflection call time = %d\n", fieldDirect / times); }
static { Field charsField = AccessController.doPrivileged( new PrivilegedAction<Field>() { @Override public Field run() { Field charsField; try { charsField = String.class.getDeclaredField("value"); charsField.setAccessible(true); } catch (NoSuchFieldException ex) { LOG.info("char array stealing from String not supported", ex); charsField = null; } catch (SecurityException ex) { throw new RuntimeException(ex); } return charsField; } }); MethodHandles.Lookup lookup = MethodHandles.lookup(); if (charsField != null) { try { CHARS_FIELD_GET = lookup.unreflectGetter(charsField); } catch (IllegalAccessException ex) { throw new ExceptionInInitializerError(ex); } } else { CHARS_FIELD_GET = null; } // up until u45 String(int offset, int count, char value[]) { // u45 reverted to: String(char[] value, boolean share) { Constructor<String> prConstr = AccessController.doPrivileged( new PrivilegedAction<Constructor<String>>() { @Override public Constructor<String> run() { Constructor<String> constr; try { constr = String.class.getDeclaredConstructor(char[].class, boolean.class); constr.setAccessible(true); } catch (NoSuchMethodException ex) { try { constr = String.class.getDeclaredConstructor(int.class, int.class, char[].class); constr.setAccessible(true); } catch (NoSuchMethodException ex2) { ex2.addSuppressed(ex); LOG.info("building String from char[] fast not supported", ex2); constr = null; } catch (SecurityException ex2) { ex2.addSuppressed(ex); throw new RuntimeException(ex2); } } catch (SecurityException ex) { throw new RuntimeException(ex); } return constr; } }); if (prConstr == null) { PROTECTED_STR_CONSTR_PARAM_TYPES = null; PROTECTED_STR_CONSTR_HANDLE = null; } else { PROTECTED_STR_CONSTR_PARAM_TYPES = prConstr.getParameterTypes(); try { PROTECTED_STR_CONSTR_HANDLE = lookup.unreflectConstructor(prConstr); } catch (IllegalAccessException ex) { throw new ExceptionInInitializerError(ex); } } }