Search in sources :

Example 16 with IfStatement

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

the class AccumulatorCompiler method generateAddIntermediateAsCombine.

private static void generateAddIntermediateAsCombine(ClassDefinition definition, FieldDefinition stateField, FieldDefinition stateSerializerField, FieldDefinition stateFactoryField, MethodHandle combineFunction, Class<?> singleStateClass, CallSiteBinder callSiteBinder, boolean grouped) {
    MethodDefinition method = declareAddIntermediate(definition, grouped);
    Scope scope = method.getScope();
    BytecodeBlock body = method.getBody();
    Variable thisVariable = method.getThis();
    Variable block = scope.getVariable("block");
    Variable scratchState = scope.declareVariable(singleStateClass, "scratchState");
    Variable position = scope.declareVariable(int.class, "position");
    body.comment("scratchState = stateFactory.createSingleState();").append(thisVariable.getField(stateFactoryField)).invokeInterface(AccumulatorStateFactory.class, "createSingleState", Object.class).checkCast(scratchState.getType()).putVariable(scratchState);
    if (grouped) {
        generateEnsureCapacity(scope, stateField, body);
    }
    BytecodeBlock loopBody = new BytecodeBlock();
    if (grouped) {
        Variable groupIdsBlock = scope.getVariable("groupIdsBlock");
        loopBody.append(thisVariable.getField(stateField).invoke("setGroupId", void.class, groupIdsBlock.invoke("getGroupId", long.class, position)));
    }
    loopBody.append(thisVariable.getField(stateSerializerField).invoke("deserialize", void.class, block, position, scratchState.cast(Object.class)));
    loopBody.comment("combine(state, scratchState)").append(thisVariable.getField(stateField)).append(scratchState).append(invoke(callSiteBinder.bind(combineFunction), "combine"));
    if (grouped) {
        // skip rows with null group id
        IfStatement ifStatement = new IfStatement("if (!groupIdsBlock.isNull(position))").condition(not(scope.getVariable("groupIdsBlock").invoke("isNull", boolean.class, position))).ifTrue(loopBody);
        loopBody = new BytecodeBlock().append(ifStatement);
    }
    body.append(generateBlockNonNullPositionForLoop(scope, position, loopBody)).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)

Example 17 with IfStatement

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

the class RowToRowCast method generateRowCast.

private static Class<?> generateRowCast(Type fromType, Type toType, FunctionRegistry functionRegistry) {
    List<Type> toTypes = toType.getTypeParameters();
    List<Type> fromTypes = fromType.getTypeParameters();
    CallSiteBinder binder = new CallSiteBinder();
    // Embed the MD5 hash code of input and output types into the generated class name instead of the raw type names,
    // which could prevent the class name from hitting the length limitation and invalid characters.
    byte[] md5Suffix = Hashing.md5().hashBytes((fromType + "$" + toType).getBytes()).asBytes();
    ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), CompilerUtils.makeClassName(Joiner.on("$").join("RowCast", BaseEncoding.base16().encode(md5Suffix))), type(Object.class));
    Parameter session = arg("session", ConnectorSession.class);
    Parameter value = arg("value", Block.class);
    MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "castRow", type(Block.class), session, value);
    Scope scope = method.getScope();
    BytecodeBlock body = method.getBody();
    Variable wasNull = scope.declareVariable(boolean.class, "wasNull");
    Variable blockBuilder = scope.createTempVariable(BlockBuilder.class);
    body.append(wasNull.set(constantBoolean(false)));
    CachedInstanceBinder cachedInstanceBinder = new CachedInstanceBinder(definition, binder);
    // create the interleave block builder
    body.newObject(InterleavedBlockBuilder.class).dup().append(constantType(binder, toType).invoke("getTypeParameters", List.class)).append(newInstance(BlockBuilderStatus.class)).append(constantInt(toTypes.size())).invokeConstructor(InterleavedBlockBuilder.class, List.class, BlockBuilderStatus.class, int.class).putVariable(blockBuilder);
    // loop through to append member blocks
    for (int i = 0; i < toTypes.size(); i++) {
        Signature signature = internalOperator(CAST.name(), toTypes.get(i).getTypeSignature(), ImmutableList.of(fromTypes.get(i).getTypeSignature()));
        ScalarFunctionImplementation function = functionRegistry.getScalarFunctionImplementation(signature);
        Type currentFromType = fromTypes.get(i);
        if (currentFromType.equals(UNKNOWN)) {
            body.append(blockBuilder.invoke("appendNull", BlockBuilder.class).pop());
            continue;
        }
        BytecodeExpression fromElement = constantType(binder, currentFromType).getValue(value, constantInt(i));
        BytecodeExpression toElement = invokeFunction(scope, cachedInstanceBinder, signature.getName(), function, fromElement);
        IfStatement ifElementNull = new IfStatement("if the element in the row type is null...");
        ifElementNull.condition(value.invoke("isNull", boolean.class, constantInt(i))).ifTrue(blockBuilder.invoke("appendNull", BlockBuilder.class).pop()).ifFalse(constantType(binder, toTypes.get(i)).writeValue(blockBuilder, toElement));
        body.append(ifElementNull);
    }
    // call blockBuilder.build()
    body.append(blockBuilder.invoke("build", Block.class)).retObject();
    // create constructor
    MethodDefinition constructorDefinition = definition.declareConstructor(a(PUBLIC));
    BytecodeBlock constructorBody = constructorDefinition.getBody();
    Variable thisVariable = constructorDefinition.getThis();
    constructorBody.comment("super();").append(thisVariable).invokeConstructor(Object.class);
    cachedInstanceBinder.generateInitializations(thisVariable, constructorBody);
    constructorBody.ret();
    return defineClass(definition, Object.class, binder.getBindings(), RowToRowCast.class.getClassLoader());
}
Also used : Variable(com.facebook.presto.bytecode.Variable) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) ClassDefinition(com.facebook.presto.bytecode.ClassDefinition) InterleavedBlockBuilder(com.facebook.presto.spi.block.InterleavedBlockBuilder) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Type(com.facebook.presto.spi.type.Type) SqlTypeBytecodeExpression.constantType(com.facebook.presto.sql.gen.SqlTypeBytecodeExpression.constantType) CachedInstanceBinder(com.facebook.presto.sql.gen.CachedInstanceBinder) Scope(com.facebook.presto.bytecode.Scope) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) CallSiteBinder(com.facebook.presto.sql.gen.CallSiteBinder) Signature(com.facebook.presto.metadata.Signature) TypeSignature.parseTypeSignature(com.facebook.presto.spi.type.TypeSignature.parseTypeSignature) 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) BytecodeExpression(com.facebook.presto.bytecode.expression.BytecodeExpression) BlockBuilderStatus(com.facebook.presto.spi.block.BlockBuilderStatus) BlockBuilder(com.facebook.presto.spi.block.BlockBuilder) InterleavedBlockBuilder(com.facebook.presto.spi.block.InterleavedBlockBuilder)

Example 18 with IfStatement

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

the class CursorProcessorCompiler method generateProcessMethod.

private static void generateProcessMethod(ClassDefinition classDefinition, int projections, Map<VariableReferenceExpression, CommonSubExpressionFields> cseFields) {
    Parameter properties = arg("properties", SqlFunctionProperties.class);
    Parameter yieldSignal = arg("yieldSignal", DriverYieldSignal.class);
    Parameter cursor = arg("cursor", RecordCursor.class);
    Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
    MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "process", type(CursorProcessorOutput.class), properties, yieldSignal, cursor, pageBuilder);
    Scope scope = method.getScope();
    Variable completedPositionsVariable = scope.declareVariable(int.class, "completedPositions");
    Variable finishedVariable = scope.declareVariable(boolean.class, "finished");
    method.getBody().comment("int completedPositions = 0;").putVariable(completedPositionsVariable, 0).comment("boolean finished = false;").putVariable(finishedVariable, false);
    // while loop loop body
    LabelNode done = new LabelNode("done");
    BytecodeBlock whileFunctionBlock = new BytecodeBlock().comment("if (pageBuilder.isFull() || yieldSignal.isSet()) return new CursorProcessorOutput(completedPositions, false);").append(new IfStatement().condition(or(pageBuilder.invoke("isFull", boolean.class), yieldSignal.invoke("isSet", boolean.class))).ifTrue(jump(done))).comment("if (!cursor.advanceNextPosition()) return new CursorProcessorOutput(completedPositions, true);").append(new IfStatement().condition(cursor.invoke("advanceNextPosition", boolean.class)).ifFalse(new BytecodeBlock().putVariable(finishedVariable, true).gotoLabel(done)));
    // reset the CSE evaluatedField = false for every row
    cseFields.values().forEach(field -> whileFunctionBlock.append(scope.getThis().setField(field.getEvaluatedField(), constantBoolean(false))));
    whileFunctionBlock.comment("do the projection").append(createProjectIfStatement(classDefinition, method, properties, cursor, pageBuilder, projections)).comment("completedPositions++;").incrementVariable(completedPositionsVariable, (byte) 1);
    WhileLoop whileLoop = new WhileLoop().condition(constantTrue()).body(whileFunctionBlock);
    method.getBody().append(whileLoop).visitLabel(done).append(newInstance(CursorProcessorOutput.class, completedPositionsVariable, finishedVariable).ret());
}
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) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) Parameter(com.facebook.presto.bytecode.Parameter) WhileLoop(com.facebook.presto.bytecode.control.WhileLoop) CursorProcessorOutput(com.facebook.presto.operator.project.CursorProcessorOutput)

Example 19 with IfStatement

use of com.facebook.presto.bytecode.control.IfStatement 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 20 with IfStatement

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

the class InCodeGenerator method buildInCase.

private static BytecodeBlock buildInCase(BytecodeGeneratorContext generatorContext, Scope scope, Type type, LabelNode matchLabel, LabelNode noMatchLabel, Variable value, Collection<BytecodeNode> testValues, boolean checkForNulls, JavaScalarFunctionImplementation isIndeterminateFunction) {
    // caseWasNull is set to true the first time a null in `testValues` is encountered
    Variable caseWasNull = null;
    if (checkForNulls) {
        caseWasNull = scope.createTempVariable(boolean.class);
    }
    BytecodeBlock caseBlock = new BytecodeBlock();
    if (checkForNulls) {
        caseBlock.putVariable(caseWasNull, false);
    }
    LabelNode elseLabel = new LabelNode("else");
    BytecodeBlock elseBlock = new BytecodeBlock().visitLabel(elseLabel);
    Variable wasNull = generatorContext.wasNull();
    if (checkForNulls) {
        // That is incorrect. Doing an explicit check for indeterminate is required to correctly return NULL.
        if (testValues.isEmpty()) {
            elseBlock.append(new BytecodeBlock().append(generatorContext.generateCall(INDETERMINATE.name(), isIndeterminateFunction, ImmutableList.of(value))).putVariable(wasNull));
        } else {
            elseBlock.append(wasNull.set(caseWasNull));
        }
    }
    elseBlock.gotoLabel(noMatchLabel);
    FunctionHandle equalsHandle = generatorContext.getFunctionManager().resolveOperator(EQUAL, fromTypes(type, type));
    JavaScalarFunctionImplementation equalsFunction = generatorContext.getFunctionManager().getJavaScalarFunctionImplementation(equalsHandle);
    BytecodeNode elseNode = elseBlock;
    for (BytecodeNode testNode : testValues) {
        LabelNode testLabel = new LabelNode("test");
        IfStatement test = new IfStatement();
        BytecodeNode equalsCall = generatorContext.generateCall(EQUAL.name(), equalsFunction, ImmutableList.of(value, testNode));
        test.condition().visitLabel(testLabel).append(equalsCall);
        if (checkForNulls) {
            IfStatement wasNullCheck = new IfStatement("if wasNull, set caseWasNull to true, clear wasNull, pop boolean, and goto next test value");
            wasNullCheck.condition(wasNull);
            wasNullCheck.ifTrue(new BytecodeBlock().append(caseWasNull.set(constantTrue())).append(wasNull.set(constantFalse())).pop(boolean.class).gotoLabel(elseLabel));
            test.condition().append(wasNullCheck);
        }
        test.ifTrue().gotoLabel(matchLabel);
        test.ifFalse(elseNode);
        elseNode = test;
        elseLabel = testLabel;
    }
    caseBlock.append(elseNode);
    return caseBlock;
}
Also used : LabelNode(com.facebook.presto.bytecode.instruction.LabelNode) JavaScalarFunctionImplementation(com.facebook.presto.spi.function.JavaScalarFunctionImplementation) IfStatement(com.facebook.presto.bytecode.control.IfStatement) Variable(com.facebook.presto.bytecode.Variable) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode) FunctionHandle(com.facebook.presto.spi.function.FunctionHandle)

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