use of io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentProperty in project hetu-core by openlookeng.
the class ArrayJoin method specializeArrayJoin.
private static BuiltInScalarFunctionImplementation specializeArrayJoin(Map<String, Type> types, FunctionAndTypeManager functionAndTypeManager, List<Boolean> nullableArguments, MethodHandle methodHandle) {
Type type = types.get("T");
List<ArgumentProperty> argumentProperties = nullableArguments.stream().map(nullable -> nullable ? valueTypeArgumentProperty(USE_BOXED_TYPE) : valueTypeArgumentProperty(RETURN_NULL_ON_NULL)).collect(toImmutableList());
if (type instanceof UnknownType) {
return new BuiltInScalarFunctionImplementation(false, argumentProperties, methodHandle.bindTo(null), Optional.of(STATE_FACTORY));
} else {
try {
BuiltInScalarFunctionImplementation castFunction = functionAndTypeManager.getBuiltInScalarFunctionImplementation(functionAndTypeManager.lookupCast(CastType.CAST, type.getTypeSignature(), VARCHAR_TYPE_SIGNATURE));
MethodHandle getter;
Class<?> elementType = type.getJavaType();
if (elementType == boolean.class) {
getter = GET_BOOLEAN;
} else if (elementType == double.class) {
getter = GET_DOUBLE;
} else if (elementType == long.class) {
getter = GET_LONG;
} else if (elementType == Slice.class) {
getter = GET_SLICE;
} else {
throw new UnsupportedOperationException("Unsupported type: " + elementType.getName());
}
MethodHandle cast = castFunction.getMethodHandle();
// if the cast doesn't take a ConnectorSession, create an adapter that drops the provided session
if (cast.type().parameterArray()[0] != ConnectorSession.class) {
cast = MethodHandles.dropArguments(cast, 0, ConnectorSession.class);
}
// Adapt a target cast that takes (ConnectorSession, ?) to one that takes (Block, int, ConnectorSession), which will be invoked by the implementation
// The first two arguments (Block, int) are filtered through the element type's getXXX method to produce the underlying value that needs to be passed to
// the cast.
cast = MethodHandles.permuteArguments(cast, MethodType.methodType(Slice.class, cast.type().parameterArray()[1], cast.type().parameterArray()[0]), 1, 0);
cast = MethodHandles.dropArguments(cast, 1, int.class);
cast = MethodHandles.dropArguments(cast, 1, Block.class);
cast = MethodHandles.foldArguments(cast, getter.bindTo(type));
MethodHandle target = MethodHandles.insertArguments(methodHandle, 0, cast);
return new BuiltInScalarFunctionImplementation(false, argumentProperties, target, Optional.of(STATE_FACTORY));
} catch (PrestoException e) {
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, String.format("Input type %s not supported", type), e);
}
}
}
use of io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentProperty in project hetu-core by openlookeng.
the class TestFunctionInvokerProvider method testFunctionInvokerProvider.
@Test
public void testFunctionInvokerProvider() {
assertTrue(checkChoice(ImmutableList.of(new ArgumentProperty(VALUE_TYPE, Optional.of(USE_BOXED_TYPE), Optional.empty()), new ArgumentProperty(VALUE_TYPE, Optional.of(USE_BOXED_TYPE), Optional.empty())), true, false, Optional.of(new InvocationConvention(ImmutableList.of(BOXED_NULLABLE, BOXED_NULLABLE), InvocationReturnConvention.NULLABLE_RETURN, false))));
assertTrue(checkChoice(ImmutableList.of(new ArgumentProperty(VALUE_TYPE, Optional.of(RETURN_NULL_ON_NULL), Optional.empty()), new ArgumentProperty(VALUE_TYPE, Optional.of(BLOCK_AND_POSITION), Optional.empty()), new ArgumentProperty(VALUE_TYPE, Optional.of(BLOCK_AND_POSITION), Optional.empty())), false, false, Optional.of(new InvocationConvention(ImmutableList.of(NEVER_NULL, BLOCK_POSITION, BLOCK_POSITION), InvocationReturnConvention.FAIL_ON_NULL, false))));
assertTrue(checkChoice(ImmutableList.of(new ArgumentProperty(VALUE_TYPE, Optional.of(BLOCK_AND_POSITION), Optional.empty()), new ArgumentProperty(VALUE_TYPE, Optional.of(USE_NULL_FLAG), Optional.empty()), new ArgumentProperty(VALUE_TYPE, Optional.of(BLOCK_AND_POSITION), Optional.empty())), false, false, Optional.of(new InvocationConvention(ImmutableList.of(BLOCK_POSITION, NULL_FLAG, BLOCK_POSITION), InvocationReturnConvention.FAIL_ON_NULL, false))));
assertFalse(checkChoice(ImmutableList.of(new ArgumentProperty(VALUE_TYPE, Optional.of(BLOCK_AND_POSITION), Optional.empty()), new ArgumentProperty(VALUE_TYPE, Optional.of(USE_BOXED_TYPE), Optional.empty())), false, false, Optional.of(new InvocationConvention(ImmutableList.of(BLOCK_POSITION, BOXED_NULLABLE), InvocationReturnConvention.NULLABLE_RETURN, false))));
assertFalse(checkChoice(ImmutableList.of(new ArgumentProperty(VALUE_TYPE, Optional.of(BLOCK_AND_POSITION), Optional.empty()), new ArgumentProperty(VALUE_TYPE, Optional.of(BLOCK_AND_POSITION), Optional.empty())), false, false, Optional.of(new InvocationConvention(ImmutableList.of(BLOCK_POSITION, NULL_FLAG), InvocationReturnConvention.NULLABLE_RETURN, false))));
assertFalse(checkChoice(ImmutableList.of(new ArgumentProperty(VALUE_TYPE, Optional.of(USE_NULL_FLAG), Optional.empty()), new ArgumentProperty(VALUE_TYPE, Optional.of(USE_BOXED_TYPE), Optional.empty())), true, false, Optional.of(new InvocationConvention(ImmutableList.of(BLOCK_POSITION, BOXED_NULLABLE), InvocationReturnConvention.FAIL_ON_NULL, false))));
}
use of io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentProperty in project hetu-core by openlookeng.
the class BytecodeUtils method generateInvocation.
public static BytecodeNode generateInvocation(Scope scope, String name, BuiltInScalarFunctionImplementation function, Optional<BytecodeNode> instance, List<BytecodeNode> arguments, CallSiteBinder binder) {
LabelNode end = new LabelNode("end");
BytecodeBlock block = new BytecodeBlock().setDescription("invoke " + name);
List<Class<?>> stackTypes = new ArrayList<>();
if (function.getInstanceFactory().isPresent()) {
checkArgument(instance.isPresent());
}
// Index of current parameter in the MethodHandle
int currentParameterIndex = 0;
// Index of parameter (without @IsNull) in Presto function
int realParameterIndex = 0;
// Go through all the choices in the function and then pick the best one
List<ScalarImplementationChoice> choices = function.getAllChoices();
ScalarImplementationChoice bestChoice = null;
for (ScalarImplementationChoice currentChoice : choices) {
boolean isValid = true;
for (int i = 0; i < arguments.size(); i++) {
if (currentChoice.getArgumentProperty(i).getArgumentType() != VALUE_TYPE) {
continue;
}
if (!(arguments.get(i) instanceof InputReferenceNode) && currentChoice.getArgumentProperty(i).getNullConvention() == NullConvention.BLOCK_AND_POSITION) {
isValid = false;
break;
}
}
if (isValid) {
bestChoice = currentChoice;
}
}
checkState(bestChoice != null, "None of the scalar function implementation choices are valid");
Binding binding = binder.bind(bestChoice.getMethodHandle());
MethodType methodType = binding.getType();
Class<?> returnType = methodType.returnType();
Class<?> unboxedReturnType = Primitives.unwrap(returnType);
boolean boundInstance = false;
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;
} else if (type == ConnectorSession.class) {
block.append(scope.getVariable("session"));
} else {
ArgumentProperty argumentProperty = bestChoice.getArgumentProperty(realParameterIndex);
switch(argumentProperty.getArgumentType()) {
case VALUE_TYPE:
// Apply null convention for value type argument
switch(argumentProperty.getNullConvention()) {
case RETURN_NULL_ON_NULL:
block.append(arguments.get(realParameterIndex));
checkArgument(!Primitives.isWrapperType(type), "Non-nullable argument must not be primitive wrapper type");
block.append(ifWasNullPopAndGoto(scope, end, unboxedReturnType, Lists.reverse(stackTypes)));
break;
case USE_NULL_FLAG:
block.append(arguments.get(realParameterIndex));
block.append(scope.getVariable("wasNull"));
block.append(scope.getVariable("wasNull").set(constantFalse()));
stackTypes.add(boolean.class);
currentParameterIndex++;
break;
case USE_BOXED_TYPE:
block.append(arguments.get(realParameterIndex));
block.append(boxPrimitiveIfNecessary(scope, type));
block.append(scope.getVariable("wasNull").set(constantFalse()));
break;
case BLOCK_AND_POSITION:
InputReferenceNode inputReferenceNode = (InputReferenceNode) arguments.get(realParameterIndex);
block.append(inputReferenceNode.produceBlockAndPosition());
stackTypes.add(int.class);
currentParameterIndex++;
break;
default:
throw new UnsupportedOperationException(format("Unsupported null convention: %s", argumentProperty.getNullConvention()));
}
break;
case FUNCTION_TYPE:
block.append(arguments.get(realParameterIndex));
break;
default:
throw new UnsupportedOperationException(format("Unsupported argument type: %s", argumentProperty.getArgumentType()));
}
realParameterIndex++;
}
currentParameterIndex++;
}
block.append(invoke(binding, name));
if (function.isNullable()) {
block.append(unboxPrimitiveIfNecessary(scope, returnType));
}
block.visitLabel(end);
return block;
}
use of io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentProperty in project hetu-core by openlookeng.
the class ParametricScalarImplementation method javaMethodType.
private static MethodType javaMethodType(ParametricScalarImplementationChoice choice, Signature signature, TypeManager typeManager) {
// This method accomplishes two purposes:
// * Assert that the method signature is as expected.
// This catches errors that would otherwise surface during bytecode generation and class loading.
// * Adapt the method signature when necessary (for example, when the parameter type or return type is declared as Object).
ImmutableList.Builder<Class<?>> methodHandleParameterTypes = ImmutableList.builder();
if (choice.getConstructor().isPresent()) {
methodHandleParameterTypes.add(Object.class);
}
if (choice.hasConnectorSession()) {
methodHandleParameterTypes.add(ConnectorSession.class);
}
List<ArgumentProperty> argumentProperties = choice.getArgumentProperties();
for (int i = 0; i < argumentProperties.size(); i++) {
ArgumentProperty argumentProperty = argumentProperties.get(i);
switch(argumentProperty.getArgumentType()) {
case VALUE_TYPE:
Type signatureType = typeManager.getType(signature.getArgumentTypes().get(i));
switch(argumentProperty.getNullConvention()) {
case RETURN_NULL_ON_NULL:
methodHandleParameterTypes.add(signatureType.getJavaType());
break;
case USE_NULL_FLAG:
methodHandleParameterTypes.add(signatureType.getJavaType());
methodHandleParameterTypes.add(boolean.class);
break;
case USE_BOXED_TYPE:
methodHandleParameterTypes.add(Primitives.wrap(signatureType.getJavaType()));
break;
case BLOCK_AND_POSITION:
methodHandleParameterTypes.add(Block.class);
methodHandleParameterTypes.add(int.class);
break;
default:
throw new UnsupportedOperationException("unknown NullConvention");
}
break;
case FUNCTION_TYPE:
methodHandleParameterTypes.add(argumentProperty.getLambdaInterface());
break;
default:
throw new UnsupportedOperationException("unknown ArgumentType");
}
}
Class<?> methodHandleReturnType = typeManager.getType(signature.getReturnType()).getJavaType();
if (choice.isNullable()) {
methodHandleReturnType = Primitives.wrap(methodHandleReturnType);
}
return MethodType.methodType(methodHandleReturnType, methodHandleParameterTypes.build());
}
use of io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentProperty in project hetu-core by openlookeng.
the class TryCastFunction method specialize.
@Override
public BuiltInScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, FunctionAndTypeManager functionAndTypeManager) {
Type fromType = boundVariables.getTypeVariable("F");
Type toType = boundVariables.getTypeVariable("T");
Class<?> returnType = Primitives.wrap(toType.getJavaType());
List<ArgumentProperty> argumentProperties;
MethodHandle tryCastHandle;
// the resulting method needs to return a boxed type
FunctionHandle functionHandle = functionAndTypeManager.lookupCast(CAST, fromType.getTypeSignature(), toType.getTypeSignature());
BuiltInScalarFunctionImplementation implementation = functionAndTypeManager.getBuiltInScalarFunctionImplementation(functionHandle);
argumentProperties = ImmutableList.of(implementation.getArgumentProperty(0));
MethodHandle coercion = implementation.getMethodHandle();
coercion = coercion.asType(methodType(returnType, coercion.type()));
MethodHandle exceptionHandler = dropArguments(constant(returnType, null), 0, RuntimeException.class);
tryCastHandle = catchException(coercion, RuntimeException.class, exceptionHandler);
return new BuiltInScalarFunctionImplementation(true, argumentProperties, tryCastHandle);
}
Aggregations