Search in sources :

Example 21 with BytecodeBlock

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

the class VarArgsToArrayAdapterGenerator method generateVarArgsToArrayAdapter.

public static MethodHandleAndConstructor generateVarArgsToArrayAdapter(Class<?> returnType, Class<?> javaType, int argsLength, MethodHandle function, MethodHandle userStateFactory) {
    requireNonNull(returnType, "returnType is null");
    requireNonNull(javaType, "javaType is null");
    requireNonNull(function, "function is null");
    requireNonNull(userStateFactory, "userStateFactory is null");
    checkCondition(argsLength <= 253, NOT_SUPPORTED, "Too many arguments for vararg function");
    MethodType methodType = function.type();
    Class<?> javaArrayType = toArrayClass(javaType);
    checkArgument(methodType.returnType() == returnType, "returnType does not match");
    checkArgument(methodType.parameterList().equals(ImmutableList.of(Object.class, javaArrayType)), "parameter types do not match");
    CallSiteBinder callSiteBinder = new CallSiteBinder();
    ClassDefinition classDefinition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("VarArgsToListAdapter"), type(Object.class));
    classDefinition.declareDefaultConstructor(a(PRIVATE));
    // generate userState constructor
    MethodDefinition stateFactoryDefinition = classDefinition.declareMethod(a(PUBLIC, STATIC), "createState", type(VarArgsToArrayAdapterState.class));
    stateFactoryDefinition.getBody().comment("create userState for current instance").append(newInstance(VarArgsToArrayAdapterState.class, loadConstant(callSiteBinder, userStateFactory, MethodHandle.class).invoke("invokeExact", Object.class), newArray(type(javaArrayType), argsLength).cast(Object.class)).ret());
    // generate adapter method
    ImmutableList.Builder<Parameter> parameterListBuilder = ImmutableList.builder();
    parameterListBuilder.add(arg("userState", VarArgsToArrayAdapterState.class));
    for (int i = 0; i < argsLength; i++) {
        parameterListBuilder.add(arg("input_" + i, javaType));
    }
    ImmutableList<Parameter> parameterList = parameterListBuilder.build();
    MethodDefinition methodDefinition = classDefinition.declareMethod(a(PUBLIC, STATIC), "varArgsToArray", type(returnType), parameterList);
    BytecodeBlock body = methodDefinition.getBody();
    BytecodeExpression userState = parameterList.get(0).getField("userState", Object.class);
    BytecodeExpression args = parameterList.get(0).getField("args", Object.class).cast(javaArrayType);
    for (int i = 0; i < argsLength; i++) {
        body.append(args.setElement(i, parameterList.get(i + 1)));
    }
    body.append(loadConstant(callSiteBinder, function, MethodHandle.class).invoke("invokeExact", returnType, userState, args).ret());
    // define class
    Class<?> generatedClass = defineClass(classDefinition, Object.class, callSiteBinder.getBindings(), VarArgsToArrayAdapterGenerator.class.getClassLoader());
    return new MethodHandleAndConstructor(Reflection.methodHandle(generatedClass, "varArgsToArray", ImmutableList.builder().add(VarArgsToArrayAdapterState.class).addAll(nCopies(argsLength, javaType)).build().toArray(new Class<?>[argsLength])), Reflection.methodHandle(generatedClass, "createState"));
}
Also used : MethodType(java.lang.invoke.MethodType) ImmutableList(com.google.common.collect.ImmutableList) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) ClassDefinition(io.airlift.bytecode.ClassDefinition) MethodDefinition(io.airlift.bytecode.MethodDefinition) Parameter(io.airlift.bytecode.Parameter) BytecodeExpression(io.airlift.bytecode.expression.BytecodeExpression) MethodHandle(java.lang.invoke.MethodHandle)

Example 22 with BytecodeBlock

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

the class VarArgsToMapAdapterGenerator method generateVarArgsToMapAdapter.

/**
 * Generate byte code that
 * <p><ul>
 * <li>takes a specified number of variables as arguments (types of the arguments are provided in {@code javaTypes})
 * <li>put the variables in a map (keys of the map are provided in {@code names})
 * <li>invoke the provided {@code function} with the map
 * <li>return with the result of the function call (type must match {@code returnType})
 * </ul></p>
 */
public static MethodHandle generateVarArgsToMapAdapter(Class<?> returnType, List<Class<?>> javaTypes, List<String> names, Function<Map<String, Object>, Object> function) {
    checkCondition(javaTypes.size() <= 254, NOT_SUPPORTED, "Too many arguments for vararg function");
    CallSiteBinder callSiteBinder = new CallSiteBinder();
    ClassDefinition classDefinition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("VarArgsToMapAdapter"), type(Object.class));
    ImmutableList.Builder<Parameter> parameterListBuilder = ImmutableList.builder();
    for (int i = 0; i < javaTypes.size(); i++) {
        Class<?> javaType = javaTypes.get(i);
        parameterListBuilder.add(arg("input_" + i, javaType));
    }
    ImmutableList<Parameter> parameterList = parameterListBuilder.build();
    MethodDefinition methodDefinition = classDefinition.declareMethod(a(PUBLIC, STATIC), "varArgsToMap", type(returnType), parameterList);
    BytecodeBlock body = methodDefinition.getBody();
    // ImmutableMap.Builder can not be used here because it doesn't allow nulls.
    Variable map = methodDefinition.getScope().declareVariable("map", methodDefinition.getBody(), invokeStatic(Maps.class, "newHashMapWithExpectedSize", HashMap.class, constantInt(javaTypes.size())));
    for (int i = 0; i < javaTypes.size(); i++) {
        body.append(map.invoke("put", Object.class, constantString(names.get(i)).cast(Object.class), parameterList.get(i).cast(Object.class)));
    }
    body.append(loadConstant(callSiteBinder, function, Function.class).invoke("apply", Object.class, map.cast(Object.class)).cast(returnType).ret());
    Class<?> generatedClass = defineClass(classDefinition, Object.class, callSiteBinder.getBindings(), new DynamicClassLoader(VarArgsToMapAdapterGenerator.class.getClassLoader()));
    return Reflection.methodHandle(generatedClass, "varArgsToMap", javaTypes.toArray(new Class<?>[javaTypes.size()]));
}
Also used : DynamicClassLoader(io.airlift.bytecode.DynamicClassLoader) Variable(io.airlift.bytecode.Variable) HashMap(java.util.HashMap) ImmutableList(com.google.common.collect.ImmutableList) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) ClassDefinition(io.airlift.bytecode.ClassDefinition) Maps(com.google.common.collect.Maps) MethodDefinition(io.airlift.bytecode.MethodDefinition) Parameter(io.airlift.bytecode.Parameter) CompilerUtils.defineClass(io.prestosql.util.CompilerUtils.defineClass)

Example 23 with BytecodeBlock

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

the class BytecodeUtils method unboxPrimitiveIfNecessary.

public static BytecodeBlock unboxPrimitiveIfNecessary(Scope scope, Class<?> boxedType) {
    BytecodeBlock block = new BytecodeBlock();
    LabelNode end = new LabelNode("end");
    Class<?> unboxedType = Primitives.unwrap(boxedType);
    Variable wasNull = scope.getVariable("wasNull");
    if (unboxedType.isPrimitive()) {
        LabelNode notNull = new LabelNode("notNull");
        block.dup(boxedType).ifNotNullGoto(notNull).append(wasNull.set(constantTrue())).comment("swap boxed null with unboxed default").pop(boxedType).pushJavaDefault(unboxedType).gotoLabel(end).visitLabel(notNull).append(unboxPrimitive(unboxedType));
    } else {
        block.dup(boxedType).ifNotNullGoto(end).append(wasNull.set(constantTrue()));
    }
    block.visitLabel(end);
    return block;
}
Also used : LabelNode(io.airlift.bytecode.instruction.LabelNode) Variable(io.airlift.bytecode.Variable) BytecodeBlock(io.airlift.bytecode.BytecodeBlock)

Example 24 with BytecodeBlock

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

the class BytecodeUtils method generateInvocation.

public static BytecodeNode generateInvocation(Scope scope, String name, BuiltInScalarFunctionImplementation function, Optional<BytecodeNode> instance, List<BytecodeNode> arguments, CallSiteBinder binder) {
    LabelNode end = new LabelNode("end");
    BytecodeBlock block = new BytecodeBlock().setDescription("invoke " + name);
    List<Class<?>> stackTypes = new ArrayList<>();
    if (function.getInstanceFactory().isPresent()) {
        checkArgument(instance.isPresent());
    }
    // Index of current parameter in the MethodHandle
    int currentParameterIndex = 0;
    // Index of parameter (without @IsNull) in Presto function
    int realParameterIndex = 0;
    // Go through all the choices in the function and then pick the best one
    List<ScalarImplementationChoice> choices = function.getAllChoices();
    ScalarImplementationChoice bestChoice = null;
    for (ScalarImplementationChoice currentChoice : choices) {
        boolean isValid = true;
        for (int i = 0; i < arguments.size(); i++) {
            if (currentChoice.getArgumentProperty(i).getArgumentType() != VALUE_TYPE) {
                continue;
            }
            if (!(arguments.get(i) instanceof InputReferenceNode) && currentChoice.getArgumentProperty(i).getNullConvention() == NullConvention.BLOCK_AND_POSITION) {
                isValid = false;
                break;
            }
        }
        if (isValid) {
            bestChoice = currentChoice;
        }
    }
    checkState(bestChoice != null, "None of the scalar function implementation choices are valid");
    Binding binding = binder.bind(bestChoice.getMethodHandle());
    MethodType methodType = binding.getType();
    Class<?> returnType = methodType.returnType();
    Class<?> unboxedReturnType = Primitives.unwrap(returnType);
    boolean boundInstance = false;
    while (currentParameterIndex < methodType.parameterArray().length) {
        Class<?> type = methodType.parameterArray()[currentParameterIndex];
        stackTypes.add(type);
        if (bestChoice.getInstanceFactory().isPresent() && !boundInstance) {
            checkState(type.equals(bestChoice.getInstanceFactory().get().type().returnType()), "Mismatched type for instance parameter");
            block.append(instance.get());
            boundInstance = true;
        } else if (type == ConnectorSession.class) {
            block.append(scope.getVariable("session"));
        } else {
            ArgumentProperty argumentProperty = bestChoice.getArgumentProperty(realParameterIndex);
            switch(argumentProperty.getArgumentType()) {
                case VALUE_TYPE:
                    // Apply null convention for value type argument
                    switch(argumentProperty.getNullConvention()) {
                        case RETURN_NULL_ON_NULL:
                            block.append(arguments.get(realParameterIndex));
                            checkArgument(!Primitives.isWrapperType(type), "Non-nullable argument must not be primitive wrapper type");
                            block.append(ifWasNullPopAndGoto(scope, end, unboxedReturnType, Lists.reverse(stackTypes)));
                            break;
                        case USE_NULL_FLAG:
                            block.append(arguments.get(realParameterIndex));
                            block.append(scope.getVariable("wasNull"));
                            block.append(scope.getVariable("wasNull").set(constantFalse()));
                            stackTypes.add(boolean.class);
                            currentParameterIndex++;
                            break;
                        case USE_BOXED_TYPE:
                            block.append(arguments.get(realParameterIndex));
                            block.append(boxPrimitiveIfNecessary(scope, type));
                            block.append(scope.getVariable("wasNull").set(constantFalse()));
                            break;
                        case BLOCK_AND_POSITION:
                            InputReferenceNode inputReferenceNode = (InputReferenceNode) arguments.get(realParameterIndex);
                            block.append(inputReferenceNode.produceBlockAndPosition());
                            stackTypes.add(int.class);
                            currentParameterIndex++;
                            break;
                        default:
                            throw new UnsupportedOperationException(format("Unsupported null convention: %s", argumentProperty.getNullConvention()));
                    }
                    break;
                case FUNCTION_TYPE:
                    block.append(arguments.get(realParameterIndex));
                    break;
                default:
                    throw new UnsupportedOperationException(format("Unsupported argument type: %s", argumentProperty.getArgumentType()));
            }
            realParameterIndex++;
        }
        currentParameterIndex++;
    }
    block.append(invoke(binding, name));
    if (function.isNullable()) {
        block.append(unboxPrimitiveIfNecessary(scope, returnType));
    }
    block.visitLabel(end);
    return block;
}
Also used : LabelNode(io.airlift.bytecode.instruction.LabelNode) MethodType(java.lang.invoke.MethodType) ArgumentProperty(io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentProperty) BytecodeBlock(io.airlift.bytecode.BytecodeBlock) ArrayList(java.util.ArrayList) ScalarImplementationChoice(io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ScalarImplementationChoice) InputReferenceNode(io.prestosql.sql.gen.InputReferenceCompiler.InputReferenceNode) ConnectorSession(io.prestosql.spi.connector.ConnectorSession)

Example 25 with BytecodeBlock

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

the class BytecodeUtils method boxPrimitiveIfNecessary.

public static BytecodeNode boxPrimitiveIfNecessary(Scope scope, Class<?> type) {
    checkArgument(!type.isPrimitive(), "cannot box into primitive type");
    if (!Primitives.isWrapperType(type)) {
        return NOP;
    }
    BytecodeBlock notNull = new BytecodeBlock().comment("box primitive");
    Class<?> expectedCurrentStackType;
    if (type == Long.class) {
        notNull.invokeStatic(Long.class, "valueOf", Long.class, long.class);
        expectedCurrentStackType = long.class;
    } else if (type == Double.class) {
        notNull.invokeStatic(Double.class, "valueOf", Double.class, double.class);
        expectedCurrentStackType = double.class;
    } else if (type == Boolean.class) {
        notNull.invokeStatic(Boolean.class, "valueOf", Boolean.class, boolean.class);
        expectedCurrentStackType = boolean.class;
    } else {
        throw new UnsupportedOperationException("not yet implemented: " + type);
    }
    BytecodeBlock condition = new BytecodeBlock().append(scope.getVariable("wasNull"));
    BytecodeBlock wasNull = new BytecodeBlock().pop(expectedCurrentStackType).pushNull().checkCast(type);
    return new IfStatement().condition(condition).ifTrue(wasNull).ifFalse(notNull);
}
Also used : IfStatement(io.airlift.bytecode.control.IfStatement) BytecodeBlock(io.airlift.bytecode.BytecodeBlock)

Aggregations

BytecodeBlock (io.airlift.bytecode.BytecodeBlock)129 Variable (io.airlift.bytecode.Variable)112 MethodDefinition (io.airlift.bytecode.MethodDefinition)81 Parameter (io.airlift.bytecode.Parameter)73 IfStatement (io.airlift.bytecode.control.IfStatement)69 Scope (io.airlift.bytecode.Scope)56 BytecodeExpression (io.airlift.bytecode.expression.BytecodeExpression)36 BytecodeNode (io.airlift.bytecode.BytecodeNode)31 ClassDefinition (io.airlift.bytecode.ClassDefinition)29 LabelNode (io.airlift.bytecode.instruction.LabelNode)29 ImmutableList (com.google.common.collect.ImmutableList)25 ArrayList (java.util.ArrayList)23 ForLoop (io.airlift.bytecode.control.ForLoop)19 FieldDefinition (io.airlift.bytecode.FieldDefinition)18 Type (io.prestosql.spi.type.Type)15 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)14 Block (io.prestosql.spi.block.Block)14 List (java.util.List)13 BlockBuilder (io.prestosql.spi.block.BlockBuilder)12 Block (io.trino.spi.block.Block)12