Search in sources :

Example 1 with Binding

use of com.facebook.presto.bytecode.Binding in project presto by prestodb.

the class InCodeGenerator method generateExpression.

@Override
public BytecodeNode generateExpression(BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments, Optional<Variable> outputBlockVariable) {
    List<RowExpression> values = arguments.subList(1, arguments.size());
    // empty IN statements are not allowed by the standard, and not possible here
    // the implementation assumes this condition is always met
    checkArgument(values.size() > 0, "values must not be empty");
    Type type = arguments.get(0).getType();
    Class<?> javaType = type.getJavaType();
    SwitchGenerationCase switchGenerationCase = checkSwitchGenerationCase(type, values);
    FunctionHandle hashCodeHandle = generatorContext.getFunctionManager().resolveOperator(HASH_CODE, fromTypes(type));
    MethodHandle hashCodeFunction = generatorContext.getFunctionManager().getJavaScalarFunctionImplementation(hashCodeHandle).getMethodHandle();
    FunctionHandle isIndeterminateHandle = generatorContext.getFunctionManager().resolveOperator(INDETERMINATE, fromTypes(type));
    JavaScalarFunctionImplementation isIndeterminateFunction = generatorContext.getFunctionManager().getJavaScalarFunctionImplementation(isIndeterminateHandle);
    ImmutableListMultimap.Builder<Integer, BytecodeNode> hashBucketsBuilder = ImmutableListMultimap.builder();
    ImmutableList.Builder<BytecodeNode> defaultBucket = ImmutableList.builder();
    ImmutableSet.Builder<Object> constantValuesBuilder = ImmutableSet.builder();
    for (RowExpression testValue : values) {
        BytecodeNode testBytecode = generatorContext.generate(testValue, Optional.empty());
        if (isDeterminateConstant(testValue, isIndeterminateFunction.getMethodHandle())) {
            ConstantExpression constant = (ConstantExpression) testValue;
            Object object = constant.getValue();
            switch(switchGenerationCase) {
                case DIRECT_SWITCH:
                case SET_CONTAINS:
                    constantValuesBuilder.add(object);
                    break;
                case HASH_SWITCH:
                    try {
                        int hashCode = toIntExact(Long.hashCode((Long) hashCodeFunction.invoke(object)));
                        hashBucketsBuilder.put(hashCode, testBytecode);
                    } catch (Throwable throwable) {
                        throw new IllegalArgumentException("Error processing IN statement: error calculating hash code for " + object, throwable);
                    }
                    break;
                default:
                    throw new IllegalArgumentException("Not supported switch generation case: " + switchGenerationCase);
            }
        } else {
            defaultBucket.add(testBytecode);
        }
    }
    ImmutableListMultimap<Integer, BytecodeNode> hashBuckets = hashBucketsBuilder.build();
    ImmutableSet<Object> constantValues = constantValuesBuilder.build();
    LabelNode end = new LabelNode("end");
    LabelNode match = new LabelNode("match");
    LabelNode noMatch = new LabelNode("noMatch");
    LabelNode defaultLabel = new LabelNode("default");
    Scope scope = generatorContext.getScope();
    Variable value = scope.createTempVariable(javaType);
    BytecodeNode switchBlock;
    Variable expression = scope.createTempVariable(int.class);
    SwitchBuilder switchBuilder = new SwitchBuilder().expression(expression);
    switch(switchGenerationCase) {
        case DIRECT_SWITCH:
            // For these types, it's safe to not use presto HASH_CODE and EQUAL operator.
            for (Object constantValue : constantValues) {
                switchBuilder.addCase(toIntExact((Long) constantValue), jump(match));
            }
            switchBuilder.defaultCase(jump(defaultLabel));
            switchBlock = new BytecodeBlock().comment("lookupSwitch(<stackValue>))").append(new IfStatement().condition(invokeStatic(InCodeGenerator.class, "isInteger", boolean.class, value)).ifFalse(new BytecodeBlock().gotoLabel(defaultLabel))).append(expression.set(value.cast(int.class))).append(switchBuilder.build());
            break;
        case HASH_SWITCH:
            for (Map.Entry<Integer, Collection<BytecodeNode>> bucket : hashBuckets.asMap().entrySet()) {
                Collection<BytecodeNode> testValues = bucket.getValue();
                BytecodeBlock caseBlock = buildInCase(generatorContext, scope, type, match, defaultLabel, value, testValues, false, isIndeterminateFunction);
                switchBuilder.addCase(bucket.getKey(), caseBlock);
            }
            switchBuilder.defaultCase(jump(defaultLabel));
            Binding hashCodeBinding = generatorContext.getCallSiteBinder().bind(hashCodeFunction);
            switchBlock = new BytecodeBlock().comment("lookupSwitch(hashCode(<stackValue>))").getVariable(value).append(invoke(hashCodeBinding, HASH_CODE.name())).invokeStatic(Long.class, "hashCode", int.class, long.class).putVariable(expression).append(switchBuilder.build());
            break;
        case SET_CONTAINS:
            Set<?> constantValuesSet = toFastutilHashSet(constantValues, type, functionAndTypeManager);
            Binding constant = generatorContext.getCallSiteBinder().bind(constantValuesSet, constantValuesSet.getClass());
            switchBlock = new BytecodeBlock().comment("inListSet.contains(<stackValue>)").append(new IfStatement().condition(new BytecodeBlock().comment("value").getVariable(value).comment("set").append(loadConstant(constant)).invokeStatic(FastutilSetHelper.class, "in", boolean.class, javaType.isPrimitive() ? javaType : Object.class, constantValuesSet.getClass())).ifTrue(jump(match)));
            break;
        default:
            throw new IllegalArgumentException("Not supported switch generation case: " + switchGenerationCase);
    }
    BytecodeBlock defaultCaseBlock = buildInCase(generatorContext, scope, type, match, noMatch, value, defaultBucket.build(), true, isIndeterminateFunction).setDescription("default");
    BytecodeBlock block = new BytecodeBlock().comment("IN").append(generatorContext.generate(arguments.get(0), Optional.empty())).append(ifWasNullPopAndGoto(scope, end, boolean.class, javaType)).putVariable(value).append(switchBlock).visitLabel(defaultLabel).append(defaultCaseBlock);
    BytecodeBlock matchBlock = new BytecodeBlock().setDescription("match").visitLabel(match).append(generatorContext.wasNull().set(constantFalse())).push(true).gotoLabel(end);
    block.append(matchBlock);
    BytecodeBlock noMatchBlock = new BytecodeBlock().setDescription("noMatch").visitLabel(noMatch).push(false).gotoLabel(end);
    block.append(noMatchBlock);
    block.visitLabel(end);
    outputBlockVariable.ifPresent(output -> block.append(generateWrite(generatorContext, returnType, output)));
    return block;
}
Also used : LabelNode(com.facebook.presto.bytecode.instruction.LabelNode) JavaScalarFunctionImplementation(com.facebook.presto.spi.function.JavaScalarFunctionImplementation) Variable(com.facebook.presto.bytecode.Variable) ImmutableList(com.google.common.collect.ImmutableList) ConstantExpression(com.facebook.presto.spi.relation.ConstantExpression) IfStatement(com.facebook.presto.bytecode.control.IfStatement) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode) FunctionHandle(com.facebook.presto.spi.function.FunctionHandle) Binding(com.facebook.presto.bytecode.Binding) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) RowExpression(com.facebook.presto.spi.relation.RowExpression) IntegerType(com.facebook.presto.common.type.IntegerType) Type(com.facebook.presto.common.type.Type) BigintType(com.facebook.presto.common.type.BigintType) DateType(com.facebook.presto.common.type.DateType) Scope(com.facebook.presto.bytecode.Scope) SwitchBuilder(com.facebook.presto.bytecode.control.SwitchStatement.SwitchBuilder) Collection(java.util.Collection) Map(java.util.Map) MethodHandle(java.lang.invoke.MethodHandle)

Example 2 with Binding

use of com.facebook.presto.bytecode.Binding in project presto by prestodb.

the class SqlTypeBytecodeExpression method constantType.

public static SqlTypeBytecodeExpression constantType(CallSiteBinder callSiteBinder, Type type) {
    requireNonNull(callSiteBinder, "callSiteBinder is null");
    requireNonNull(type, "type is null");
    Binding binding = callSiteBinder.bind(type, Type.class);
    return new SqlTypeBytecodeExpression(type, binding, BOOTSTRAP_METHOD);
}
Also used : Binding(com.facebook.presto.bytecode.Binding)

Example 3 with Binding

use of com.facebook.presto.bytecode.Binding in project presto by prestodb.

the class CachedInstanceBinder method generateInitializations.

public void generateInitializations(Variable thisVariable, BytecodeBlock block) {
    for (Map.Entry<FieldDefinition, MethodHandle> entry : initializers.entrySet()) {
        Binding binding = callSiteBinder.bind(entry.getValue());
        block.append(thisVariable).append(invoke(binding, "instanceFieldConstructor")).putField(entry.getKey());
    }
}
Also used : Binding(com.facebook.presto.bytecode.Binding) FieldDefinition(com.facebook.presto.bytecode.FieldDefinition) HashMap(java.util.HashMap) Map(java.util.Map) MethodHandle(java.lang.invoke.MethodHandle)

Example 4 with Binding

use of com.facebook.presto.bytecode.Binding in project presto by prestodb.

the class AccumulatorCompiler method generateAddInputWindowIndex.

private static void generateAddInputWindowIndex(ClassDefinition definition, List<FieldDefinition> stateField, List<ParameterMetadata> parameterMetadatas, List<Class> lambdaInterfaces, List<FieldDefinition> lambdaProviderFields, MethodHandle inputFunction, CallSiteBinder callSiteBinder) {
    // TODO: implement masking based on maskChannel field once Window Functions support DISTINCT arguments to the functions.
    Parameter index = arg("index", WindowIndex.class);
    Parameter channels = arg("channels", type(List.class, Integer.class));
    Parameter startPosition = arg("startPosition", int.class);
    Parameter endPosition = arg("endPosition", int.class);
    MethodDefinition method = definition.declareMethod(a(PUBLIC), "addInput", type(void.class), ImmutableList.of(index, channels, startPosition, endPosition));
    Scope scope = method.getScope();
    Variable position = scope.declareVariable(int.class, "position");
    Binding binding = callSiteBinder.bind(inputFunction);
    BytecodeExpression invokeInputFunction = invokeDynamic(BOOTSTRAP_METHOD, ImmutableList.of(binding.getBindingId()), "input", binding.getType(), getInvokeFunctionOnWindowIndexParameters(scope, inputFunction.type().parameterArray(), parameterMetadatas, lambdaInterfaces, lambdaProviderFields, stateField, index, channels, position));
    method.getBody().append(new ForLoop().initialize(position.set(startPosition)).condition(BytecodeExpressions.lessThanOrEqual(position, endPosition)).update(position.increment()).body(new IfStatement().condition(anyParametersAreNull(parameterMetadatas, index, channels, position)).ifFalse(invokeInputFunction))).ret();
}
Also used : Binding(com.facebook.presto.bytecode.Binding) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Variable(com.facebook.presto.bytecode.Variable) Scope(com.facebook.presto.bytecode.Scope) ForLoop(com.facebook.presto.bytecode.control.ForLoop) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) Parameter(com.facebook.presto.bytecode.Parameter) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) BytecodeExpression(com.facebook.presto.bytecode.expression.BytecodeExpression)

Example 5 with Binding

use of com.facebook.presto.bytecode.Binding 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)

Aggregations

Binding (com.facebook.presto.bytecode.Binding)5 BytecodeBlock (com.facebook.presto.bytecode.BytecodeBlock)2 Scope (com.facebook.presto.bytecode.Scope)2 Variable (com.facebook.presto.bytecode.Variable)2 IfStatement (com.facebook.presto.bytecode.control.IfStatement)2 LabelNode (com.facebook.presto.bytecode.instruction.LabelNode)2 ImmutableList (com.google.common.collect.ImmutableList)2 MethodHandle (java.lang.invoke.MethodHandle)2 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2 BytecodeNode (com.facebook.presto.bytecode.BytecodeNode)1 FieldDefinition (com.facebook.presto.bytecode.FieldDefinition)1 MethodDefinition (com.facebook.presto.bytecode.MethodDefinition)1 Parameter (com.facebook.presto.bytecode.Parameter)1 ForLoop (com.facebook.presto.bytecode.control.ForLoop)1 SwitchBuilder (com.facebook.presto.bytecode.control.SwitchStatement.SwitchBuilder)1 BytecodeExpression (com.facebook.presto.bytecode.expression.BytecodeExpression)1 SqlFunctionProperties (com.facebook.presto.common.function.SqlFunctionProperties)1 BigintType (com.facebook.presto.common.type.BigintType)1 DateType (com.facebook.presto.common.type.DateType)1