Search in sources :

Example 6 with IfStatement

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

the class InCodeGenerator method generateExpression.

@Override
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments) {
    BytecodeNode value = generatorContext.generate(arguments.get(0));
    List<RowExpression> values = arguments.subList(1, arguments.size());
    ImmutableList.Builder<BytecodeNode> valuesBytecode = ImmutableList.builder();
    for (int i = 1; i < arguments.size(); i++) {
        BytecodeNode testNode = generatorContext.generate(arguments.get(i));
        valuesBytecode.add(testNode);
    }
    Type type = arguments.get(0).getType();
    Class<?> javaType = type.getJavaType();
    SwitchGenerationCase switchGenerationCase = checkSwitchGenerationCase(type, values);
    Signature hashCodeSignature = internalOperator(HASH_CODE, BIGINT, ImmutableList.of(type));
    MethodHandle hashCodeFunction = generatorContext.getRegistry().getScalarFunctionImplementation(hashCodeSignature).getMethodHandle();
    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);
        if (testValue instanceof ConstantExpression && ((ConstantExpression) testValue).getValue() != null) {
            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();
    BytecodeNode switchBlock;
    BytecodeBlock switchCaseBlocks = new BytecodeBlock();
    LookupSwitch.LookupSwitchBuilder switchBuilder = lookupSwitchBuilder();
    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), match);
            }
            switchBuilder.defaultCase(defaultLabel);
            switchBlock = new BytecodeBlock().comment("lookupSwitch(<stackValue>))").dup(javaType).append(new IfStatement().condition(new BytecodeBlock().dup(javaType).invokeStatic(InCodeGenerator.class, "isInteger", boolean.class, long.class)).ifFalse(new BytecodeBlock().pop(javaType).gotoLabel(defaultLabel))).longToInt().append(switchBuilder.build());
            break;
        case HASH_SWITCH:
            for (Map.Entry<Integer, Collection<BytecodeNode>> bucket : hashBuckets.asMap().entrySet()) {
                LabelNode label = new LabelNode("inHash" + bucket.getKey());
                switchBuilder.addCase(bucket.getKey(), label);
                Collection<BytecodeNode> testValues = bucket.getValue();
                BytecodeBlock caseBlock = buildInCase(generatorContext, scope, type, label, match, defaultLabel, testValues, false);
                switchCaseBlocks.append(caseBlock.setDescription("case " + bucket.getKey()));
            }
            switchBuilder.defaultCase(defaultLabel);
            Binding hashCodeBinding = generatorContext.getCallSiteBinder().bind(hashCodeFunction);
            switchBlock = new BytecodeBlock().comment("lookupSwitch(hashCode(<stackValue>))").dup(javaType).append(invoke(hashCodeBinding, hashCodeSignature)).invokeStatic(Long.class, "hashCode", int.class, long.class).append(switchBuilder.build()).append(switchCaseBlocks);
            break;
        case SET_CONTAINS:
            Set<?> constantValuesSet = toFastutilHashSet(constantValues, type, registry);
            Binding constant = generatorContext.getCallSiteBinder().bind(constantValuesSet, constantValuesSet.getClass());
            switchBlock = new BytecodeBlock().comment("inListSet.contains(<stackValue>)").append(new IfStatement().condition(new BytecodeBlock().comment("value").dup(javaType).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, defaultLabel, match, noMatch, defaultBucket.build(), true).setDescription("default");
    BytecodeBlock block = new BytecodeBlock().comment("IN").append(value).append(ifWasNullPopAndGoto(scope, end, boolean.class, javaType)).append(switchBlock).append(defaultCaseBlock);
    BytecodeBlock matchBlock = new BytecodeBlock().setDescription("match").visitLabel(match).pop(javaType).append(generatorContext.wasNull().set(constantFalse())).push(true).gotoLabel(end);
    block.append(matchBlock);
    BytecodeBlock noMatchBlock = new BytecodeBlock().setDescription("noMatch").visitLabel(noMatch).pop(javaType).push(false).gotoLabel(end);
    block.append(noMatchBlock);
    block.visitLabel(end);
    return block;
}
Also used : LabelNode(com.facebook.presto.bytecode.instruction.LabelNode) ImmutableList(com.google.common.collect.ImmutableList) ConstantExpression(com.facebook.presto.sql.relational.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) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) RowExpression(com.facebook.presto.sql.relational.RowExpression) IntegerType(com.facebook.presto.spi.type.IntegerType) DateType(com.facebook.presto.spi.type.DateType) Type(com.facebook.presto.spi.type.Type) BigintType(com.facebook.presto.spi.type.BigintType) LookupSwitch(com.facebook.presto.bytecode.control.LookupSwitch) Scope(com.facebook.presto.bytecode.Scope) Signature(com.facebook.presto.metadata.Signature) Collection(java.util.Collection) Map(java.util.Map) MethodHandle(java.lang.invoke.MethodHandle)

Example 7 with IfStatement

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

the class PageProcessorCompiler method generateGetNonLazyPageMethod.

private static void generateGetNonLazyPageMethod(ClassDefinition classDefinition, RowExpression filter, List<RowExpression> projections) {
    Parameter page = arg("page", Page.class);
    MethodDefinition method = classDefinition.declareMethod(a(PRIVATE), "getNonLazyPage", type(Page.class), page);
    Scope scope = method.getScope();
    BytecodeBlock body = method.getBody();
    List<Integer> allInputChannels = getInputChannels(concat(projections, ImmutableList.of(filter)));
    if (allInputChannels.isEmpty()) {
        body.append(page.ret());
        return;
    }
    Variable index = scope.declareVariable(int.class, "index");
    Variable channelCount = scope.declareVariable("channelCount", body, page.invoke("getChannelCount", int.class));
    Variable blocks = scope.declareVariable("blocks", body, newArray(type(Block[].class), channelCount));
    Variable inputBlock = scope.declareVariable(Block.class, "inputBlock");
    Variable positionCount = scope.declareVariable("positionCount", body, page.invoke("getPositionCount", int.class));
    Variable createNewPage = scope.declareVariable("createNewPage", body, constantFalse());
    ForLoop forLoop = new ForLoop().initialize(index.set(constantInt(0))).condition(lessThan(index, channelCount)).update(index.increment()).body(new BytecodeBlock().append(inputBlock.set(page.invoke("getBlock", Block.class, index))).append(new IfStatement().condition(inputBlock.instanceOf(LazyBlock.class)).ifTrue(new BytecodeBlock().append(blocks.setElement(index, inputBlock.cast(LazyBlock.class).invoke("getBlock", Block.class))).append(createNewPage.set(constantTrue()))).ifFalse(blocks.setElement(index, inputBlock))));
    body.append(forLoop);
    body.append(new IfStatement().condition(createNewPage).ifTrue(page.set(newInstance(Page.class, positionCount, blocks))));
    body.append(page.ret());
}
Also used : IfStatement(com.facebook.presto.bytecode.control.IfStatement) Variable(com.facebook.presto.bytecode.Variable) LazyBlock(com.facebook.presto.spi.block.LazyBlock) Scope(com.facebook.presto.bytecode.Scope) ForLoop(com.facebook.presto.bytecode.control.ForLoop) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) 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) Page(com.facebook.presto.spi.Page)

Example 8 with IfStatement

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

the class PageProcessorCompiler method generateProjectColumnarMethod.

private static MethodDefinition generateProjectColumnarMethod(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, String methodName, RowExpression projection, MethodDefinition projectionMethod) {
    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);
    List<Parameter> params = 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();
    ImmutableList.Builder<Variable> builder = ImmutableList.builder();
    for (int channel : getInputChannels(projection)) {
        Variable blockVariable = scope.declareVariable("block_" + channel, body, page.invoke("getBlock", Block.class, constantInt(channel)));
        builder.add(blockVariable);
    }
    List<Variable> inputs = builder.build();
    Variable positionCount = scope.declareVariable("positionCount", body, page.invoke("getPositionCount", int.class));
    Variable position = scope.declareVariable("position", body, constantInt(0));
    Variable cardinality = scope.declareVariable("cardinality", body, selectedPositions.length());
    Variable outputBlock = scope.declareVariable(Block.class, "outputBlock");
    Variable blockBuilder = scope.declareVariable("blockBuilder", body, pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, projectionIndex));
    Variable type = scope.declareVariable("type", body, pageBuilder.invoke("getType", Type.class, projectionIndex));
    BytecodeBlock projectBlock = new BytecodeBlock().append(new ForLoop().initialize(position.set(constantInt(0))).condition(lessThan(position, cardinality)).update(position.increment()).body(invokeProject(thisVariable, session, inputs, selectedPositions.getElement(position), pageBuilder, projectionIndex, projectionMethod))).append(outputBlock.set(blockBuilder.invoke("build", Block.class)));
    if (isIdentityExpression(projection)) {
        // if nothing is filtered out, copy the entire block, else project it
        body.append(new IfStatement().condition(equal(cardinality, positionCount)).ifTrue(new BytecodeBlock().append(inputs.get(0).invoke("assureLoaded", void.class)).append(outputBlock.set(inputs.get(0)))).ifFalse(projectBlock));
    } else if (isConstantExpression(projection)) {
        // if projection is a constant, create RLE block of constant expression with cardinality positions
        ConstantExpression constantExpression = (ConstantExpression) projection;
        verify(getInputChannels(projection).isEmpty());
        BytecodeExpression value = loadConstant(callSiteBinder, constantExpression.getValue(), Object.class);
        body.append(outputBlock.set(invokeStatic(RunLengthEncodedBlock.class, "create", Block.class, type, value, cardinality)));
    } else {
        body.append(projectBlock);
    }
    body.append(outputBlock.ret());
    return method;
}
Also used : Variable(com.facebook.presto.bytecode.Variable) ForLoop(com.facebook.presto.bytecode.control.ForLoop) ImmutableList(com.google.common.collect.ImmutableList) ConstantExpression(com.facebook.presto.sql.relational.ConstantExpression) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Type(com.facebook.presto.spi.type.Type) 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) RunLengthEncodedBlock(com.facebook.presto.spi.block.RunLengthEncodedBlock) BlockBuilder(com.facebook.presto.spi.block.BlockBuilder)

Example 9 with IfStatement

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

the class PageProcessorCompiler method generateFilterMethod.

private void generateFilterMethod(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, RowExpression filter) {
    PreGeneratedExpressions preGeneratedExpressions = generateMethodsForLambdaAndTry(classDefinition, callSiteBinder, cachedInstanceBinder, filter, "filter");
    Parameter session = arg("session", ConnectorSession.class);
    List<Parameter> blocks = toBlockParameters(getInputChannels(filter));
    Parameter position = arg("position", int.class);
    MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "filter", type(boolean.class), ImmutableList.<Parameter>builder().add(session).addAll(blocks).add(position).build());
    method.comment("Filter: %s", filter.toString());
    BytecodeBlock body = method.getBody();
    Scope scope = method.getScope();
    Variable wasNullVariable = scope.declareVariable("wasNull", body, constantFalse());
    BytecodeExpressionVisitor visitor = new BytecodeExpressionVisitor(callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(callSiteBinder), metadata.getFunctionRegistry(), preGeneratedExpressions);
    BytecodeNode visitorBody = filter.accept(visitor, scope);
    Variable result = scope.declareVariable(boolean.class, "result");
    body.append(visitorBody).putVariable(result).append(new IfStatement().condition(wasNullVariable).ifTrue(constantFalse().ret()).ifFalse(result.ret()));
}
Also used : IfStatement(com.facebook.presto.bytecode.control.IfStatement) Variable(com.facebook.presto.bytecode.Variable) Scope(com.facebook.presto.bytecode.Scope) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) Parameter(com.facebook.presto.bytecode.Parameter) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode)

Example 10 with IfStatement

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

the class JoinFilterFunctionCompiler method generateFilterMethod.

private void generateFilterMethod(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, RowExpression filter, int leftBlocksSize, FieldDefinition sessionField) {
    PreGeneratedExpressions preGeneratedExpressions = generateMethodsForLambdaAndTry(classDefinition, callSiteBinder, cachedInstanceBinder, leftBlocksSize, filter);
    // int leftPosition, Block[] leftBlocks, int rightPosition, Block[] rightBlocks
    Parameter leftPosition = arg("leftPosition", int.class);
    Parameter leftBlocks = arg("leftBlocks", Block[].class);
    Parameter rightPosition = arg("rightPosition", int.class);
    Parameter rightBlocks = arg("rightBlocks", Block[].class);
    MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "filter", type(boolean.class), ImmutableList.<Parameter>builder().add(leftPosition).add(leftBlocks).add(rightPosition).add(rightBlocks).build());
    method.comment("filter: %s", filter.toString());
    BytecodeBlock body = method.getBody();
    Scope scope = method.getScope();
    Variable wasNullVariable = scope.declareVariable("wasNull", body, constantFalse());
    scope.declareVariable("session", body, method.getThis().getField(sessionField));
    BytecodeExpressionVisitor visitor = new BytecodeExpressionVisitor(callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(callSiteBinder, leftPosition, leftBlocks, rightPosition, rightBlocks, leftBlocksSize), metadata.getFunctionRegistry(), preGeneratedExpressions);
    BytecodeNode visitorBody = filter.accept(visitor, scope);
    Variable result = scope.declareVariable(boolean.class, "result");
    body.append(visitorBody).putVariable(result).append(new IfStatement().condition(wasNullVariable).ifTrue(constantFalse().ret()).ifFalse(result.ret()));
}
Also used : IfStatement(com.facebook.presto.bytecode.control.IfStatement) Variable(com.facebook.presto.bytecode.Variable) Scope(com.facebook.presto.bytecode.Scope) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) Parameter(com.facebook.presto.bytecode.Parameter) Block(com.facebook.presto.spi.block.Block) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode)

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