Search in sources :

Example 26 with BytecodeBlock

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

the class DereferenceCodeGenerator method generateExpression.

@Override
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generator, Type returnType, List<RowExpression> arguments) {
    checkArgument(arguments.size() == 2);
    CallSiteBinder callSiteBinder = generator.getCallSiteBinder();
    BytecodeBlock block = new BytecodeBlock().comment("DEREFERENCE").setDescription("DEREFERENCE");
    Variable wasNull = generator.wasNull();
    Variable rowBlock = generator.getScope().createTempVariable(Block.class);
    int index = (int) ((ConstantExpression) arguments.get(1)).getValue();
    // clear the wasNull flag before evaluating the row value
    block.putVariable(wasNull, false);
    block.append(generator.generate(arguments.get(0))).putVariable(rowBlock);
    IfStatement ifRowBlockIsNull = new IfStatement("if row block is null...").condition(wasNull);
    Class<?> javaType = returnType.getJavaType();
    LabelNode end = new LabelNode("end");
    ifRowBlockIsNull.ifTrue().comment("if row block is null, push null to the stack and goto 'end' label (return)").putVariable(wasNull, true).pushJavaDefault(javaType).gotoLabel(end);
    block.append(ifRowBlockIsNull);
    IfStatement ifFieldIsNull = new IfStatement("if row field is null...");
    ifFieldIsNull.condition().comment("call rowBlock.isNull(index)").append(rowBlock).push(index).invokeInterface(Block.class, "isNull", boolean.class, int.class);
    ifFieldIsNull.ifTrue().comment("if the field is null, push null to stack").putVariable(wasNull, true).pushJavaDefault(javaType);
    BytecodeExpression value = constantType(callSiteBinder, returnType).getValue(rowBlock, constantInt(index));
    ifFieldIsNull.ifFalse().comment("otherwise call type.getTYPE(rowBlock, index)").append(value).putVariable(wasNull, false);
    block.append(ifFieldIsNull).visitLabel(end);
    return block;
}
Also used : LabelNode(com.facebook.presto.bytecode.instruction.LabelNode) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Variable(com.facebook.presto.bytecode.Variable) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) BytecodeExpression(com.facebook.presto.bytecode.expression.BytecodeExpression)

Example 27 with BytecodeBlock

use of com.facebook.presto.bytecode.BytecodeBlock 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 28 with BytecodeBlock

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

the class PageProcessorCompiler method generateProjectMethod.

private MethodDefinition generateProjectMethod(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, String methodName, RowExpression projection) {
    PreGeneratedExpressions preGeneratedExpressions = generateMethodsForLambdaAndTry(classDefinition, callSiteBinder, cachedInstanceBinder, projection, methodName);
    Parameter session = arg("session", ConnectorSession.class);
    List<Parameter> blocks = toBlockParameters(getInputChannels(projection));
    Parameter position = arg("position", int.class);
    Parameter output = arg("output", BlockBuilder.class);
    MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), methodName, type(void.class), ImmutableList.<Parameter>builder().add(session).addAll(blocks).add(position).add(output).build());
    method.comment("Projection: %s", projection.toString());
    Scope scope = method.getScope();
    BytecodeBlock body = method.getBody();
    Variable wasNullVariable = scope.declareVariable("wasNull", body, constantFalse());
    BytecodeExpressionVisitor visitor = new BytecodeExpressionVisitor(callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(callSiteBinder), metadata.getFunctionRegistry(), preGeneratedExpressions);
    body.getVariable(output).comment("evaluate projection: " + projection.toString()).append(projection.accept(visitor, scope)).append(generateWrite(callSiteBinder, scope, wasNullVariable, projection.getType())).ret();
    return method;
}
Also used : 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)

Example 29 with BytecodeBlock

use of com.facebook.presto.bytecode.BytecodeBlock 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 30 with BytecodeBlock

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

Aggregations

BytecodeBlock (com.facebook.presto.bytecode.BytecodeBlock)82 Variable (com.facebook.presto.bytecode.Variable)57 MethodDefinition (com.facebook.presto.bytecode.MethodDefinition)43 IfStatement (com.facebook.presto.bytecode.control.IfStatement)42 Parameter (com.facebook.presto.bytecode.Parameter)38 Scope (com.facebook.presto.bytecode.Scope)33 Block (com.facebook.presto.spi.block.Block)23 BytecodeExpression (com.facebook.presto.bytecode.expression.BytecodeExpression)18 LabelNode (com.facebook.presto.bytecode.instruction.LabelNode)18 BytecodeNode (com.facebook.presto.bytecode.BytecodeNode)17 ImmutableList (com.google.common.collect.ImmutableList)16 ForLoop (com.facebook.presto.bytecode.control.ForLoop)12 Type (com.facebook.presto.spi.type.Type)12 ClassDefinition (com.facebook.presto.bytecode.ClassDefinition)11 DictionaryBlock (com.facebook.presto.spi.block.DictionaryBlock)11 LazyBlock (com.facebook.presto.spi.block.LazyBlock)11 RunLengthEncodedBlock (com.facebook.presto.spi.block.RunLengthEncodedBlock)11 BlockBuilder (com.facebook.presto.spi.block.BlockBuilder)10 List (java.util.List)9 RowExpression (com.facebook.presto.sql.relational.RowExpression)7