Search in sources :

Example 6 with CallSiteBinder

use of io.trino.sql.gen.CallSiteBinder 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 7 with CallSiteBinder

use of io.trino.sql.gen.CallSiteBinder in project trino by trinodb.

the class ArrayTransformFunction method generateTransform.

private static Class<?> generateTransform(Type inputType, Type outputType) {
    CallSiteBinder binder = new CallSiteBinder();
    Class<?> inputJavaType = Primitives.wrap(inputType.getJavaType());
    Class<?> outputJavaType = Primitives.wrap(outputType.getJavaType());
    ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("ArrayTransform"), type(Object.class));
    definition.declareDefaultConstructor(a(PRIVATE));
    // define createPageBuilder
    MethodDefinition createPageBuilderMethod = definition.declareMethod(a(PUBLIC, STATIC), "createPageBuilder", type(PageBuilder.class));
    createPageBuilderMethod.getBody().append(newInstance(PageBuilder.class, constantType(binder, new ArrayType(outputType)).invoke("getTypeParameters", List.class)).ret());
    // define transform method
    Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
    Parameter block = arg("block", Block.class);
    Parameter function = arg("function", UnaryFunctionInterface.class);
    MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "transform", type(Block.class), ImmutableList.of(pageBuilder, 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 blockBuilder = scope.declareVariable(BlockBuilder.class, "blockBuilder");
    Variable inputElement = scope.declareVariable(inputJavaType, "inputElement");
    Variable outputElement = scope.declareVariable(outputJavaType, "outputElement");
    // invoke block.getPositionCount()
    body.append(positionCount.set(block.invoke("getPositionCount", int.class)));
    // reset page builder if it is full
    body.append(new IfStatement().condition(pageBuilder.invoke("isFull", boolean.class)).ifTrue(pageBuilder.invoke("reset", void.class)));
    // get block builder
    body.append(blockBuilder.set(pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, constantInt(0))));
    BytecodeNode loadInputElement;
    if (!inputType.equals(UNKNOWN)) {
        loadInputElement = new IfStatement().condition(block.invoke("isNull", boolean.class, position)).ifTrue(inputElement.set(constantNull(inputJavaType))).ifFalse(inputElement.set(constantType(binder, inputType).getValue(block, position).cast(inputJavaType)));
    } else {
        loadInputElement = new BytecodeBlock().append(inputElement.set(constantNull(inputJavaType)));
    }
    BytecodeNode writeOutputElement;
    if (!outputType.equals(UNKNOWN)) {
        writeOutputElement = new IfStatement().condition(equal(outputElement, constantNull(outputJavaType))).ifTrue(blockBuilder.invoke("appendNull", BlockBuilder.class).pop()).ifFalse(constantType(binder, outputType).writeValue(blockBuilder, outputElement.cast(outputType.getJavaType())));
    } else {
        writeOutputElement = 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) 1)).body(new BytecodeBlock().append(loadInputElement).append(outputElement.set(function.invoke("apply", Object.class, inputElement.cast(Object.class)).cast(outputJavaType))).append(writeOutputElement)));
    body.append(pageBuilder.invoke("declarePositions", void.class, positionCount));
    body.append(blockBuilder.invoke("getRegion", Block.class, subtract(blockBuilder.invoke("getPositionCount", int.class), positionCount), positionCount).ret());
    return defineClass(definition, Object.class, binder.getBindings(), ArrayTransformFunction.class.getClassLoader());
}
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) PageBuilder(io.trino.spi.PageBuilder) ClassDefinition(io.airlift.bytecode.ClassDefinition) ArrayType(io.trino.spi.type.ArrayType) 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) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) BytecodeNode(io.airlift.bytecode.BytecodeNode) BlockBuilder(io.trino.spi.block.BlockBuilder)

Example 8 with CallSiteBinder

use of io.trino.sql.gen.CallSiteBinder in project trino by trinodb.

the class MapTransformKeysFunction method generateTransformKey.

private MethodHandle generateTransformKey(Type keyType, Type transformedKeyType, Type valueType, Type resultMapType) {
    CallSiteBinder binder = new CallSiteBinder();
    Class<?> keyJavaType = Primitives.wrap(keyType.getJavaType());
    Class<?> transformedKeyJavaType = Primitives.wrap(transformedKeyType.getJavaType());
    Class<?> valueJavaType = Primitives.wrap(valueType.getJavaType());
    ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("MapTransformKey"), type(Object.class));
    definition.declareDefaultConstructor(a(PRIVATE));
    Parameter state = arg("state", Object.class);
    Parameter session = arg("session", ConnectorSession.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, session, 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 typedSet = scope.declareVariable(TypedSet.class, "typeSet");
    Variable keyElement = scope.declareVariable(keyJavaType, "keyElement");
    Variable transformedKeyElement = scope.declareVariable(transformedKeyJavaType, "transformedKeyElement");
    Variable valueElement = scope.declareVariable(valueJavaType, "valueElement");
    // 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)));
    // create typed set
    body.append(typedSet.set(invokeStatic(TypedSet.class, "createEqualityTypedSet", TypedSet.class, constantType(binder, transformedKeyType), loadConstant(binder, blockTypeOperators.getEqualOperator(transformedKeyType), BlockPositionEqual.class), loadConstant(binder, blockTypeOperators.getHashCodeOperator(transformedKeyType), BlockPositionHashCode.class), divide(positionCount, constantInt(2)), constantString(NAME))));
    // 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 {
        // make sure invokeExact will not take uninitialized keys during compile time
        loadValueElement = new BytecodeBlock().append(valueElement.set(constantNull(valueJavaType)));
    }
    SqlTypeBytecodeExpression transformedKeySqlType = constantType(binder, transformedKeyType);
    BytecodeNode writeKeyElement;
    BytecodeNode throwDuplicatedKeyException;
    if (!transformedKeyType.equals(UNKNOWN)) {
        writeKeyElement = new BytecodeBlock().append(transformedKeyElement.set(function.invoke("apply", Object.class, keyElement.cast(Object.class), valueElement.cast(Object.class)).cast(transformedKeyJavaType))).append(new IfStatement().condition(equal(transformedKeyElement, constantNull(transformedKeyJavaType))).ifTrue(throwNullKeyException).ifFalse(new BytecodeBlock().append(constantType(binder, transformedKeyType).writeValue(blockBuilder, transformedKeyElement.cast(transformedKeyType.getJavaType()))).append(valueSqlType.invoke("appendTo", void.class, block, add(position, constantInt(1)), blockBuilder))));
        // make sure getObjectValue takes a known key type
        throwDuplicatedKeyException = new BytecodeBlock().append(mapBlockBuilder.invoke("closeEntry", BlockBuilder.class).pop()).append(newInstance(TrinoException.class, getStatic(INVALID_FUNCTION_ARGUMENT.getDeclaringClass(), "INVALID_FUNCTION_ARGUMENT").cast(ErrorCodeSupplier.class), invokeStatic(String.class, "format", String.class, constantString("Duplicate keys (%s) are not allowed"), newArray(type(Object[].class), ImmutableList.of(transformedKeySqlType.invoke("getObjectValue", Object.class, session, blockBuilder.cast(Block.class), position)))))).throwObject();
    } else {
        // key cannot be unknown
        // if we reach this point during runtime, it is an exception
        writeKeyElement = throwNullKeyException;
        throwDuplicatedKeyException = throwNullKeyException;
    }
    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(writeKeyElement).append(new IfStatement().condition(typedSet.invoke("add", boolean.class, blockBuilder.cast(Block.class), position)).ifFalse(throwDuplicatedKeyException))));
    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(), MapTransformKeysFunction.class.getClassLoader());
    return methodHandle(generatedClass, "transform", Object.class, ConnectorSession.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) ErrorCodeSupplier(io.trino.spi.ErrorCodeSupplier) ForLoop(io.airlift.bytecode.control.ForLoop) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) ClassDefinition(io.airlift.bytecode.ClassDefinition) BlockPositionEqual(io.trino.type.BlockTypeOperators.BlockPositionEqual) 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) TrinoException(io.trino.spi.TrinoException) BytecodeNode(io.airlift.bytecode.BytecodeNode) BlockPositionHashCode(io.trino.type.BlockTypeOperators.BlockPositionHashCode) SqlTypeBytecodeExpression(io.trino.sql.gen.SqlTypeBytecodeExpression) BlockBuilder(io.trino.spi.block.BlockBuilder)

Example 9 with CallSiteBinder

use of io.trino.sql.gen.CallSiteBinder in project trino by trinodb.

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) Signature.typeVariable(io.trino.metadata.Signature.typeVariable) Variable(io.airlift.bytecode.Variable) 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.trino.sql.gen.CallSiteBinder) Parameter(io.airlift.bytecode.Parameter) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) Block(io.trino.spi.block.Block) BytecodeExpression(io.airlift.bytecode.expression.BytecodeExpression) BlockBuilder(io.trino.spi.block.BlockBuilder)

Example 10 with CallSiteBinder

use of io.trino.sql.gen.CallSiteBinder in project trino by trinodb.

the class SingleAccessMethodCompiler method compileSingleAccessMethod.

// Note: this currently only handles interfaces, and has no mechanism to declare generic types.
public static <T> T compileSingleAccessMethod(String suggestedClassName, Class<T> interfaceType, MethodHandle methodHandle) {
    ClassDefinition classDefinition = new ClassDefinition(a(PUBLIC, FINAL, SYNTHETIC), makeClassName(suggestedClassName), type(Object.class), type(interfaceType));
    classDefinition.declareDefaultConstructor(a(PUBLIC));
    Method method = getSingleAbstractMethod(interfaceType);
    Class<?>[] parameterTypes = method.getParameterTypes();
    MethodHandle adaptedMethodHandle = methodHandle.asType(methodType(method.getReturnType(), parameterTypes));
    List<io.airlift.bytecode.Parameter> parameters = new ArrayList<>();
    for (int i = 0; i < parameterTypes.length; i++) {
        parameters.add(arg("arg" + i, parameterTypes[i]));
    }
    MethodDefinition methodDefinition = classDefinition.declareMethod(a(PUBLIC), method.getName(), type(method.getReturnType()), parameters);
    CallSiteBinder callSiteBinder = new CallSiteBinder();
    BytecodeExpression invocation = invokeDynamic(BOOTSTRAP_METHOD, ImmutableList.of(callSiteBinder.bind(adaptedMethodHandle).getBindingId()), method.getName(), method.getReturnType(), parameters);
    if (method.getReturnType() != void.class) {
        invocation = invocation.ret();
    }
    methodDefinition.getBody().append(invocation);
    // note this will not work if interface class is not visible from this class loader,
    // but we must use this class loader to ensure the bootstrap method is visible
    ClassLoader classLoader = SingleAccessMethodCompiler.class.getClassLoader();
    Class<? extends T> newClass = defineClass(classDefinition, interfaceType, callSiteBinder.getBindings(), classLoader);
    try {
        return newClass.getDeclaredConstructor().newInstance();
    } catch (ReflectiveOperationException e) {
        throw new RuntimeException(e);
    }
}
Also used : ArrayList(java.util.ArrayList) Method(java.lang.reflect.Method) ClassDefinition(io.airlift.bytecode.ClassDefinition) MethodDefinition(io.airlift.bytecode.MethodDefinition) CallSiteBinder(io.trino.sql.gen.CallSiteBinder) CompilerUtils.defineClass(io.trino.util.CompilerUtils.defineClass) BytecodeExpression(io.airlift.bytecode.expression.BytecodeExpression) MethodHandle(java.lang.invoke.MethodHandle)

Aggregations

ClassDefinition (io.airlift.bytecode.ClassDefinition)11 CallSiteBinder (io.trino.sql.gen.CallSiteBinder)11 MethodDefinition (io.airlift.bytecode.MethodDefinition)8 BytecodeBlock (io.airlift.bytecode.BytecodeBlock)7 Parameter (io.airlift.bytecode.Parameter)7 Scope (io.airlift.bytecode.Scope)7 Variable (io.airlift.bytecode.Variable)7 IfStatement (io.airlift.bytecode.control.IfStatement)6 Block (io.trino.spi.block.Block)6 Signature.typeVariable (io.trino.metadata.Signature.typeVariable)5 BytecodeNode (io.airlift.bytecode.BytecodeNode)4 DynamicClassLoader (io.airlift.bytecode.DynamicClassLoader)4 ForLoop (io.airlift.bytecode.control.ForLoop)4 VariableInstruction.incrementVariable (io.airlift.bytecode.instruction.VariableInstruction.incrementVariable)4 ImmutableList (com.google.common.collect.ImmutableList)3 BytecodeExpression (io.airlift.bytecode.expression.BytecodeExpression)3 BlockBuilder (io.trino.spi.block.BlockBuilder)3 Type (io.trino.spi.type.Type)3 SqlTypeBytecodeExpression (io.trino.sql.gen.SqlTypeBytecodeExpression)3 MethodHandle (java.lang.invoke.MethodHandle)3