Search in sources :

Example 6 with ArgumentProperty

use of com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty in project presto by prestodb.

the class FunctionCallCodeGenerator method generateCall.

public BytecodeNode generateCall(FunctionHandle functionHandle, BytecodeGeneratorContext context, Type returnType, List<RowExpression> arguments, Optional<Variable> outputBlockVariable) {
    FunctionAndTypeManager functionAndTypeManager = context.getFunctionManager();
    ScalarFunctionImplementation function = functionAndTypeManager.getScalarFunctionImplementation(functionHandle);
    checkArgument(function instanceof JavaScalarFunctionImplementation, format("FunctionCallCodeGenerator only handles JavaScalarFunctionImplementation, get %s", function.getClass().getName()));
    JavaScalarFunctionImplementation javaFunction = (JavaScalarFunctionImplementation) function;
    List<BytecodeNode> argumentsBytecode = new ArrayList<>();
    ScalarFunctionImplementationChoice choice = getAllScalarFunctionImplementationChoices(javaFunction).get(0);
    for (int i = 0; i < arguments.size(); i++) {
        RowExpression argument = arguments.get(i);
        ArgumentProperty argumentProperty = choice.getArgumentProperty(i);
        if (argumentProperty.getArgumentType() == VALUE_TYPE) {
            argumentsBytecode.add(context.generate(argument, Optional.empty()));
        } else {
            argumentsBytecode.add(context.generate(argument, Optional.empty(), Optional.of(argumentProperty.getLambdaInterface())));
        }
    }
    return context.generateCall(functionAndTypeManager.getFunctionMetadata(functionHandle).getName().getObjectName(), javaFunction, argumentsBytecode, outputBlockVariable.map(variable -> new OutputBlockVariableAndType(variable, returnType)));
}
Also used : JavaScalarFunctionImplementation(com.facebook.presto.spi.function.JavaScalarFunctionImplementation) ScalarFunctionImplementation(com.facebook.presto.spi.function.ScalarFunctionImplementation) FunctionAndTypeManager(com.facebook.presto.metadata.FunctionAndTypeManager) RowExpression(com.facebook.presto.spi.relation.RowExpression) VALUE_TYPE(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentType.VALUE_TYPE) Variable(com.facebook.presto.bytecode.Variable) JavaScalarFunctionImplementation(com.facebook.presto.spi.function.JavaScalarFunctionImplementation) OutputBlockVariableAndType(com.facebook.presto.sql.gen.BytecodeUtils.OutputBlockVariableAndType) ScalarFunctionImplementationChoice(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice) String.format(java.lang.String.format) ArrayList(java.util.ArrayList) ArgumentProperty(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty) BytecodeUtils.getAllScalarFunctionImplementationChoices(com.facebook.presto.sql.gen.BytecodeUtils.getAllScalarFunctionImplementationChoices) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode) List(java.util.List) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) ScalarFunctionImplementation(com.facebook.presto.spi.function.ScalarFunctionImplementation) FunctionHandle(com.facebook.presto.spi.function.FunctionHandle) Optional(java.util.Optional) Type(com.facebook.presto.common.type.Type) JavaScalarFunctionImplementation(com.facebook.presto.spi.function.JavaScalarFunctionImplementation) ArgumentProperty(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty) ScalarFunctionImplementationChoice(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice) FunctionAndTypeManager(com.facebook.presto.metadata.FunctionAndTypeManager) ArrayList(java.util.ArrayList) RowExpression(com.facebook.presto.spi.relation.RowExpression) OutputBlockVariableAndType(com.facebook.presto.sql.gen.BytecodeUtils.OutputBlockVariableAndType) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode)

Example 7 with ArgumentProperty

use of com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty in project presto by prestodb.

the class BytecodeUtils method generateInvocation.

public static BytecodeNode generateInvocation(Scope scope, String name, JavaScalarFunctionImplementation function, Optional<BytecodeNode> instance, List<BytecodeNode> arguments, CallSiteBinder binder, Optional<OutputBlockVariableAndType> outputBlockVariableAndType) {
    LabelNode end = new LabelNode("end");
    BytecodeBlock block = new BytecodeBlock().setDescription("invoke " + name);
    List<Class<?>> stackTypes = new ArrayList<>();
    if (function instanceof BuiltInScalarFunctionImplementation && ((BuiltInScalarFunctionImplementation) 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<ScalarFunctionImplementationChoice> choices = getAllScalarFunctionImplementationChoices(function);
    ScalarFunctionImplementationChoice bestChoice = null;
    for (ScalarFunctionImplementationChoice currentChoice : choices) {
        boolean isValid = true;
        for (int i = 0; i < arguments.size(); i++) {
            if (currentChoice.getArgumentProperty(i).getArgumentType() != VALUE_TYPE) {
                continue;
            }
            if (currentChoice.getArgumentProperty(i).getNullConvention() == BLOCK_AND_POSITION && !(arguments.get(i) instanceof InputReferenceNode) || currentChoice.getReturnPlaceConvention() == PROVIDED_BLOCKBUILDER && (!outputBlockVariableAndType.isPresent())) {
                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 == SqlFunctionProperties.class) {
            block.append(scope.getVariable("properties"));
        } else if (type == BlockBuilder.class) {
            block.append(outputBlockVariableAndType.get().getOutputBlockVariable());
        } 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");
                            switch(bestChoice.getReturnPlaceConvention()) {
                                case STACK:
                                    block.append(ifWasNullPopAndGoto(scope, end, unboxedReturnType, Lists.reverse(stackTypes)));
                                    break;
                                case PROVIDED_BLOCKBUILDER:
                                    checkArgument(unboxedReturnType == void.class);
                                    block.append(ifWasNullClearPopAppendAndGoto(scope, end, unboxedReturnType, outputBlockVariableAndType.get().getOutputBlockVariable(), Lists.reverse(stackTypes)));
                                    break;
                                default:
                                    throw new UnsupportedOperationException(format("Unsupported return place convention: %s", bestChoice.getReturnPlaceConvention()));
                            }
                            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 (bestChoice.isNullable()) {
        switch(bestChoice.getReturnPlaceConvention()) {
            case STACK:
                block.append(unboxPrimitiveIfNecessary(scope, returnType));
                break;
            case PROVIDED_BLOCKBUILDER:
                // no-op
                break;
            default:
                throw new UnsupportedOperationException(format("Unsupported return place convention: %s", bestChoice.getReturnPlaceConvention()));
        }
    }
    block.visitLabel(end);
    if (outputBlockVariableAndType.isPresent()) {
        switch(bestChoice.getReturnPlaceConvention()) {
            case STACK:
                block.append(generateWrite(binder, scope, scope.getVariable("wasNull"), outputBlockVariableAndType.get().getType(), outputBlockVariableAndType.get().getOutputBlockVariable()));
                break;
            case PROVIDED_BLOCKBUILDER:
                // no-op
                break;
            default:
                throw new UnsupportedOperationException(format("Unsupported return place convention: %s", bestChoice.getReturnPlaceConvention()));
        }
    }
    return block;
}
Also used : LabelNode(com.facebook.presto.bytecode.instruction.LabelNode) Binding(com.facebook.presto.bytecode.Binding) MethodType(java.lang.invoke.MethodType) ArgumentProperty(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty) BuiltInScalarFunctionImplementation(com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation) SqlFunctionProperties(com.facebook.presto.common.function.SqlFunctionProperties) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) ArrayList(java.util.ArrayList) ScalarFunctionImplementationChoice(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice) InputReferenceNode(com.facebook.presto.sql.gen.InputReferenceCompiler.InputReferenceNode)

Example 8 with ArgumentProperty

use of com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty in project presto by prestodb.

the class ArrayJoin method specializeArrayJoin.

private static BuiltInScalarFunctionImplementation specializeArrayJoin(Map<String, Type> types, FunctionAndTypeManager functionAndTypeManager, List<Boolean> nullableArguments, MethodHandle methodHandleStack, MethodHandle methodHandleProvidedBlock) {
    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, methodHandleStack.bindTo(null), Optional.empty());
    } else {
        try {
            MethodHandle cast = functionAndTypeManager.getJavaScalarFunctionImplementation(functionAndTypeManager.lookupCast(CAST, type.getTypeSignature(), VARCHAR_TYPE_SIGNATURE)).getMethodHandle();
            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());
            }
            // if the cast doesn't take a SqlFunctionProperties, create an adapter that drops the provided session
            if (cast.type().parameterArray()[0] != SqlFunctionProperties.class) {
                cast = MethodHandles.dropArguments(cast, 0, SqlFunctionProperties.class);
            }
            // Adapt a target cast that takes (SqlFunctionProperties, ?) to one that takes (Block, int, SqlFunctionProperties), 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 targetStack = MethodHandles.insertArguments(methodHandleStack, 0, cast);
            MethodHandle targetProvidedBlock = MethodHandles.insertArguments(methodHandleProvidedBlock, 0, cast);
            return new BuiltInScalarFunctionImplementation(ImmutableList.of(new ScalarFunctionImplementationChoice(false, argumentProperties, STACK, targetStack, Optional.empty()), new ScalarFunctionImplementationChoice(false, argumentProperties, PROVIDED_BLOCKBUILDER, targetProvidedBlock, Optional.empty())));
        } catch (PrestoException e) {
            throw new PrestoException(INVALID_FUNCTION_ARGUMENT, format("Input type %s not supported", type), e);
        }
    }
}
Also used : FunctionAndTypeManager(com.facebook.presto.metadata.FunctionAndTypeManager) STACK(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ReturnPlaceConvention.STACK) MethodHandle(java.lang.invoke.MethodHandle) StandardTypes(com.facebook.presto.common.type.StandardTypes) FunctionKind(com.facebook.presto.spi.function.FunctionKind) Slice(io.airlift.slice.Slice) VARCHAR(com.facebook.presto.common.type.VarcharType.VARCHAR) GENERIC_INTERNAL_ERROR(com.facebook.presto.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR) PrestoException(com.facebook.presto.spi.PrestoException) TypeSignature(com.facebook.presto.common.type.TypeSignature) ArgumentProperty(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty) DEFAULT_NAMESPACE(com.facebook.presto.metadata.BuiltInTypeAndFunctionNamespaceManager.DEFAULT_NAMESPACE) Signature.typeVariable(com.facebook.presto.spi.function.Signature.typeVariable) ImmutableList(com.google.common.collect.ImmutableList) Reflection.methodHandle(com.facebook.presto.util.Reflection.methodHandle) Map(java.util.Map) QualifiedObjectName(com.facebook.presto.common.QualifiedObjectName) INVALID_FUNCTION_ARGUMENT(com.facebook.presto.spi.StandardErrorCode.INVALID_FUNCTION_ARGUMENT) UnknownType(com.facebook.presto.common.type.UnknownType) RETURN_NULL_ON_NULL(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.NullConvention.RETURN_NULL_ON_NULL) UsedByGeneratedCode(com.facebook.presto.annotation.UsedByGeneratedCode) Type(com.facebook.presto.common.type.Type) BlockBuilder(com.facebook.presto.common.block.BlockBuilder) BoundVariables(com.facebook.presto.metadata.BoundVariables) SqlScalarFunction(com.facebook.presto.metadata.SqlScalarFunction) PROVIDED_BLOCKBUILDER(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ReturnPlaceConvention.PROVIDED_BLOCKBUILDER) SqlFunctionProperties(com.facebook.presto.common.function.SqlFunctionProperties) MethodHandles(java.lang.invoke.MethodHandles) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) USE_BOXED_TYPE(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.NullConvention.USE_BOXED_TYPE) String.format(java.lang.String.format) SqlFunctionVisibility(com.facebook.presto.spi.function.SqlFunctionVisibility) ArgumentProperty.valueTypeArgumentProperty(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty.valueTypeArgumentProperty) PUBLIC(com.facebook.presto.spi.function.SqlFunctionVisibility.PUBLIC) List(java.util.List) MethodType(java.lang.invoke.MethodType) TypeSignature.parseTypeSignature(com.facebook.presto.common.type.TypeSignature.parseTypeSignature) Signature(com.facebook.presto.spi.function.Signature) Optional(java.util.Optional) Block(com.facebook.presto.common.block.Block) CAST(com.facebook.presto.metadata.CastType.CAST) ArgumentProperty(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty) ArgumentProperty.valueTypeArgumentProperty(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty.valueTypeArgumentProperty) SqlFunctionProperties(com.facebook.presto.common.function.SqlFunctionProperties) PrestoException(com.facebook.presto.spi.PrestoException) UnknownType(com.facebook.presto.common.type.UnknownType) UnknownType(com.facebook.presto.common.type.UnknownType) Type(com.facebook.presto.common.type.Type) MethodType(java.lang.invoke.MethodType) Slice(io.airlift.slice.Slice) Block(com.facebook.presto.common.block.Block) MethodHandle(java.lang.invoke.MethodHandle)

Aggregations

ArgumentProperty (com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty)8 Type (com.facebook.presto.common.type.Type)5 MethodHandle (java.lang.invoke.MethodHandle)4 SqlFunctionProperties (com.facebook.presto.common.function.SqlFunctionProperties)3 ScalarFunctionImplementationChoice (com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice)3 ArgumentProperty.valueTypeArgumentProperty (com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty.valueTypeArgumentProperty)3 MethodType (java.lang.invoke.MethodType)3 ArrayList (java.util.ArrayList)3 Block (com.facebook.presto.common.block.Block)2 FunctionAndTypeManager (com.facebook.presto.metadata.FunctionAndTypeManager)2 FunctionHandle (com.facebook.presto.spi.function.FunctionHandle)2 String.format (java.lang.String.format)2 MethodType.methodType (java.lang.invoke.MethodType.methodType)2 List (java.util.List)2 Optional (java.util.Optional)2 UsedByGeneratedCode (com.facebook.presto.annotation.UsedByGeneratedCode)1 Binding (com.facebook.presto.bytecode.Binding)1 BytecodeBlock (com.facebook.presto.bytecode.BytecodeBlock)1 BytecodeNode (com.facebook.presto.bytecode.BytecodeNode)1 Variable (com.facebook.presto.bytecode.Variable)1