Search in sources :

Example 46 with IfStatement

use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.

the class SwitchCodeGenerator method generateExpression.

@Override
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments) {
    // TODO: compile as
    /*
            hashCode = hashCode(<value>)

            // all constant expressions before a non-constant
            switch (hashCode) {
                case ...:
                    if (<value> == <constant1>) {
                       ...
                    }
                    else if (<value> == <constant2>) {
                       ...
                    }
                    else if (...) {
                    }
                case ...:
                    ...
            }

            if (<value> == <non-constant1>) {
                ...
            }
            else if (<value> == <non-constant2>) {
                ...
            }
            ...

            // repeat with next sequence of constant expressions
         */
    Scope scope = generatorContext.getScope();
    // process value, else, and all when clauses
    RowExpression value = arguments.get(0);
    BytecodeNode valueBytecode = generatorContext.generate(value);
    BytecodeNode elseValue;
    List<RowExpression> whenClauses;
    RowExpression last = arguments.get(arguments.size() - 1);
    if (last instanceof CallExpression && ((CallExpression) last).getSignature().getName().equals("WHEN")) {
        whenClauses = arguments.subList(1, arguments.size());
        elseValue = new BytecodeBlock().append(generatorContext.wasNull().set(constantTrue())).pushJavaDefault(returnType.getJavaType());
    } else {
        whenClauses = arguments.subList(1, arguments.size() - 1);
        elseValue = generatorContext.generate(last);
    }
    // determine the type of the value and result
    Class<?> valueType = value.getType().getJavaType();
    // evaluate the value and store it in a variable
    LabelNode nullValue = new LabelNode("nullCondition");
    Variable tempVariable = scope.createTempVariable(valueType);
    BytecodeBlock block = new BytecodeBlock().append(valueBytecode).append(BytecodeUtils.ifWasNullClearPopAndGoto(scope, nullValue, void.class, valueType)).putVariable(tempVariable);
    BytecodeNode getTempVariableNode = VariableInstruction.loadVariable(tempVariable);
    // build the statements
    elseValue = new BytecodeBlock().visitLabel(nullValue).append(elseValue);
    // reverse list because current if statement builder doesn't support if/else so we need to build the if statements bottom up
    for (RowExpression clause : Lists.reverse(whenClauses)) {
        Preconditions.checkArgument(clause instanceof CallExpression && ((CallExpression) clause).getSignature().getName().equals("WHEN"));
        RowExpression operand = ((CallExpression) clause).getArguments().get(0);
        RowExpression result = ((CallExpression) clause).getArguments().get(1);
        // call equals(value, operand)
        Signature equalsFunction = generatorContext.getRegistry().resolveOperator(OperatorType.EQUAL, ImmutableList.of(value.getType(), operand.getType()));
        // TODO: what if operand is null? It seems that the call will return "null" (which is cleared below)
        // and the code only does the right thing because the value in the stack for that scenario is
        // Java's default for boolean == false
        // This code should probably be checking for wasNull after the call and "failing" the equality
        // check if wasNull is true
        BytecodeNode equalsCall = generatorContext.generateCall(equalsFunction.getName(), generatorContext.getRegistry().getScalarFunctionImplementation(equalsFunction), ImmutableList.of(generatorContext.generate(operand), getTempVariableNode));
        BytecodeBlock condition = new BytecodeBlock().append(equalsCall).append(generatorContext.wasNull().set(constantFalse()));
        elseValue = new IfStatement("when").condition(condition).ifTrue(generatorContext.generate(result)).ifFalse(elseValue);
    }
    return block.append(elseValue);
}
Also used : LabelNode(com.facebook.presto.bytecode.instruction.LabelNode) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Variable(com.facebook.presto.bytecode.Variable) Scope(com.facebook.presto.bytecode.Scope) Signature(com.facebook.presto.metadata.Signature) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) RowExpression(com.facebook.presto.sql.relational.RowExpression) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode) CallExpression(com.facebook.presto.sql.relational.CallExpression)

Example 47 with IfStatement

use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.

the class PageProcessorCompiler method generateProjectDictionaryMethod.

private MethodDefinition generateProjectDictionaryMethod(ClassDefinition classDefinition, String methodName, RowExpression projection, MethodDefinition project, MethodDefinition projectColumnar, MethodDefinition projectRLE) {
    Parameter session = arg("session", ConnectorSession.class);
    Parameter page = arg("page", Page.class);
    Parameter selectedPositions = arg("selectedPositions", int[].class);
    Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
    Parameter projectionIndex = arg("projectionIndex", int.class);
    Parameter dictionarySourceIds = arg("dictionarySourceIds", Map.class);
    List<Parameter> params = ImmutableList.<Parameter>builder().add(session).add(page).add(selectedPositions).add(pageBuilder).add(projectionIndex).add(dictionarySourceIds).build();
    List<Parameter> columnarParams = ImmutableList.<Parameter>builder().add(session).add(page).add(selectedPositions).add(pageBuilder).add(projectionIndex).build();
    MethodDefinition method = classDefinition.declareMethod(a(PRIVATE), methodName, type(Block.class), params);
    BytecodeBlock body = method.getBody();
    Scope scope = method.getScope();
    Variable thisVariable = method.getThis();
    List<Integer> inputChannels = getInputChannels(projection);
    if (inputChannels.size() != 1 || !determinismEvaluator.isDeterministic(projection)) {
        body.append(thisVariable.invoke(projectColumnar, columnarParams).ret());
        return method;
    }
    Variable inputBlock = scope.declareVariable("inputBlock", body, page.invoke("getBlock", Block.class, constantInt(getOnlyElement(inputChannels))));
    body.append(new IfStatement().condition(inputBlock.instanceOf(RunLengthEncodedBlock.class)).ifTrue(thisVariable.invoke(projectRLE, columnarParams).ret()));
    body.append(new IfStatement().condition(inputBlock.instanceOf(DictionaryBlock.class)).ifFalse(thisVariable.invoke(projectColumnar, columnarParams).ret()));
    Variable blockBuilder = scope.declareVariable("blockBuilder", body, pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, projectionIndex));
    Variable cardinality = scope.declareVariable("cardinality", body, selectedPositions.length());
    Variable dictionary = scope.declareVariable(Block.class, "dictionary");
    Variable dictionaryCount = scope.declareVariable(int.class, "dictionaryCount");
    Variable inputSourceId = scope.declareVariable(DictionaryId.class, "inputSourceId");
    Variable outputSourceId = scope.declareVariable(DictionaryId.class, "outputSourceId");
    Variable outputDictionary = scope.declareVariable(Block.class, "outputDictionary");
    Variable outputIds = scope.declareVariable(int[].class, "outputIds");
    BytecodeExpression inputDictionaries = thisVariable.getField("inputDictionaries", Block[].class);
    BytecodeExpression outputDictionaries = thisVariable.getField("outputDictionaries", Block[].class);
    Variable position = scope.declareVariable("position", body, constantInt(0));
    BytecodeExpression castDictionaryBlock = inputBlock.cast(DictionaryBlock.class);
    body.comment("Extract dictionary, ids, positionCount and dictionarySourceId").append(dictionary.set(castDictionaryBlock.invoke("getDictionary", Block.class))).append(dictionaryCount.set(dictionary.invoke("getPositionCount", int.class))).append(inputSourceId.set(castDictionaryBlock.invoke("getDictionarySourceId", DictionaryId.class)));
    BytecodeBlock projectDictionary = new BytecodeBlock().comment("Project dictionary").append(new ForLoop().initialize(position.set(constantInt(0))).condition(lessThan(position, dictionaryCount)).update(position.increment()).body(invokeProject(thisVariable, session, ImmutableList.of(dictionary), position, pageBuilder, projectionIndex, project))).append(outputDictionary.set(blockBuilder.invoke("build", Block.class))).append(inputDictionaries.setElement(projectionIndex, dictionary)).append(outputDictionaries.setElement(projectionIndex, outputDictionary));
    body.comment("Use processed dictionary, if available, else project it").append(new IfStatement().condition(equal(inputDictionaries.getElement(projectionIndex), dictionary)).ifTrue(outputDictionary.set(outputDictionaries.getElement(projectionIndex))).ifFalse(projectDictionary));
    body.comment("Filter ids").append(outputIds.set(newArray(type(int[].class), cardinality))).append(new ForLoop().initialize(position.set(constantInt(0))).condition(lessThan(position, cardinality)).update(position.increment()).body(outputIds.setElement(position, castDictionaryBlock.invoke("getId", int.class, selectedPositions.getElement(position)))));
    body.append(outputSourceId.set(dictionarySourceIds.invoke("get", Object.class, inputSourceId.cast(Object.class)).cast(DictionaryId.class)));
    body.append(new IfStatement().condition(equal(outputSourceId, constantNull(DictionaryId.class))).ifTrue(new BytecodeBlock().append(outputSourceId.set(invokeStatic(DictionaryId.class, "randomDictionaryId", DictionaryId.class))).append(dictionarySourceIds.invoke("put", Object.class, inputSourceId.cast(Object.class), outputSourceId.cast(Object.class))).pop()));
    body.append(newInstance(DictionaryBlock.class, cardinality, outputDictionary, outputIds, constantFalse(), outputSourceId).cast(Block.class).ret());
    return method;
}
Also used : Variable(com.facebook.presto.bytecode.Variable) ForLoop(com.facebook.presto.bytecode.control.ForLoop) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) DictionaryBlock(com.facebook.presto.spi.block.DictionaryBlock) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Scope(com.facebook.presto.bytecode.Scope) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) Parameter(com.facebook.presto.bytecode.Parameter) Block(com.facebook.presto.spi.block.Block) DictionaryBlock(com.facebook.presto.spi.block.DictionaryBlock) LazyBlock(com.facebook.presto.spi.block.LazyBlock) RunLengthEncodedBlock(com.facebook.presto.spi.block.RunLengthEncodedBlock) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) RunLengthEncodedBlock(com.facebook.presto.spi.block.RunLengthEncodedBlock) BytecodeExpression(com.facebook.presto.bytecode.expression.BytecodeExpression) BlockBuilder(com.facebook.presto.spi.block.BlockBuilder)

Example 48 with IfStatement

use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.

the class PageProcessorCompiler method generateProcessColumnarDictionaryMethod.

private static void generateProcessColumnarDictionaryMethod(ClassDefinition classDefinition, List<RowExpression> projections, List<MethodDefinition> projectDictionaryMethods) {
    Parameter session = arg("session", ConnectorSession.class);
    Parameter page = arg("page", Page.class);
    Parameter types = arg("types", List.class);
    MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "processColumnarDictionary", type(Page.class), session, page, types);
    Scope scope = method.getScope();
    BytecodeBlock body = method.getBody();
    Variable thisVariable = method.getThis();
    Variable selectedPositions = scope.declareVariable("selectedPositions", body, thisVariable.invoke("filterPage", int[].class, session, page));
    Variable cardinality = scope.declareVariable("cardinality", body, selectedPositions.length());
    Variable dictionarySourceIds = scope.declareVariable(type(Map.class, DictionaryId.class, DictionaryId.class), "dictionarySourceIds");
    body.append(dictionarySourceIds.set(newInstance(type(HashMap.class, DictionaryId.class, DictionaryId.class))));
    body.comment("if no rows selected return null").append(new IfStatement().condition(equal(cardinality, constantInt(0))).ifTrue(constantNull(Page.class).ret()));
    if (projections.isEmpty()) {
        // if no projections, return new page with selected rows
        body.append(newInstance(Page.class, cardinality, newArray(type(Block[].class), 0)).ret());
        return;
    }
    // create PageBuilder
    Variable pageBuilder = scope.declareVariable("pageBuilder", body, newInstance(PageBuilder.class, cardinality, types));
    body.append(page.set(thisVariable.invoke("getNonLazyPage", Page.class, page)));
    // create outputBlocks
    Variable outputBlocks = scope.declareVariable("outputBlocks", body, newArray(type(Block[].class), projections.size()));
    for (int projectionIndex = 0; projectionIndex < projections.size(); projectionIndex++) {
        List<BytecodeExpression> params = ImmutableList.<BytecodeExpression>builder().add(session).add(page).add(selectedPositions).add(pageBuilder).add(constantInt(projectionIndex)).add(dictionarySourceIds).build();
        body.append(outputBlocks.setElement(projectionIndex, thisVariable.invoke(projectDictionaryMethods.get(projectionIndex), params)));
    }
    body.append(newInstance(Page.class, cardinality, outputBlocks).ret());
}
Also used : Variable(com.facebook.presto.bytecode.Variable) HashMap(java.util.HashMap) DictionaryId(com.facebook.presto.spi.block.DictionaryId) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) Page(com.facebook.presto.spi.Page) PageBuilder(com.facebook.presto.spi.PageBuilder) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Scope(com.facebook.presto.bytecode.Scope) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) Parameter(com.facebook.presto.bytecode.Parameter) Block(com.facebook.presto.spi.block.Block) DictionaryBlock(com.facebook.presto.spi.block.DictionaryBlock) LazyBlock(com.facebook.presto.spi.block.LazyBlock) RunLengthEncodedBlock(com.facebook.presto.spi.block.RunLengthEncodedBlock) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) BytecodeExpression(com.facebook.presto.bytecode.expression.BytecodeExpression) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) HashMap(java.util.HashMap)

Example 49 with IfStatement

use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.

the class MapFilterFunction method generateFilter.

private static MethodHandle generateFilter(Type keyType, Type valueType) {
    CallSiteBinder binder = new CallSiteBinder();
    MapType mapType = new MapType(keyType, valueType);
    Class<?> keyJavaType = Primitives.wrap(keyType.getJavaType());
    Class<?> valueJavaType = Primitives.wrap(valueType.getJavaType());
    ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("MapFilter"), type(Object.class));
    definition.declareDefaultConstructor(a(PRIVATE));
    Parameter block = arg("block", Block.class);
    Parameter function = arg("function", MethodHandle.class);
    MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "filter", type(Block.class), ImmutableList.of(block, function));
    BytecodeBlock body = method.getBody();
    Scope scope = method.getScope();
    Variable positionCount = scope.declareVariable(int.class, "positionCount");
    Variable position = scope.declareVariable(int.class, "position");
    Variable blockBuilder = scope.declareVariable(BlockBuilder.class, "blockBuilder");
    Variable keyElement = scope.declareVariable(keyJavaType, "keyElement");
    Variable valueElement = scope.declareVariable(valueJavaType, "valueElement");
    Variable keep = scope.declareVariable(Boolean.class, "keep");
    // invoke block.getPositionCount()
    body.append(positionCount.set(block.invoke("getPositionCount", int.class)));
    // create the interleaved block builder
    body.append(blockBuilder.set(newInstance(InterleavedBlockBuilder.class, constantType(binder, mapType).invoke("getTypeParameters", List.class), newInstance(BlockBuilderStatus.class), positionCount)));
    SqlTypeBytecodeExpression keySqlType = constantType(binder, keyType);
    BytecodeNode loadKeyElement;
    if (!keyType.equals(UNKNOWN)) {
        // key element must be non-null
        loadKeyElement = new BytecodeBlock().append(keyElement.set(keySqlType.getValue(block, position).cast(keyJavaType)));
    } else {
        loadKeyElement = new BytecodeBlock().append(keyElement.set(constantNull(keyJavaType)));
    }
    SqlTypeBytecodeExpression valueSqlType = constantType(binder, valueType);
    BytecodeNode loadValueElement;
    if (!valueType.equals(UNKNOWN)) {
        loadValueElement = new IfStatement().condition(block.invoke("isNull", boolean.class, add(position, constantInt(1)))).ifTrue(valueElement.set(constantNull(valueJavaType))).ifFalse(valueElement.set(valueSqlType.getValue(block, add(position, constantInt(1))).cast(valueJavaType)));
    } else {
        loadValueElement = new BytecodeBlock().append(valueElement.set(constantNull(valueJavaType)));
    }
    body.append(new ForLoop().initialize(position.set(constantInt(0))).condition(lessThan(position, positionCount)).update(incrementVariable(position, (byte) 2)).body(new BytecodeBlock().append(loadKeyElement).append(loadValueElement).append(keep.set(function.invoke("invokeExact", Boolean.class, keyElement, valueElement))).append(new IfStatement("if (keep != null && keep) ...").condition(and(notEqual(keep, constantNull(Boolean.class)), keep.cast(boolean.class))).ifTrue(new BytecodeBlock().append(keySqlType.invoke("appendTo", void.class, block, position, blockBuilder)).append(valueSqlType.invoke("appendTo", void.class, block, add(position, constantInt(1)), blockBuilder))))));
    body.append(blockBuilder.invoke("build", Block.class).ret());
    Class<?> generatedClass = defineClass(definition, Object.class, binder.getBindings(), MapFilterFunction.class.getClassLoader());
    return methodHandle(generatedClass, "filter", Block.class, MethodHandle.class);
}
Also used : Variable(com.facebook.presto.bytecode.Variable) Signature.typeVariable(com.facebook.presto.metadata.Signature.typeVariable) VariableInstruction.incrementVariable(com.facebook.presto.bytecode.instruction.VariableInstruction.incrementVariable) ForLoop(com.facebook.presto.bytecode.control.ForLoop) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) ClassDefinition(com.facebook.presto.bytecode.ClassDefinition) MapType(com.facebook.presto.type.MapType) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Scope(com.facebook.presto.bytecode.Scope) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) CallSiteBinder(com.facebook.presto.sql.gen.CallSiteBinder) Parameter(com.facebook.presto.bytecode.Parameter) Block(com.facebook.presto.spi.block.Block) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode) BlockBuilderStatus(com.facebook.presto.spi.block.BlockBuilderStatus) SqlTypeBytecodeExpression(com.facebook.presto.sql.gen.SqlTypeBytecodeExpression)

Example 50 with IfStatement

use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.

the class CursorProcessorCompiler method fieldReferenceCompiler.

private static RowExpressionVisitor<Scope, BytecodeNode> fieldReferenceCompiler(Variable cursorVariable) {
    return new RowExpressionVisitor<Scope, BytecodeNode>() {

        @Override
        public BytecodeNode visitInputReference(InputReferenceExpression node, Scope scope) {
            int field = node.getField();
            Type type = node.getType();
            Variable wasNullVariable = scope.getVariable("wasNull");
            Class<?> javaType = type.getJavaType();
            if (!javaType.isPrimitive() && javaType != Slice.class) {
                javaType = Object.class;
            }
            IfStatement ifStatement = new IfStatement();
            ifStatement.condition().setDescription(format("cursor.get%s(%d)", type, field)).getVariable(cursorVariable).push(field).invokeInterface(RecordCursor.class, "isNull", boolean.class, int.class);
            ifStatement.ifTrue().putVariable(wasNullVariable, true).pushJavaDefault(javaType);
            ifStatement.ifFalse().getVariable(cursorVariable).push(field).invokeInterface(RecordCursor.class, "get" + Primitives.wrap(javaType).getSimpleName(), javaType, int.class);
            return ifStatement;
        }

        @Override
        public BytecodeNode visitCall(CallExpression call, Scope scope) {
            throw new UnsupportedOperationException("not yet implemented");
        }

        @Override
        public BytecodeNode visitConstant(ConstantExpression literal, Scope scope) {
            throw new UnsupportedOperationException("not yet implemented");
        }

        @Override
        public BytecodeNode visitLambda(LambdaDefinitionExpression lambda, Scope context) {
            throw new UnsupportedOperationException();
        }

        @Override
        public BytecodeNode visitVariableReference(VariableReferenceExpression reference, Scope context) {
            throw new UnsupportedOperationException();
        }
    };
}
Also used : InputReferenceExpression(com.facebook.presto.sql.relational.InputReferenceExpression) Variable(com.facebook.presto.bytecode.Variable) ConstantExpression(com.facebook.presto.sql.relational.ConstantExpression) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Type(com.facebook.presto.spi.type.Type) Scope(com.facebook.presto.bytecode.Scope) Slice(io.airlift.slice.Slice) VariableReferenceExpression(com.facebook.presto.sql.relational.VariableReferenceExpression) RowExpressionVisitor(com.facebook.presto.sql.relational.RowExpressionVisitor) CallExpression(com.facebook.presto.sql.relational.CallExpression) LambdaDefinitionExpression(com.facebook.presto.sql.relational.LambdaDefinitionExpression)

Aggregations

IfStatement (com.facebook.presto.bytecode.control.IfStatement)77 BytecodeBlock (com.facebook.presto.bytecode.BytecodeBlock)72 Variable (com.facebook.presto.bytecode.Variable)65 MethodDefinition (com.facebook.presto.bytecode.MethodDefinition)45 Scope (com.facebook.presto.bytecode.Scope)43 Parameter (com.facebook.presto.bytecode.Parameter)41 BytecodeNode (com.facebook.presto.bytecode.BytecodeNode)23 ForLoop (com.facebook.presto.bytecode.control.ForLoop)19 BytecodeExpression (com.facebook.presto.bytecode.expression.BytecodeExpression)19 LabelNode (com.facebook.presto.bytecode.instruction.LabelNode)19 ImmutableList (com.google.common.collect.ImmutableList)18 Block (com.facebook.presto.spi.block.Block)15 Block (com.facebook.presto.common.block.Block)13 ClassDefinition (com.facebook.presto.bytecode.ClassDefinition)10 Type (com.facebook.presto.common.type.Type)10 DictionaryBlock (com.facebook.presto.spi.block.DictionaryBlock)10 LazyBlock (com.facebook.presto.spi.block.LazyBlock)10 RunLengthEncodedBlock (com.facebook.presto.spi.block.RunLengthEncodedBlock)10 CallSiteBinder (com.facebook.presto.bytecode.CallSiteBinder)9 BlockBuilder (com.facebook.presto.common.block.BlockBuilder)9