Search in sources :

Example 6 with ForLoop

use of io.airlift.bytecode.control.ForLoop in project trino by trinodb.

the class AccumulatorCompiler method generateBlockNonNullPositionForLoop.

// Generates a for-loop with a local variable named "position" defined, with the current position in the block,
// loopBody will only be executed for non-null positions in the Block
private static BytecodeBlock generateBlockNonNullPositionForLoop(Scope scope, Variable positionVariable, BytecodeBlock loopBody) {
    Variable rowsVariable = scope.declareVariable(int.class, "rows");
    Variable blockVariable = scope.getVariable("block");
    BytecodeBlock block = new BytecodeBlock().append(blockVariable).invokeInterface(Block.class, "getPositionCount", int.class).putVariable(rowsVariable);
    IfStatement ifStatement = new IfStatement("if(!block.isNull(position))").condition(new BytecodeBlock().append(blockVariable).append(positionVariable).invokeInterface(Block.class, "isNull", boolean.class, int.class)).ifFalse(loopBody);
    block.append(new ForLoop().initialize(positionVariable.set(constantInt(0))).condition(new BytecodeBlock().append(positionVariable).append(rowsVariable).invokeStatic(CompilerOperations.class, "lessThan", boolean.class, int.class, int.class)).update(new BytecodeBlock().incrementVariable(positionVariable, (byte) 1)).body(ifStatement));
    return block;
}
Also used : IfStatement(io.airlift.bytecode.control.IfStatement) Variable(io.airlift.bytecode.Variable) ForLoop(io.airlift.bytecode.control.ForLoop) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) Block(io.trino.spi.block.Block) GroupByIdBlock(io.trino.operator.GroupByIdBlock)

Example 7 with ForLoop

use of io.airlift.bytecode.control.ForLoop in project trino by trinodb.

the class MapFilterFunction method generateFilter.

private static MethodHandle generateFilter(MapType mapType) {
    CallSiteBinder binder = new CallSiteBinder();
    Type keyType = mapType.getKeyType();
    Type valueType = mapType.getValueType();
    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 state = arg("state", Object.class);
    Parameter block = arg("block", Block.class);
    Parameter function = arg("function", BinaryFunctionInterface.class);
    MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "filter", type(Block.class), ImmutableList.of(state, 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 pageBuilder = scope.declareVariable(PageBuilder.class, "pageBuilder");
    Variable mapBlockBuilder = scope.declareVariable(BlockBuilder.class, "mapBlockBuilder");
    Variable singleMapBlockWriter = scope.declareVariable(BlockBuilder.class, "singleMapBlockWriter");
    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)));
    // prepare the single map block builder
    body.append(pageBuilder.set(state.cast(PageBuilder.class)));
    body.append(new IfStatement().condition(pageBuilder.invoke("isFull", boolean.class)).ifTrue(pageBuilder.invoke("reset", void.class)));
    body.append(mapBlockBuilder.set(pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, constantInt(0))));
    body.append(singleMapBlockWriter.set(mapBlockBuilder.invoke("beginBlockEntry", BlockBuilder.class)));
    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("apply", Object.class, keyElement.cast(Object.class), valueElement.cast(Object.class)).cast(Boolean.class))).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, singleMapBlockWriter)).append(valueSqlType.invoke("appendTo", void.class, block, add(position, constantInt(1)), singleMapBlockWriter))))));
    body.append(mapBlockBuilder.invoke("closeEntry", BlockBuilder.class).pop());
    body.append(pageBuilder.invoke("declarePosition", void.class));
    body.append(constantType(binder, mapType).invoke("getObject", Object.class, mapBlockBuilder.cast(Block.class), subtract(mapBlockBuilder.invoke("getPositionCount", int.class), constantInt(1))).ret());
    Class<?> generatedClass = defineClass(definition, Object.class, binder.getBindings(), MapFilterFunction.class.getClassLoader());
    return methodHandle(generatedClass, "filter", Object.class, Block.class, BinaryFunctionInterface.class);
}
Also used : Signature.typeVariable(io.trino.metadata.Signature.typeVariable) Variable(io.airlift.bytecode.Variable) VariableInstruction.incrementVariable(io.airlift.bytecode.instruction.VariableInstruction.incrementVariable) ForLoop(io.airlift.bytecode.control.ForLoop) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) ClassDefinition(io.airlift.bytecode.ClassDefinition) IfStatement(io.airlift.bytecode.control.IfStatement) SqlTypeBytecodeExpression.constantType(io.trino.sql.gen.SqlTypeBytecodeExpression.constantType) TypeSignature.mapType(io.trino.spi.type.TypeSignature.mapType) Type(io.trino.spi.type.Type) TypeSignature.functionType(io.trino.spi.type.TypeSignature.functionType) MapType(io.trino.spi.type.MapType) Scope(io.airlift.bytecode.Scope) MethodDefinition(io.airlift.bytecode.MethodDefinition) CallSiteBinder(io.trino.sql.gen.CallSiteBinder) Parameter(io.airlift.bytecode.Parameter) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) Block(io.trino.spi.block.Block) BytecodeNode(io.airlift.bytecode.BytecodeNode) SqlTypeBytecodeExpression(io.trino.sql.gen.SqlTypeBytecodeExpression)

Example 8 with ForLoop

use of io.airlift.bytecode.control.ForLoop in project trino by trinodb.

the class MapTransformValuesFunction method generateTransform.

private static MethodHandle generateTransform(Type keyType, Type valueType, Type transformedValueType, Type resultMapType) {
    CallSiteBinder binder = new CallSiteBinder();
    Class<?> keyJavaType = Primitives.wrap(keyType.getJavaType());
    Class<?> valueJavaType = Primitives.wrap(valueType.getJavaType());
    Class<?> transformedValueJavaType = Primitives.wrap(transformedValueType.getJavaType());
    ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("MapTransformValue"), type(Object.class));
    definition.declareDefaultConstructor(a(PRIVATE));
    // define transform method
    Parameter state = arg("state", Object.class);
    Parameter block = arg("block", Block.class);
    Parameter function = arg("function", BinaryFunctionInterface.class);
    MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "transform", type(Block.class), ImmutableList.of(state, 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 pageBuilder = scope.declareVariable(PageBuilder.class, "pageBuilder");
    Variable mapBlockBuilder = scope.declareVariable(BlockBuilder.class, "mapBlockBuilder");
    Variable blockBuilder = scope.declareVariable(BlockBuilder.class, "blockBuilder");
    Variable keyElement = scope.declareVariable(keyJavaType, "keyElement");
    Variable valueElement = scope.declareVariable(valueJavaType, "valueElement");
    Variable transformedValueElement = scope.declareVariable(transformedValueJavaType, "transformedValueElement");
    // invoke block.getPositionCount()
    body.append(positionCount.set(block.invoke("getPositionCount", int.class)));
    // prepare the single map block builder
    body.append(pageBuilder.set(state.cast(PageBuilder.class)));
    body.append(new IfStatement().condition(pageBuilder.invoke("isFull", boolean.class)).ifTrue(pageBuilder.invoke("reset", void.class)));
    body.append(mapBlockBuilder.set(pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, constantInt(0))));
    body.append(blockBuilder.set(mapBlockBuilder.invoke("beginBlockEntry", BlockBuilder.class)));
    // throw null key exception block
    BytecodeNode throwNullKeyException = new BytecodeBlock().append(newInstance(TrinoException.class, getStatic(INVALID_FUNCTION_ARGUMENT.getDeclaringClass(), "INVALID_FUNCTION_ARGUMENT").cast(ErrorCodeSupplier.class), constantString("map key cannot be null"))).throwObject();
    SqlTypeBytecodeExpression keySqlType = constantType(binder, keyType);
    BytecodeNode loadKeyElement;
    if (!keyType.equals(UNKNOWN)) {
        loadKeyElement = new BytecodeBlock().append(keyElement.set(keySqlType.getValue(block, position).cast(keyJavaType)));
    } else {
        // make sure invokeExact will not take uninitialized keys during compile time
        // but if we reach this point during runtime, it is an exception
        // also close the block builder before throwing as we may be in a TRY() call
        // so that subsequent calls do not find it in an inconsistent state
        loadKeyElement = new BytecodeBlock().append(mapBlockBuilder.invoke("closeEntry", BlockBuilder.class).pop()).append(keyElement.set(constantNull(keyJavaType))).append(throwNullKeyException);
    }
    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)));
    }
    BytecodeNode writeTransformedValueElement;
    if (!transformedValueType.equals(UNKNOWN)) {
        writeTransformedValueElement = new IfStatement().condition(equal(transformedValueElement, constantNull(transformedValueJavaType))).ifTrue(blockBuilder.invoke("appendNull", BlockBuilder.class).pop()).ifFalse(constantType(binder, transformedValueType).writeValue(blockBuilder, transformedValueElement.cast(transformedValueType.getJavaType())));
    } else {
        writeTransformedValueElement = new BytecodeBlock().append(blockBuilder.invoke("appendNull", BlockBuilder.class).pop());
    }
    Variable transformationException = scope.declareVariable(Throwable.class, "transformationException");
    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(new TryCatch("Close builder before throwing to avoid subsequent calls finding it in an inconsistent state if we are in a TRY() call.", transformedValueElement.set(function.invoke("apply", Object.class, keyElement.cast(Object.class), valueElement.cast(Object.class)).cast(transformedValueJavaType)), ImmutableList.of(new TryCatch.CatchBlock(new BytecodeBlock().append(mapBlockBuilder.invoke("closeEntry", BlockBuilder.class).pop()).append(pageBuilder.invoke("declarePosition", void.class)).putVariable(transformationException).append(invokeStatic(Throwables.class, "throwIfUnchecked", void.class, transformationException)).append(newInstance(RuntimeException.class, transformationException)).throwObject(), ImmutableList.of(type(Throwable.class)))))).append(keySqlType.invoke("appendTo", void.class, block, position, blockBuilder)).append(writeTransformedValueElement)));
    body.append(mapBlockBuilder.invoke("closeEntry", BlockBuilder.class).pop());
    body.append(pageBuilder.invoke("declarePosition", void.class));
    body.append(constantType(binder, resultMapType).invoke("getObject", Object.class, mapBlockBuilder.cast(Block.class), subtract(mapBlockBuilder.invoke("getPositionCount", int.class), constantInt(1))).ret());
    Class<?> generatedClass = defineClass(definition, Object.class, binder.getBindings(), MapTransformValuesFunction.class.getClassLoader());
    return methodHandle(generatedClass, "transform", Object.class, Block.class, BinaryFunctionInterface.class);
}
Also used : TryCatch(io.airlift.bytecode.control.TryCatch) Signature.typeVariable(io.trino.metadata.Signature.typeVariable) Variable(io.airlift.bytecode.Variable) VariableInstruction.incrementVariable(io.airlift.bytecode.instruction.VariableInstruction.incrementVariable) ErrorCodeSupplier(io.trino.spi.ErrorCodeSupplier) ForLoop(io.airlift.bytecode.control.ForLoop) Throwables(com.google.common.base.Throwables) 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.trino.sql.gen.CallSiteBinder) Parameter(io.airlift.bytecode.Parameter) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) Block(io.trino.spi.block.Block) BytecodeNode(io.airlift.bytecode.BytecodeNode) SqlTypeBytecodeExpression(io.trino.sql.gen.SqlTypeBytecodeExpression) BlockBuilder(io.trino.spi.block.BlockBuilder)

Example 9 with ForLoop

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

the class AccumulatorCompiler method generateAddInputWindowIndex.

private static void generateAddInputWindowIndex(ClassDefinition definition, List<FieldDefinition> stateField, List<ParameterMetadata> parameterMetadatas, List<Class<?>> lambdaInterfaces, List<FieldDefinition> lambdaProviderFields, MethodHandle inputFunction, CallSiteBinder callSiteBinder) {
    // TODO: implement masking based on maskChannel field once Window Functions support DISTINCT arguments to the functions.
    Parameter index = arg("index", WindowIndex.class);
    Parameter channels = arg("channels", type(List.class, Integer.class));
    Parameter startPosition = arg("startPosition", int.class);
    Parameter endPosition = arg("endPosition", int.class);
    MethodDefinition method = definition.declareMethod(a(PUBLIC), "addInput", type(void.class), ImmutableList.of(index, channels, startPosition, endPosition));
    Scope scope = method.getScope();
    Variable position = scope.declareVariable(int.class, "position");
    Binding binding = callSiteBinder.bind(inputFunction);
    BytecodeExpression invokeInputFunction = invokeDynamic(BOOTSTRAP_METHOD, ImmutableList.of(binding.getBindingId()), "input", binding.getType(), getInvokeFunctionOnWindowIndexParameters(scope, inputFunction.type().parameterArray(), parameterMetadatas, lambdaInterfaces, lambdaProviderFields, stateField, index, channels, position));
    method.getBody().append(new ForLoop().initialize(position.set(startPosition)).condition(BytecodeExpressions.lessThanOrEqual(position, endPosition)).update(position.increment()).body(new IfStatement().condition(anyParametersAreNull(parameterMetadatas, index, channels, position)).ifFalse(invokeInputFunction))).ret();
}
Also used : Binding(io.prestosql.sql.gen.Binding) 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) Parameter(io.airlift.bytecode.Parameter) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) BytecodeExpression(io.airlift.bytecode.expression.BytecodeExpression)

Example 10 with ForLoop

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

the class AccumulatorCompiler method generateBlockNonNullPositionForLoop.

// Generates a for-loop with a local variable named "position" defined, with the current position in the block,
// loopBody will only be executed for non-null positions in the Block
private static BytecodeBlock generateBlockNonNullPositionForLoop(Scope scope, Variable positionVariable, BytecodeBlock loopBody) {
    Variable rowsVariable = scope.declareVariable(int.class, "rows");
    Variable blockVariable = scope.getVariable("block");
    BytecodeBlock block = new BytecodeBlock().append(blockVariable).invokeInterface(Block.class, "getPositionCount", int.class).putVariable(rowsVariable);
    IfStatement ifStatement = new IfStatement("if(!block.isNull(position))").condition(new BytecodeBlock().append(blockVariable).append(positionVariable).invokeInterface(Block.class, "isNull", boolean.class, int.class)).ifFalse(loopBody);
    block.append(new ForLoop().initialize(positionVariable.set(constantInt(0))).condition(new BytecodeBlock().append(positionVariable).append(rowsVariable).invokeStatic(CompilerOperations.class, "lessThan", boolean.class, int.class, int.class)).update(new BytecodeBlock().incrementVariable(positionVariable, (byte) 1)).body(ifStatement));
    return block;
}
Also used : IfStatement(io.airlift.bytecode.control.IfStatement) Variable(io.airlift.bytecode.Variable) ForLoop(io.airlift.bytecode.control.ForLoop) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) GroupByIdBlock(io.prestosql.operator.GroupByIdBlock) Block(io.prestosql.spi.block.Block)

Aggregations

Variable (io.airlift.bytecode.Variable)20 ForLoop (io.airlift.bytecode.control.ForLoop)20 IfStatement (io.airlift.bytecode.control.IfStatement)20 BytecodeBlock (io.airlift.bytecode.BytecodeBlock)18 MethodDefinition (io.airlift.bytecode.MethodDefinition)16 Parameter (io.airlift.bytecode.Parameter)14 Scope (io.airlift.bytecode.Scope)14 BytecodeNode (io.airlift.bytecode.BytecodeNode)10 ClassDefinition (io.airlift.bytecode.ClassDefinition)8 VariableInstruction.incrementVariable (io.airlift.bytecode.instruction.VariableInstruction.incrementVariable)8 Block (io.prestosql.spi.block.Block)7 Block (io.trino.spi.block.Block)7 ImmutableList (com.google.common.collect.ImmutableList)5 List (java.util.List)5 BytecodeExpression (io.airlift.bytecode.expression.BytecodeExpression)4 Signature.typeVariable (io.prestosql.spi.function.Signature.typeVariable)4 CallSiteBinder (io.prestosql.sql.gen.CallSiteBinder)4 Signature.typeVariable (io.trino.metadata.Signature.typeVariable)4 CallSiteBinder (io.trino.sql.gen.CallSiteBinder)4 ArrayList (java.util.ArrayList)4