@Override public BytecodeNode visitLambda(LambdaDefinitionExpression lambda, Context context) { checkArgument(!context.getOutputBlockVariable().isPresent(), "lambda definition expression does not support writing to block"); checkState(compiledLambdaMap.containsKey(lambda), "lambda expressions map does not contain this lambda definition"); if (!context.lambdaInterface.get().isAnnotationPresent(FunctionalInterface.class)) { // lambdaInterface is checked to be annotated with FunctionalInterface when generating ScalarFunctionImplementation throw new VerifyException("lambda should be generated as class annotated with FunctionalInterface"); } BytecodeGeneratorContext generatorContext = new BytecodeGeneratorContext( RowExpressionCompiler.this, context.getScope(), callSiteBinder, cachedInstanceBinder, registry); return generateLambda( generatorContext, ImmutableList.of(), compiledLambdaMap.get(lambda), context.getLambdaInterface().get()); }
Scope scope = generatorContext.getScope(); BytecodeNode valueBytecode = generatorContext.generate(value, Optional.empty()); BytecodeNode elseValue; whenClauses = arguments.subList(1, arguments.size()); elseValue = new BytecodeBlock() .append(generatorContext.wasNull().set(constantTrue())) .pushJavaDefault(returnType.getJavaType()); elseValue = generatorContext.generate(last, Optional.empty()); Signature equalsFunction = generatorContext.getRegistry().resolveOperator(OperatorType.EQUAL, ImmutableList.of(value.getType(), operand.getType())); BytecodeNode equalsCall = generatorContext.generateCall( equalsFunction.getName(), generatorContext.getRegistry().getScalarFunctionImplementation(equalsFunction), ImmutableList.of(generatorContext.generate(operand, Optional.empty()), getTempVariableNode)); .append(generatorContext.wasNull().set(constantFalse())); .ifTrue(generatorContext.generate(result, Optional.empty())) .ifFalse(elseValue);
static BytecodeNode generateWrite(BytecodeGeneratorContext context, Type returnType, Variable outputBlock) { return BytecodeUtils.generateWrite( context.getCallSiteBinder(), context.getScope(), context.getScope().getVariable("wasNull"), returnType, outputBlock); } }
@Override public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext context, Type returnType, List<RowExpression> arguments, Optional<Variable> outputBlockVariable) { FunctionRegistry registry = context.getRegistry(); ScalarFunctionImplementation function = registry.getScalarFunctionImplementation(signature); List<BytecodeNode> argumentsBytecode = new ArrayList<>(); for (int i = 0; i < arguments.size(); i++) { RowExpression argument = arguments.get(i); ScalarFunctionImplementation.ArgumentProperty argumentProperty = function.getArgumentProperty(i); if (argumentProperty.getArgumentType() == VALUE_TYPE) { argumentsBytecode.add(context.generate(argument, Optional.empty())); } else { argumentsBytecode.add(context.generate(argument, Optional.empty(), Optional.of(argumentProperty.getLambdaInterface()))); } } return context.generateCall( signature.getName(), function, argumentsBytecode, outputBlockVariable.map(variable -> new OutputBlockVariableAndType(variable, returnType))); } }
private static BytecodeNode cast( BytecodeGeneratorContext generatorContext, BytecodeNode argument, Type actualType, TypeSignature requiredType) { if (actualType.getTypeSignature().equals(requiredType)) { return argument; } Signature function = generatorContext .getRegistry() .getCoercion(actualType.getTypeSignature(), requiredType); // TODO: do we need a full function call? (nullability checks, etc) return generatorContext.generateCall(function.getName(), generatorContext.getRegistry().getScalarFunctionImplementation(function), ImmutableList.of(argument)); } }
CallSiteBinder binder = context.getCallSiteBinder(); Scope scope = context.getScope(); List<Type> types = rowType.getTypeParameters(); Variable field = scope.createTempVariable(fieldType.getJavaType()); block.comment("Clean wasNull and Generate + " + i + "-th field of row"); block.append(context.wasNull().set(constantFalse())); block.append(context.generate(arguments.get(i), Optional.empty())); block.putVariable(field); block.append(new IfStatement() .condition(context.wasNull()) .ifTrue(singleRowBlockWriter.invoke("appendNull", BlockBuilder.class).pop()) .ifFalse(constantType(binder, fieldType).writeValue(singleRowBlockWriter, field).pop())); block.append(constantType(binder, rowType).invoke("getObject", Object.class, blockBuilder.cast(Block.class), constantInt(0)) .cast(Block.class)); block.append(context.wasNull().set(constantFalse())); outputBlockVariable.ifPresent(output -> block.append(generateWrite(context, rowType, output))); return block;
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext context, Type returnType, List<RowExpression> arguments, Optional<Variable> outputBlockVariable) { Preconditions.checkArgument(arguments.size() == 3); Variable wasNull = context.wasNull(); BytecodeBlock condition = new BytecodeBlock() .append(context.generate(arguments.get(0), Optional.empty())) .comment("... and condition value was not null") .append(wasNull) .invokeStatic(CompilerOperations.class, "not", boolean.class, boolean.class) .invokeStatic(CompilerOperations.class, "and", boolean.class, boolean.class, boolean.class) .append(wasNull.set(constantFalse())); BytecodeBlock block = new BytecodeBlock() .append(new IfStatement() .condition(condition) .ifTrue(context.generate(arguments.get(1), Optional.empty())) .ifFalse(context.generate(arguments.get(2), Optional.empty()))); outputBlockVariable.ifPresent(output -> block.append(generateWrite(context, returnType, output))); return block; } }
.visitLabel(elseLabel); Variable wasNull = generatorContext.wasNull(); if (checkForNulls) { .append(generatorContext.generateCall(isIndeterminateSignature.getName(), isIndeterminateFunction, ImmutableList.of(value))) .putVariable(wasNull)); Signature equalsSignature = generatorContext.getRegistry().resolveOperator(OperatorType.EQUAL, ImmutableList.of(type, type)); ScalarFunctionImplementation equalsFunction = generatorContext.getRegistry().getScalarFunctionImplementation(equalsSignature); IfStatement test = new IfStatement(); BytecodeNode equalsCall = generatorContext.generateCall( equalsSignature.getName(), equalsFunction,
.visitLabel(elseLabel); Variable wasNull = generatorContext.wasNull(); if (checkForNulls) { elseBlock.append(wasNull.set(caseWasNull)); ScalarFunctionImplementation operator = generatorContext.getRegistry().getScalarFunctionImplementation(internalOperator(EQUAL, BOOLEAN, ImmutableList.of(type, type))); .getCallSiteBinder() .bind(operator.getMethodHandle());
Scope scope = context.getScope(); Class<?> valueType = Primitives.wrap(captureExpression.getType().getJavaType()); Variable valueVariable = scope.createTempVariable(valueType); block.append(context.generate(captureExpression, Optional.empty())); block.append(boxPrimitiveIfNecessary(scope, valueType)); block.putVariable(valueVariable);
public BytecodeNode generateCall(String name, ScalarFunctionImplementation function, List<BytecodeNode> arguments) { return generateCall(name, function, arguments, Optional.empty()); }
public BytecodeNode generate(RowExpression expression, Optional<Variable> outputBlockVariable) { return generate(expression, outputBlockVariable, Optional.empty()); }
@Override public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext context, Type returnType, List<RowExpression> arguments) { checkArgument(arguments.size() == 1, "try methods only contain a single expression"); checkArgument(getOnlyElement(arguments) instanceof CallExpression, "try methods must contain a call expression"); CallExpression innerCallExpression = (CallExpression) getOnlyElement(arguments); checkState(tryMethodsMap.containsKey(innerCallExpression), "try methods map does not contain this try call"); BytecodeBlock bytecodeBlock = new BytecodeBlock() .comment("load required variables") .getVariable(context.getScope().getVariable("this")); inputParameters.stream() .forEach(bytecodeBlock::getVariable); bytecodeBlock.comment("call dynamic try method: " + tryMethodsMap.get(innerCallExpression).getName()) .invokeVirtual(tryMethodsMap.get(innerCallExpression)) .append(unboxPrimitiveIfNecessary(context.getScope(), Primitives.wrap(innerCallExpression.getType().getJavaType()))); return bytecodeBlock; }
CallSiteBinder callSiteBinder = generator.getCallSiteBinder(); Variable wasNull = generator.wasNull(); Variable rowBlock = generator.getScope().createTempVariable(Block.class); int index = (int) ((ConstantExpression) arguments.get(1)).getValue(); block.append(generator.generate(arguments.get(0), Optional.empty())).putVariable(rowBlock);
@Override public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments, Optional<Variable> outputBlockVariable) { Preconditions.checkArgument(arguments.size() == 1); RowExpression argument = arguments.get(0); if (argument.getType().equals(UNKNOWN)) { return loadBoolean(true); } BytecodeNode value = generatorContext.generate(argument, Optional.empty()); // evaluate the expression, pop the produced value, and load the null flag Variable wasNull = generatorContext.wasNull(); BytecodeBlock block = new BytecodeBlock() .comment("is null") .append(value) .pop(argument.getType().getJavaType()) .append(wasNull); // clear the null flag block.append(wasNull.set(constantFalse())); outputBlockVariable.ifPresent(output -> block.append(generateWrite(generatorContext, returnType, output))); return block; } }
@Override public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments, Optional<Variable> outputBlockVariable) { RowExpression argument = arguments.get(0); Signature function = generatorContext .getRegistry() .getCoercion(argument.getType(), returnType); BytecodeBlock block = new BytecodeBlock() .append(generatorContext.generateCall( function.getName(), generatorContext.getRegistry().getScalarFunctionImplementation(function), ImmutableList.of(generatorContext.generate(argument, Optional.empty())))); outputBlockVariable.ifPresent(output -> block.append(generateWrite(generatorContext, returnType, output))); return block; } }
private BytecodeNode cast( BytecodeGeneratorContext generatorContext, BytecodeNode argument, Type actualType, TypeSignature requiredType) { if (actualType.getTypeSignature().equals(requiredType)) { return argument; } Signature function = generatorContext .getRegistry() .getCoercion(actualType.getTypeSignature(), requiredType); // TODO: do we need a full function call? (nullability checks, etc) return generatorContext.generateCall(function.getName(), generatorContext.getRegistry().getScalarFunctionImplementation(function), ImmutableList.of(argument)); } }
Signature hashCodeSignature = generatorContext.getRegistry().resolveOperator(HASH_CODE, ImmutableList.of(type)); MethodHandle hashCodeFunction = generatorContext.getRegistry().getScalarFunctionImplementation(hashCodeSignature).getMethodHandle(); Signature isIndeterminateSignature = generatorContext.getRegistry().resolveOperator(INDETERMINATE, ImmutableList.of(type)); ScalarFunctionImplementation isIndeterminateFunction = generatorContext.getRegistry().getScalarFunctionImplementation(isIndeterminateSignature); BytecodeNode testBytecode = generatorContext.generate(testValue, Optional.empty()); Scope scope = generatorContext.getScope(); Variable value = scope.createTempVariable(javaType); .getCallSiteBinder() .bind(hashCodeFunction); switchBlock = new BytecodeBlock() case SET_CONTAINS: Set<?> constantValuesSet = toFastutilHashSet(constantValues, type, registry); Binding constant = generatorContext.getCallSiteBinder().bind(constantValuesSet, constantValuesSet.getClass()); .append(generatorContext.generate(arguments.get(0), Optional.empty())) .append(ifWasNullPopAndGoto(scope, end, boolean.class, javaType)) .putVariable(value) .setDescription("match") .visitLabel(match) .append(generatorContext.wasNull().set(constantFalse())) .push(true) .gotoLabel(end);
@Override public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments, Optional<Variable> outputBlockVariable) Scope scope = generatorContext.getScope(); BytecodeBlock block = new BytecodeBlock() .comment("check if first arg is null") .append(generatorContext.generate(first, Optional.empty())) .append(ifWasNullPopAndGoto(scope, notMatch, void.class)) .dup(first.getType().getJavaType()) Signature equalsSignature = generatorContext.getRegistry().resolveOperator(OperatorType.EQUAL, ImmutableList.of(firstType, secondType)); ScalarFunctionImplementation equalsFunction = generatorContext.getRegistry().getScalarFunctionImplementation(equalsSignature); BytecodeNode equalsCall = generatorContext.generateCall( equalsSignature.getName(), equalsFunction, ImmutableList.of( cast(generatorContext, firstValue, firstType, equalsSignature.getArgumentTypes().get(0)), cast(generatorContext, generatorContext.generate(second, Optional.empty()), secondType, equalsSignature.getArgumentTypes().get(1)))); .append(generatorContext.wasNull().set(constantTrue())) .pop(first.getType().getJavaType()) .pushJavaDefault(first.getType().getJavaType());