Search in sources :

Example 11 with Scope

use of io.airlift.bytecode.Scope in project hetu-core by openlookeng.

the class CursorProcessorCompiler method generateProcessMethod.

private static void generateProcessMethod(ClassDefinition classDefinition, int projections) {
    Parameter session = arg("session", ConnectorSession.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), session, 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");
    WhileLoop whileLoop = new WhileLoop().condition(constantTrue()).body(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))).comment("do the projection").append(createProjectIfStatement(classDefinition, method, session, cursor, pageBuilder, projections)).comment("completedPositions++;").incrementVariable(completedPositionsVariable, (byte) 1));
    method.getBody().append(whileLoop).visitLabel(done).append(newInstance(CursorProcessorOutput.class, completedPositionsVariable, finishedVariable).ret());
}
Also used : LabelNode(io.airlift.bytecode.instruction.LabelNode) IfStatement(io.airlift.bytecode.control.IfStatement) Variable(io.airlift.bytecode.Variable) Scope(io.airlift.bytecode.Scope) MethodDefinition(io.airlift.bytecode.MethodDefinition) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) Parameter(io.airlift.bytecode.Parameter) WhileLoop(io.airlift.bytecode.control.WhileLoop) CursorProcessorOutput(io.prestosql.operator.project.CursorProcessorOutput)

Example 12 with Scope

use of io.airlift.bytecode.Scope in project hetu-core by openlookeng.

the class InCodeGenerator method generateExpression.

@Override
public BytecodeNode generateExpression(FunctionHandle functionHandle, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments) {
    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().resolveOperatorFunctionHandle(HASH_CODE, fromTypes(type));
    MethodHandle hashCodeFunction = generatorContext.getFunctionManager().getBuiltInScalarFunctionImplementation(hashCodeHandle).getMethodHandle();
    FunctionHandle isIndeterminateHandle = generatorContext.getFunctionManager().resolveOperatorFunctionHandle(INDETERMINATE, fromTypes(type));
    BuiltInScalarFunctionImplementation isIndeterminateFunction = generatorContext.getFunctionManager().getBuiltInScalarFunctionImplementation(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);
        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, metadata);
            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))).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);
    return block;
}
Also used : LabelNode(io.airlift.bytecode.instruction.LabelNode) Variable(io.airlift.bytecode.Variable) ImmutableList(com.google.common.collect.ImmutableList) ConstantExpression(io.prestosql.spi.relation.ConstantExpression) IfStatement(io.airlift.bytecode.control.IfStatement) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) BytecodeNode(io.airlift.bytecode.BytecodeNode) FunctionHandle(io.prestosql.spi.function.FunctionHandle) BuiltInScalarFunctionImplementation(io.prestosql.spi.function.BuiltInScalarFunctionImplementation) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) RowExpression(io.prestosql.spi.relation.RowExpression) BigintType(io.prestosql.spi.type.BigintType) Type(io.prestosql.spi.type.Type) IntegerType(io.prestosql.spi.type.IntegerType) DateType(io.prestosql.spi.type.DateType) Scope(io.airlift.bytecode.Scope) SwitchBuilder(io.airlift.bytecode.control.SwitchStatement.SwitchBuilder) Collection(java.util.Collection) Map(java.util.Map) MethodHandle(java.lang.invoke.MethodHandle)

Example 13 with Scope

use of io.airlift.bytecode.Scope in project hetu-core by openlookeng.

the class PageFunctionCompiler method generatePageFilterMethod.

private static MethodDefinition generatePageFilterMethod(ClassDefinition classDefinition, FieldDefinition selectedPositionsField) {
    Parameter session = arg("session", ConnectorSession.class);
    Parameter page = arg("page", Page.class);
    MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "filter", type(SelectedPositions.class), ImmutableList.<Parameter>builder().add(session).add(page).build());
    Scope scope = method.getScope();
    Variable thisVariable = method.getThis();
    BytecodeBlock body = method.getBody();
    Variable positionCount = scope.declareVariable("positionCount", body, page.invoke("getPositionCount", int.class));
    body.append(new IfStatement("grow selectedPositions if necessary").condition(lessThan(thisVariable.getField(selectedPositionsField).length(), positionCount)).ifTrue(thisVariable.setField(selectedPositionsField, newArray(type(boolean[].class), positionCount))));
    Variable selectedPositions = scope.declareVariable("selectedPositions", body, thisVariable.getField(selectedPositionsField));
    Variable position = scope.declareVariable(int.class, "position");
    body.append(new ForLoop().initialize(position.set(constantInt(0))).condition(lessThan(position, positionCount)).update(position.increment()).body(selectedPositions.setElement(position, thisVariable.invoke("filter", boolean.class, session, page, position))));
    body.append(invokeStatic(PageFilter.class, "positionsArrayToSelectedPositions", SelectedPositions.class, selectedPositions, positionCount).ret());
    return method;
}
Also used : IfStatement(io.airlift.bytecode.control.IfStatement) Variable(io.airlift.bytecode.Variable) Scope(io.airlift.bytecode.Scope) ForLoop(io.airlift.bytecode.control.ForLoop) MethodDefinition(io.airlift.bytecode.MethodDefinition) SelectedPositions(io.prestosql.operator.project.SelectedPositions) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) Parameter(io.airlift.bytecode.Parameter)

Example 14 with Scope

use of io.airlift.bytecode.Scope in project hetu-core by openlookeng.

the class SwitchCodeGenerator method generateExpression.

@Override
public BytecodeNode generateExpression(FunctionHandle functionHandle, 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 SpecialForm && ((SpecialForm) last).getForm() == 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 SpecialForm && ((SpecialForm) clause).getForm() == WHEN);
        RowExpression operand = ((SpecialForm) clause).getArguments().get(0);
        RowExpression result = ((SpecialForm) clause).getArguments().get(1);
        // call equals(value, operand)
        FunctionHandle equalsFunction = generatorContext.getFunctionManager().resolveOperatorFunctionHandle(EQUAL, fromTypes(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(EQUAL.name(), generatorContext.getFunctionManager().getBuiltInScalarFunctionImplementation(equalsFunction), ImmutableList.of(generatorContext.generate(operand, Optional.empty()), 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(io.airlift.bytecode.instruction.LabelNode) IfStatement(io.airlift.bytecode.control.IfStatement) Variable(io.airlift.bytecode.Variable) Scope(io.airlift.bytecode.Scope) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) RowExpression(io.prestosql.spi.relation.RowExpression) BytecodeNode(io.airlift.bytecode.BytecodeNode) FunctionHandle(io.prestosql.spi.function.FunctionHandle) SpecialForm(io.prestosql.spi.relation.SpecialForm)

Example 15 with Scope

use of io.airlift.bytecode.Scope in project hetu-core by openlookeng.

the class ArrayConstructor method generateArrayConstructor.

private static Class<?> generateArrayConstructor(List<Class<?>> stackTypes, Type elementType) {
    checkCondition(stackTypes.size() <= 254, NOT_SUPPORTED, "Too many arguments for array constructor");
    List<String> stackTypeNames = stackTypes.stream().map(Class::getSimpleName).collect(toImmutableList());
    ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName(Joiner.on("").join(stackTypeNames) + "ArrayConstructor"), type(Object.class));
    // Generate constructor
    definition.declareDefaultConstructor(a(PRIVATE));
    // Generate arrayConstructor()
    ImmutableList.Builder<Parameter> parameters = ImmutableList.builder();
    for (int i = 0; i < stackTypes.size(); i++) {
        Class<?> stackType = stackTypes.get(i);
        parameters.add(arg("arg" + i, stackType));
    }
    MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "arrayConstructor", type(Block.class), parameters.build());
    Scope scope = method.getScope();
    BytecodeBlock body = method.getBody();
    Variable blockBuilderVariable = scope.declareVariable(BlockBuilder.class, "blockBuilder");
    CallSiteBinder binder = new CallSiteBinder();
    BytecodeExpression createBlockBuilder = blockBuilderVariable.set(constantType(binder, elementType).invoke("createBlockBuilder", BlockBuilder.class, constantNull(BlockBuilderStatus.class), constantInt(stackTypes.size())));
    body.append(createBlockBuilder);
    for (int i = 0; i < stackTypes.size(); i++) {
        Variable argument = scope.getVariable("arg" + i);
        IfStatement ifStatement = new IfStatement().condition(equal(argument, constantNull(stackTypes.get(i)))).ifTrue(blockBuilderVariable.invoke("appendNull", BlockBuilder.class).pop()).ifFalse(constantType(binder, elementType).writeValue(blockBuilderVariable, argument.cast(elementType.getJavaType())));
        body.append(ifStatement);
    }
    body.append(blockBuilderVariable.invoke("build", Block.class).ret());
    return defineClass(definition, Object.class, binder.getBindings(), new DynamicClassLoader(ArrayConstructor.class.getClassLoader()));
}
Also used : DynamicClassLoader(io.airlift.bytecode.DynamicClassLoader) Variable(io.airlift.bytecode.Variable) Signature.typeVariable(io.prestosql.spi.function.Signature.typeVariable) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) ImmutableList(com.google.common.collect.ImmutableList) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) ClassDefinition(io.airlift.bytecode.ClassDefinition) IfStatement(io.airlift.bytecode.control.IfStatement) Scope(io.airlift.bytecode.Scope) MethodDefinition(io.airlift.bytecode.MethodDefinition) CallSiteBinder(io.prestosql.sql.gen.CallSiteBinder) Parameter(io.airlift.bytecode.Parameter) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) Block(io.prestosql.spi.block.Block) BytecodeExpression(io.airlift.bytecode.expression.BytecodeExpression) BlockBuilder(io.prestosql.spi.block.BlockBuilder)

Aggregations

Scope (io.airlift.bytecode.Scope)67 Variable (io.airlift.bytecode.Variable)63 BytecodeBlock (io.airlift.bytecode.BytecodeBlock)56 MethodDefinition (io.airlift.bytecode.MethodDefinition)53 Parameter (io.airlift.bytecode.Parameter)49 IfStatement (io.airlift.bytecode.control.IfStatement)44 BytecodeNode (io.airlift.bytecode.BytecodeNode)21 ClassDefinition (io.airlift.bytecode.ClassDefinition)21 ImmutableList (com.google.common.collect.ImmutableList)17 ForLoop (io.airlift.bytecode.control.ForLoop)15 BytecodeExpression (io.airlift.bytecode.expression.BytecodeExpression)14 LabelNode (io.airlift.bytecode.instruction.LabelNode)14 Type (io.prestosql.spi.type.Type)12 Block (io.prestosql.spi.block.Block)11 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)10 CallSiteBinder (io.prestosql.sql.gen.CallSiteBinder)9 Block (io.trino.spi.block.Block)9 VariableInstruction.incrementVariable (io.airlift.bytecode.instruction.VariableInstruction.incrementVariable)8 BlockBuilder (io.prestosql.spi.block.BlockBuilder)8 Type (io.trino.spi.type.Type)8