private static MethodHandle unmapJava9(MethodHandles.Lookup lookup) throws ReflectiveOperationException { Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); MethodHandle unmapper = lookup.findVirtual(unsafeClass, "invokeCleaner", methodType(void.class, ByteBuffer.class)); Field f = unsafeClass.getDeclaredField("theUnsafe"); f.setAccessible(true); Object theUnsafe = f.get(null); return unmapper.bindTo(theUnsafe); }
private static MethodHandle unmapJava7Or8(MethodHandles.Lookup lookup) throws ReflectiveOperationException { /* "Compile" a MethodHandle that is roughly equivalent to the following lambda: * * (ByteBuffer buffer) -> { * sun.misc.Cleaner cleaner = ((java.nio.DirectByteBuffer) byteBuffer).cleaner(); * if (nonNull(cleaner)) * cleaner.clean(); * else * noop(cleaner); // the noop is needed because MethodHandles#guardWithTest always needs both if and else * } */ Class<?> directBufferClass = Class.forName("java.nio.DirectByteBuffer"); Method m = directBufferClass.getMethod("cleaner"); m.setAccessible(true); MethodHandle directBufferCleanerMethod = lookup.unreflect(m); Class<?> cleanerClass = directBufferCleanerMethod.type().returnType(); MethodHandle cleanMethod = lookup.findVirtual(cleanerClass, "clean", methodType(void.class)); MethodHandle nonNullTest = lookup.findStatic(MappedByteBuffers.class, "nonNull", methodType(boolean.class, Object.class)).asType(methodType(boolean.class, cleanerClass)); MethodHandle noop = dropArguments(constant(Void.class, null).asType(methodType(void.class)), 0, cleanerClass); MethodHandle unmapper = filterReturnValue(directBufferCleanerMethod, guardWithTest(nonNullTest, cleanMethod, noop)) .asType(methodType(void.class, ByteBuffer.class)); return unmapper; }
@Override public MethodHandle getMethodHandle(String methodName, MethodType type) throws NoSuchMethodException, IllegalAccessException { MethodHandle nothing = constant(Void.class, null).asType(methodType(void.class)); if (type.parameterCount() != 0) { return dropArguments(nothing, 0, type.parameterArray()); } else { return nothing; } } }
/** * Helper method to manipulate the given type to replace Wrapper with Object. */ private MethodType removeWrapper(MethodType targetType) { Class[] types = targetType.parameterArray(); for (int i=0; i<types.length; i++) { if (types[i]==Wrapper.class) { targetType = targetType.changeParameterType(i, Object.class); } } return targetType; }
/** * Replaces the types in the callSiteType parameter if more specific types * given through the arguments. This is in general the case, unless * the argument is null. */ protected static MethodType replaceWithMoreSpecificType(Object[] args, MethodType callSiteType) { for (int i=0; i<args.length; i++) { // if argument null, take the static type if (args[i]==null) continue; if (callSiteType.parameterType(i).isPrimitive()) continue; Class argClass = args[i].getClass(); callSiteType = callSiteType.changeParameterType(i, argClass); } return callSiteType; }
/** * Corrects method argument wrapping. * In cases in which we want to force a certain method selection * we use Wrapper classes to transport the static type information. * This method will be used to undo the wrapping. */ public void correctWrapping() { if (useMetaClass) return; Class[] pt = handle.type().parameterArray(); if (currentType!=null) pt = currentType.parameterArray(); for (int i=1; i<args.length; i++) { if (args[i] instanceof Wrapper) { Class type = pt[i]; MethodType mt = MethodType.methodType(type, Wrapper.class); handle = MethodHandles.filterArguments(handle, i, UNWRAP_METHOD.asType(mt)); if (LOG_ENABLED) LOG.info("added filter for Wrapper for argument at pos "+i); } } }
/** * Apply a transformer as filter. * The filter may not match exactly in the types. In this case needed * additional type transformations are done by {@link MethodHandle#asType(MethodType)} */ public static MethodHandle applyUnsharpFilter(MethodHandle handle, int pos, MethodHandle transformer) { MethodType type = transformer.type(); Class given = handle.type().parameterType(pos); if (type.returnType() != given || type.parameterType(0) != given) { transformer = transformer.asType(MethodType.methodType(given, type.parameterType(0))); } return MethodHandles.filterArguments(handle, pos, transformer); }
/** * The signature of the returned MethodHandle is (Block fromMap, int position, ConnectorSession session, BlockBuilder mapBlockBuilder)void. * The processor will get the value from fromMap, cast it and write to toBlock. */ private MethodHandle buildProcessor(FunctionRegistry functionRegistry, Type fromType, Type toType, boolean isKey) { MethodHandle getter = nativeValueGetter(fromType); // Adapt cast that takes ([ConnectorSession,] ?) to one that takes (?, ConnectorSession), where ? is the return type of getter. ScalarFunctionImplementation castImplementation = functionRegistry.getScalarFunctionImplementation(functionRegistry.getCoercion(fromType, toType)); MethodHandle cast = castImplementation.getMethodHandle(); if (cast.type().parameterArray()[0] != ConnectorSession.class) { cast = MethodHandles.dropArguments(cast, 0, ConnectorSession.class); } cast = permuteArguments(cast, methodType(cast.type().returnType(), cast.type().parameterArray()[1], cast.type().parameterArray()[0]), 1, 0); MethodHandle target = compose(cast, getter); // If the key cast function is nullable, check the result is not null. if (isKey && castImplementation.isNullable()) { target = compose(nullChecker(target.type().returnType()), target); } MethodHandle writer = nativeValueWriter(toType); writer = permuteArguments(writer, methodType(void.class, writer.type().parameterArray()[1], writer.type().parameterArray()[0]), 1, 0); return compose(writer, target.asType(methodType(unwrap(target.type().returnType()), target.type().parameterArray()))); }
public MethodType down(MethodType type) { Class<?>[] types = new Class<?>[reorder.length]; for (int i = 0; i < reorder.length; i++) { int typeIndex = reorder[i]; if (typeIndex < 0 || typeIndex >= type.parameterCount()) { throw new InvalidTransformException("one or more permute indices (" + Arrays.toString(reorder) + ") out of bounds for " + source); } types[i] = type.parameterType(reorder[i]); } return MethodType.methodType(type.returnType(), types); }
if (f.type().parameterCount() != 2) { throw new IllegalArgumentException(format("f.parameterCount != 2. f: %s", f.type())); if (f.type().parameterType(0) != g.type().returnType()) { throw new IllegalArgumentException(format("f.parameter(0) != g.return. f: %s g: %s", f.type(), g.type())); if (f.type().parameterType(1) != h.type().returnType()) { throw new IllegalArgumentException(format("f.parameter(0) != h.return. f: %s h: %s", f.type(), h.type())); MethodType typeVTU = f.type().dropParameterTypes(0, 1).appendParameterTypes(h.type().parameterList()).appendParameterTypes(f.type().parameterType(0)); MethodHandle fVTU = MethodHandles.permuteArguments(f, typeVTU, h.type().parameterCount() + 1, 0); int[] reorder = new int[fhTU.type().parameterCount()]; for (int i = 0; i < reorder.length - 1; i++) { reorder[i] = i + 1 + g.type().parameterCount(); MethodType typeUST = f.type().dropParameterTypes(1, 2).appendParameterTypes(g.type().parameterList()).appendParameterTypes(h.type().parameterList());
MethodHandle test = SAME_MC.bindTo(mc); test = test.asType(MethodType.methodType(boolean.class,targetType.parameterType(0))); handle = MethodHandles.guardWithTest(test, handle, fallback); if (LOG_ENABLED) LOG.info("added meta class equality check"); } else if (receiver instanceof Class) { MethodHandle test = EQUALS.bindTo(receiver); test = test.asType(MethodType.methodType(boolean.class,targetType.parameterType(0))); handle = MethodHandles.guardWithTest(test, handle, fallback); if (LOG_ENABLED) LOG.info("added class equality check"); Class[] pt = handle.type().parameterArray(); for (int i=0; i<args.length; i++) { Object arg = args[i]; MethodHandle test = null; if (arg==null) { test = IS_NULL.asType(MethodType.methodType(boolean.class, pt[i])); if (LOG_ENABLED) LOG.info("added null argument check at pos "+i); } else { asType(MethodType.methodType(boolean.class, pt[i])); if (LOG_ENABLED) LOG.info("added same class check at pos "+i);
private static MethodHandle bindCallSite(MethodCallSite site) throws IllegalAccessException { MethodHandle mh = RobolectricInternals.findShadowMethodHandle(site.getTheClass(), site.getName(), site.type(), site.isStatic()); if (mh == null) { // call original code mh = site.getOriginal(); } else if (mh == ShadowWrangler.DO_NOTHING) { // no-op mh = dropArguments(mh, 0, site.type().parameterList()); } else if (!site.isStatic()) { // drop arg 0 (this) for static methods Class<?> shadowType = mh.type().parameterType(0); mh = filterArguments(mh, 0, GET_SHADOW.asType(methodType(shadowType, site.thisType()))); } try { return bindWithFallback(site, cleanStackTraces(mh), BIND_CALL_SITE); } catch (Throwable t) { // The error that bubbles up is currently not very helpful so we print any error messages // here t.printStackTrace(); System.err.println(site.getTheClass()); throw t; } }
private static MethodHandle asType(final MethodHandle test, final int pos, final MethodType type) { assert test != null; assert type != null; assert type.parameterCount() > 0; assert pos >= 0 && pos < type.parameterCount(); assert test.type().parameterCount() == 1; assert test.type().returnType() == Boolean.TYPE; return MethodHandles.permuteArguments(test.asType(test.type().changeParameterType(0, type.parameterType(pos))), type.changeReturnType(Boolean.TYPE), new int[] { pos }); }
MethodType foldTargetType = MethodType.methodType(Object.class); if (args.length==3) { con = MethodHandles.dropArguments(con, 1, targetType.parameterType(1)); foldTargetType = foldTargetType.insertParameterTypes(0, targetType.parameterType(1));
@Override public MethodHandle findShadowMethodHandle(Class<?> theClass, String name, MethodType type, boolean isStatic) throws IllegalAccessException { String signature = getSignature(theClass, name, type, isStatic); InvocationProfile invocationProfile = new InvocationProfile(signature, isStatic, getClass().getClassLoader()); try { MethodHandle mh = MethodHandles.lookup().findVirtual(getClass(), "invoke", methodType(Object.class, InvocationProfile.class, Object.class, Object[].class)); mh = insertArguments(mh, 0, this, invocationProfile); if (isStatic) { return mh.bindTo(null).asCollector(Object[].class, type.parameterCount()); } else { return mh.asCollector(Object[].class, type.parameterCount() - 1); } } catch (NoSuchMethodException e) { throw new AssertionError(e); } }
Class<?> instanceType = instanceFactory.get().type().returnType(); checkArgument(instanceFactory.get().type().parameterList().size() == 0, "instanceFactory should have no parameter"); checkArgument(instanceType.equals(methodHandle.type().parameterType(0)), "methodHandle is not an instance method"); List<Class<?>> parameterList = methodHandle.type().parameterList(); boolean hasSession = false; if (parameterList.contains(ConnectorSession.class)) {
if (method.type().parameterCount() > 0 && method.type().parameterType(0) == ConnectorSession.class) { method = method.bindTo(session); boolean isNull = argument == null; if (isNull) { argument = Defaults.defaultValue(method.type().parameterType(actualArguments.size()));
public Procedure(String schema, String name, List<Argument> arguments, MethodHandle methodHandle) { this.schema = checkNotNullOrEmpty(schema, "schema").toLowerCase(ENGLISH); this.name = checkNotNullOrEmpty(name, "name").toLowerCase(ENGLISH); this.arguments = unmodifiableList(new ArrayList<>(arguments)); this.methodHandle = requireNonNull(methodHandle, "methodHandle is null"); Set<String> names = new HashSet<>(); for (Argument argument : arguments) { checkArgument(names.add(argument.getName()), "Duplicate argument name: " + argument.getName()); } checkArgument(!methodHandle.isVarargsCollector(), "Method must have fixed arity"); checkArgument(methodHandle.type().returnType() == void.class, "Method must return void"); long parameterCount = methodHandle.type().parameterList().stream() .filter(type -> !ConnectorSession.class.isAssignableFrom(type)) .count(); checkArgument(parameterCount == arguments.size(), "Method parameter count must match arguments"); }
@Override public MethodHandle getMethodHandle(String methodName, MethodType type) throws NoSuchMethodException, IllegalAccessException { Class<?> shadowWindowClass; try { shadowWindowClass = type.returnType().getClassLoader().loadClass(ShadowWindow.class.getName()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return lookup.in(type.returnType()).findStatic(shadowWindowClass, "create", type); } }
Class<?> returnType = methodType.returnType(); Class<?> unboxedReturnType = Primitives.unwrap(returnType); while (currentParameterIndex < methodType.parameterArray().length) { Class<?> type = methodType.parameterArray()[currentParameterIndex]; stackTypes.add(type); if (bestChoice.getInstanceFactory().isPresent() && !boundInstance) { checkState(type.equals(bestChoice.getInstanceFactory().get().type().returnType()), "Mismatched type for instance parameter"); block.append(instance.get()); boundInstance = true;