Search in sources :

Example 26 with MethodDefinition

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

the class StateCompiler method generateSingleStateClass.

private static <T> Class<? extends T> generateSingleStateClass(Class<T> clazz, Map<String, Type> fieldTypes, DynamicClassLoader classLoader) {
    ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("Single" + clazz.getSimpleName()), type(Object.class), type(clazz), type(Restorable.class));
    FieldDefinition instanceSize = generateInstanceSize(definition);
    // Add getter for class size
    definition.declareMethod(a(PUBLIC), "getEstimatedSize", type(long.class)).getBody().getStaticField(instanceSize).retLong();
    // Generate constructor
    MethodDefinition constructor = definition.declareConstructor(a(PUBLIC));
    constructor.getBody().append(constructor.getThis()).invokeConstructor(Object.class);
    // Generate fields
    List<StateField> fields = enumerateFields(clazz, fieldTypes);
    for (StateField field : fields) {
        generateField(definition, constructor, field);
    }
    constructor.getBody().ret();
    Parameter captureSerdeProvider = arg("serdeProvider", BlockEncodingSerdeProvider.class);
    MethodDefinition capture = definition.declareMethod(a(PUBLIC), "capture", type(Object.class), captureSerdeProvider);
    Variable myState = capture.getScope().declareVariable(List.class, "myState");
    capture.getBody().append(myState.set(newInstance(ArrayList.class)));
    Variable captureBlockEncodingSerde = capture.getScope().declareVariable(BlockEncodingSerde.class, "captureBlockEncodingSerde");
    capture.getBody().append(captureBlockEncodingSerde.set(captureSerdeProvider.invoke("getBlockEncodingSerde", BlockEncodingSerde.class)));
    Variable obj = capture.getScope().declareVariable(Object.class, "obj");
    for (int i = 1; i < definition.getFields().size(); i++) {
        capture.getBody().append(obj.set(invokeStatic(SnapshotUtils.class, "captureHelper", Object.class, capture.getThis().getField(definition.getFields().get(i)).cast(Object.class), captureSerdeProvider)));
        capture.getBody().append(myState.invoke("add", boolean.class, obj));
    }
    capture.getBody().append(myState.ret());
    Parameter state = arg("state", Object.class);
    Parameter restoreSerdeProvider = arg("serdeProvider", BlockEncodingSerdeProvider.class);
    MethodDefinition restore = definition.declareMethod(a(PUBLIC), "restore", type(void.class), state, restoreSerdeProvider);
    Variable restoreBlockEncodingSerde = restore.getScope().declareVariable(BlockEncodingSerde.class, "restoreBlockEncodingSerde");
    restore.getBody().append(restoreBlockEncodingSerde.set(restoreSerdeProvider.invoke("getBlockEncodingSerde", BlockEncodingSerde.class)));
    Variable restoreState = restore.getScope().declareVariable(List.class, "restoreState");
    restore.getBody().append(restoreState.set(state.cast(List.class)));
    Variable value = restore.getScope().declareVariable(Object.class, "value");
    for (int i = 0; i < fields.size(); i++) {
        restore.getBody().append(value.set(restoreState.invoke("get", Object.class, constantInt(i))));
        restore.getBody().append(value.set(invokeStatic(SnapshotUtils.class, "restoreHelper", Object.class, value, constantClass(fields.get(i).getType()), restoreSerdeProvider)));
        restore.getBody().append(restore.getThis().invoke(fields.get(i).getSetterName(), void.class, value.cast(fields.get(i).getType())));
    }
    restore.getBody().ret();
    return defineClass(definition, clazz, classLoader);
}
Also used : Variable(io.airlift.bytecode.Variable) MethodDefinition(io.airlift.bytecode.MethodDefinition) FieldDefinition(io.airlift.bytecode.FieldDefinition) Parameter(io.airlift.bytecode.Parameter) ClassDefinition(io.airlift.bytecode.ClassDefinition) Restorable(io.prestosql.spi.snapshot.Restorable)

Example 27 with MethodDefinition

use of io.airlift.bytecode.MethodDefinition 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)

Example 28 with MethodDefinition

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

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 : Variable(io.airlift.bytecode.Variable) VariableInstruction.incrementVariable(io.airlift.bytecode.instruction.VariableInstruction.incrementVariable) Signature.typeVariable(io.prestosql.spi.function.Signature.typeVariable) 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.prestosql.sql.gen.SqlTypeBytecodeExpression.constantType) Type(io.prestosql.spi.type.Type) MapType(io.prestosql.spi.type.MapType) Scope(io.airlift.bytecode.Scope) MethodDefinition(io.airlift.bytecode.MethodDefinition) CallSiteBinder(io.prestosql.sql.gen.CallSiteBinder) TypeSignatureParameter(io.prestosql.spi.type.TypeSignatureParameter) Parameter(io.airlift.bytecode.Parameter) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) Block(io.prestosql.spi.block.Block) BytecodeNode(io.airlift.bytecode.BytecodeNode) SqlTypeBytecodeExpression(io.prestosql.sql.gen.SqlTypeBytecodeExpression)

Example 29 with MethodDefinition

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

the class MapTransformValueFunction 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(PrestoException.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());
    }
    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(transformedValueElement.set(function.invoke("apply", Object.class, keyElement.cast(Object.class), valueElement.cast(Object.class)).cast(transformedValueJavaType))).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(), MapTransformValueFunction.class.getClassLoader());
    return methodHandle(generatedClass, "transform", Object.class, Block.class, BinaryFunctionInterface.class);
}
Also used : Variable(io.airlift.bytecode.Variable) VariableInstruction.incrementVariable(io.airlift.bytecode.instruction.VariableInstruction.incrementVariable) Signature.typeVariable(io.prestosql.spi.function.Signature.typeVariable) ErrorCodeSupplier(io.prestosql.spi.ErrorCodeSupplier) ForLoop(io.airlift.bytecode.control.ForLoop) 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) TypeSignatureParameter(io.prestosql.spi.type.TypeSignatureParameter) Parameter(io.airlift.bytecode.Parameter) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) Block(io.prestosql.spi.block.Block) BytecodeNode(io.airlift.bytecode.BytecodeNode) SqlTypeBytecodeExpression(io.prestosql.sql.gen.SqlTypeBytecodeExpression) BlockBuilder(io.prestosql.spi.block.BlockBuilder)

Example 30 with MethodDefinition

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

the class StateCompiler method generateField.

private static void generateField(ClassDefinition definition, MethodDefinition constructor, StateField stateField) {
    FieldDefinition field = definition.declareField(a(PRIVATE), UPPER_CAMEL.to(LOWER_CAMEL, stateField.getName()) + "Value", stateField.getType());
    // Generate getter
    MethodDefinition getter = definition.declareMethod(a(PUBLIC), stateField.getGetterName(), type(stateField.getType()));
    getter.getBody().append(getter.getThis().getField(field).ret());
    // Generate setter
    Parameter value = arg("value", stateField.getType());
    MethodDefinition setter = definition.declareMethod(a(PUBLIC), stateField.getSetterName(), type(void.class), value);
    setter.getBody().append(setter.getThis().setField(field, value)).ret();
    constructor.getBody().append(constructor.getThis().setField(field, stateField.initialValueExpression()));
}
Also used : MethodDefinition(io.airlift.bytecode.MethodDefinition) FieldDefinition(io.airlift.bytecode.FieldDefinition) Parameter(io.airlift.bytecode.Parameter)

Aggregations

MethodDefinition (io.airlift.bytecode.MethodDefinition)126 Parameter (io.airlift.bytecode.Parameter)104 Variable (io.airlift.bytecode.Variable)102 BytecodeBlock (io.airlift.bytecode.BytecodeBlock)83 Scope (io.airlift.bytecode.Scope)53 BytecodeExpression (io.airlift.bytecode.expression.BytecodeExpression)52 IfStatement (io.airlift.bytecode.control.IfStatement)45 ClassDefinition (io.airlift.bytecode.ClassDefinition)32 FieldDefinition (io.airlift.bytecode.FieldDefinition)28 BytecodeNode (io.airlift.bytecode.BytecodeNode)24 ImmutableList (com.google.common.collect.ImmutableList)21 ArrayList (java.util.ArrayList)20 LabelNode (io.airlift.bytecode.instruction.LabelNode)19 ForLoop (io.airlift.bytecode.control.ForLoop)17 Type (io.trino.spi.type.Type)15 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)13 List (java.util.List)13 Block (io.prestosql.spi.block.Block)12 BlockBuilder (io.prestosql.spi.block.BlockBuilder)12 SqlTypeBytecodeExpression.constantType (io.trino.sql.gen.SqlTypeBytecodeExpression.constantType)12