private Optional<MethodHandle> getConstructor(Method method, Optional<Constructor<?>> optionalConstructor) { if (isStatic(method.getModifiers())) { return Optional.empty(); } checkArgument(optionalConstructor.isPresent(), "Method [%s] is an instance method. It must be in a class annotated with @ScalarFunction, and the class is required to have a public constructor.", method); Constructor<?> constructor = optionalConstructor.get(); Set<TypeParameter> constructorTypeParameters = Stream.of(constructor.getAnnotationsByType(TypeParameter.class)) .collect(ImmutableSet.toImmutableSet()); checkArgument(constructorTypeParameters.containsAll(typeParameters), "Method [%s] is an instance method and requires a public constructor containing all type parameters: %s", method, typeParameters); for (int i = 0; i < constructor.getParameterCount(); i++) { Annotation[] annotations = constructor.getParameterAnnotations()[i]; checkArgument(containsImplementationDependencyAnnotation(annotations), "Constructors may only have meta parameters [%s]", constructor); checkArgument(annotations.length == 1, "Meta parameters may only have a single annotation [%s]", constructor); Annotation annotation = annotations[0]; if (annotation instanceof TypeParameter) { checkTypeParameters(parseTypeSignature(((TypeParameter) annotation).value()), typeParameterNames, method); } constructorDependencies.add(createDependency(annotation, literalParameters)); } MethodHandle result = constructorMethodHandle(FUNCTION_IMPLEMENTATION_ERROR, constructor); // Change type of return value to Object to make sure callers won't have classloader issues return Optional.of(result.asType(result.type().changeReturnType(Object.class))); }
@Override public ScalarFunctionImplementation specialize( BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry) { Type toType = boundVariables.getTypeVariable("E"); MethodHandle methodHandle = METHOD_HANDLE_NON_NULL.asType(METHOD_HANDLE_NON_NULL.type().changeReturnType(toType.getJavaType())); return new ScalarFunctionImplementation( false, ImmutableList.of(valueTypeArgumentProperty(RETURN_NULL_ON_NULL)), methodHandle, isDeterministic()); }
@Override public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry) { Type returnType = boundVariables.getTypeVariable("T"); return new ScalarFunctionImplementation( true, ImmutableList.of(functionTypeArgumentProperty(InvokeLambda.class)), METHOD_HANDLE.asType( METHOD_HANDLE.type() .changeReturnType(wrap(returnType.getJavaType()))), isDeterministic()); }
private static MethodHandle cleanStackTraces(MethodHandle mh) { MethodType type = EXCEPTION_HANDLER.type().changeReturnType(mh.type().returnType()); return catchException(mh, Throwable.class, EXCEPTION_HANDLER.asType(type)); } }
@Override public MethodHandle getShadowCreator(Class<?> theClass) { ShadowInfo shadowInfo = getShadowInfo(theClass); if (shadowInfo == null) return dropArguments(NO_SHADOW_HANDLE, 0, theClass); String shadowClassName = shadowInfo.shadowClassName; try { Class<?> shadowClass = Class.forName(shadowClassName, false, theClass.getClassLoader()); ShadowMetadata shadowMetadata = getShadowMetadata(shadowClass); MethodHandle mh = identity(shadowClass); // (instance) mh = dropArguments(mh, 1, theClass); // (instance) for (Field field : shadowMetadata.realObjectFields) { MethodHandle setter = LOOKUP.unreflectSetter(field); MethodType setterType = mh.type().changeReturnType(void.class); mh = foldArguments(mh, setter.asType(setterType)); } mh = foldArguments(mh, LOOKUP.unreflectConstructor(shadowMetadata.constructor)); // (shadow, instance) return mh; // (instance) } catch (IllegalAccessException | ClassNotFoundException e) { throw new RuntimeException("Could not instantiate shadow " + shadowClassName + " for " + theClass, e); } }
@Override public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry) { Type argumentType = boundVariables.getTypeVariable("T"); Type returnType = boundVariables.getTypeVariable("U"); return new ScalarFunctionImplementation( true, ImmutableList.of( valueTypeArgumentProperty(USE_BOXED_TYPE), functionTypeArgumentProperty(UnaryFunctionInterface.class)), METHOD_HANDLE.asType( METHOD_HANDLE.type() .changeReturnType(wrap(returnType.getJavaType())) .changeParameterType(0, wrap(argumentType.getJavaType()))), isDeterministic()); }
@Override public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry) { Type inputType = boundVariables.getTypeVariable("T"); Type intermediateType = boundVariables.getTypeVariable("S"); Type outputType = boundVariables.getTypeVariable("R"); MethodHandle methodHandle = METHOD_HANDLE.bindTo(inputType); return new ScalarFunctionImplementation( true, ImmutableList.of( valueTypeArgumentProperty(RETURN_NULL_ON_NULL), valueTypeArgumentProperty(USE_BOXED_TYPE), functionTypeArgumentProperty(BinaryFunctionInterface.class), functionTypeArgumentProperty(UnaryFunctionInterface.class)), methodHandle.asType( methodHandle.type() .changeParameterType(1, Primitives.wrap(intermediateType.getJavaType())) .changeReturnType(Primitives.wrap(outputType.getJavaType()))), isDeterministic()); }
methodHandle = methodHandle.asType(methodHandle.type().changeReturnType(Primitives.wrap(valueType.getJavaType())));
InterpretedFunctionInvoker functionInvoker = new InterpretedFunctionInvoker(functionRegistry); methodHandle = methodHandle.bindTo(functionInvoker).bindTo(keyType).bindTo(valueType); methodHandle = methodHandle.asType(methodHandle.type().changeReturnType(Primitives.wrap(valueType.getJavaType())));
/** * Create a new signature based on this one with a different return type. * * @param retval the class for the new signature's return type * @return the new signature with modified return value */ public Signature changeReturn(Class<?> retval) { return new Signature(methodType.changeReturnType(retval), argNames); }
private static MethodHandle constantBoolean(Boolean value, MethodType type) { return MethodHandles.permuteArguments(MethodHandles.constant(Boolean.TYPE, value), type.changeReturnType(Boolean.TYPE)); } }
/** * Returns a new call site descriptor that is identical to the passed one, except that it has the return type * changed in its method type. * @param desc the original call site descriptor * @param nrtype the new return type * @return a new call site descriptor with modified method type */ public static CallSiteDescriptor changeReturnType(final CallSiteDescriptor desc, final Class<?> nrtype) { return desc.changeMethodType(desc.getMethodType().changeReturnType(nrtype)); }
private static MethodHandle constantBoolean(final Boolean value, final MethodType type) { return MethodHandles.permuteArguments(MethodHandles.constant(Boolean.TYPE, value), type.changeReturnType(Boolean.TYPE)); } }
private static MethodHandle getHandle( final Class<? extends RuntimeException> c) { return HANDLES.computeIfAbsent(c, key -> { try { return LOOKUP.findConstructor(c, TYPE) .asType(TYPE.changeReturnType(RuntimeException.class)); } catch (IllegalAccessException | NoSuchMethodException e) { throw new InstantiationException(e); } }); }
public MethodType down(MethodType type) { int count = function.type().parameterCount(); switch (count) { case 0: return type.changeReturnType(void.class); case 1: return type.changeReturnType(function.type().parameterType(0)); default: throw new InvalidTransformException("return filter " + function + " does not accept zero or one argument"); } }
@Override public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry) { Type returnType = boundVariables.getTypeVariable("T"); return new ScalarFunctionImplementation( true, ImmutableList.of(functionTypeArgumentProperty(InvokeLambda.class)), METHOD_HANDLE.asType( METHOD_HANDLE.type() .changeReturnType(wrap(returnType.getJavaType()))), isDeterministic()); }
private MethodHandle createRelinkAndInvokeMethod(final RelinkableCallSite callSite, int relinkCount) { // Make a bound MH of invoke() for this linker and call site final MethodHandle boundRelinker = MethodHandles.insertArguments(RELINK, 0, this, callSite, Integer.valueOf( relinkCount)); // Make a MH that gathers all arguments to the invocation into an Object[] final MethodType type = callSite.getDescriptor().getMethodType(); final MethodHandle collectingRelinker = boundRelinker.asCollector(Object[].class, type.parameterCount()); return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), collectingRelinker.asType( type.changeReturnType(MethodHandle.class))); }
protected static MethodHandle adaptSignature(MethodHandle originalHandle, boolean isStatic, int parameterCount) { MethodHandle adaptedHandle = originalHandle; adaptedHandle = adaptedHandle.asType(adaptedHandle.type().changeReturnType(Object.class)); if (isStatic) { adaptedHandle = MethodHandles.dropArguments(adaptedHandle, 0, Object.class); } else { adaptedHandle = adaptedHandle.asType(adaptedHandle.type().changeParameterType(0, Object.class)); } adaptedHandle = adaptedHandle.asSpreader(Object[].class, parameterCount); return adaptedHandle; } }
private static MethodHandle convertArgToInt(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) { final Class<?> sourceType = desc.getMethodType().parameterType(1); if(TypeUtilities.isMethodInvocationConvertible(sourceType, Number.class)) { return mh; } else if(ls.canConvert(sourceType, Number.class)) { final MethodHandle converter = ls.getTypeConverter(sourceType, Number.class); return MethodHandles.filterArguments(mh, 1, converter.asType(converter.type().changeReturnType( mh.type().parameterType(1)))); } return mh; }
private static MethodHandle convertArgToInt(MethodHandle mh, LinkerServices ls, CallSiteDescriptor desc) { final Class<?> sourceType = desc.getMethodType().parameterType(1); if(TypeUtilities.isMethodInvocationConvertible(sourceType, Number.class)) { return mh; } else if(ls.canConvert(sourceType, Number.class)) { final MethodHandle converter = ls.getTypeConverter(sourceType, Number.class); return MethodHandles.filterArguments(mh, 1, converter.asType(converter.type().changeReturnType( mh.type().parameterType(1)))); } return mh; }