use of io.prestosql.sql.gen.InputReferenceCompiler.InputReferenceNode 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;
}
Aggregations