use of io.airlift.bytecode.instruction.LabelNode in project trino by trinodb.
the class JoinCompiler method generateRowNotDistinctFromRowMethod.
private void generateRowNotDistinctFromRowMethod(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, List<Type> joinChannelTypes) {
Parameter leftPosition = arg("leftPosition", int.class);
Parameter leftPage = arg("leftPage", Page.class);
Parameter rightPosition = arg("rightPosition", int.class);
Parameter rightPage = arg("rightPage", Page.class);
MethodDefinition rowNotDistinctFromRowMethod = classDefinition.declareMethod(a(PUBLIC), "rowNotDistinctFromRow", type(boolean.class), leftPosition, leftPage, rightPosition, rightPage);
for (int index = 0; index < joinChannelTypes.size(); index++) {
Type type = joinChannelTypes.get(index);
BytecodeExpression leftBlock = leftPage.invoke("getBlock", Block.class, constantInt(index));
BytecodeExpression rightBlock = rightPage.invoke("getBlock", Block.class, constantInt(index));
LabelNode checkNextField = new LabelNode("checkNextField");
rowNotDistinctFromRowMethod.getBody().append(typeDistinctFrom(callSiteBinder, type, leftBlock, leftPosition, rightBlock, rightPosition)).ifFalseGoto(checkNextField).push(false).retBoolean().visitLabel(checkNextField);
}
rowNotDistinctFromRowMethod.getBody().push(true).retInt();
}
use of io.airlift.bytecode.instruction.LabelNode in project trino by trinodb.
the class OrderingCompiler method generatePageIndexCompareTo.
private void generatePageIndexCompareTo(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, List<Type> sortTypes, List<Integer> sortChannels, List<SortOrder> sortOrders) {
Parameter pagesIndex = arg("pagesIndex", PagesIndex.class);
Parameter leftPosition = arg("leftPosition", int.class);
Parameter rightPosition = arg("rightPosition", int.class);
MethodDefinition compareToMethod = classDefinition.declareMethod(a(PUBLIC), "compareTo", type(int.class), pagesIndex, leftPosition, rightPosition);
Scope scope = compareToMethod.getScope();
Variable valueAddresses = scope.declareVariable(LongArrayList.class, "valueAddresses");
compareToMethod.getBody().comment("LongArrayList valueAddresses = pagesIndex.valueAddresses").append(valueAddresses.set(pagesIndex.invoke("getValueAddresses", LongArrayList.class)));
Variable leftPageAddress = scope.declareVariable(long.class, "leftPageAddress");
compareToMethod.getBody().comment("long leftPageAddress = valueAddresses.getLong(leftPosition)").append(leftPageAddress.set(valueAddresses.invoke("getLong", long.class, leftPosition)));
Variable leftBlockIndex = scope.declareVariable(int.class, "leftBlockIndex");
compareToMethod.getBody().comment("int leftBlockIndex = decodeSliceIndex(leftPageAddress)").append(leftBlockIndex.set(invokeStatic(SyntheticAddress.class, "decodeSliceIndex", int.class, leftPageAddress)));
Variable leftBlockPosition = scope.declareVariable(int.class, "leftBlockPosition");
compareToMethod.getBody().comment("int leftBlockPosition = decodePosition(leftPageAddress)").append(leftBlockPosition.set(invokeStatic(SyntheticAddress.class, "decodePosition", int.class, leftPageAddress)));
Variable rightPageAddress = scope.declareVariable(long.class, "rightPageAddress");
compareToMethod.getBody().comment("long rightPageAddress = valueAddresses.getLong(rightPosition);").append(rightPageAddress.set(valueAddresses.invoke("getLong", long.class, rightPosition)));
Variable rightBlockIndex = scope.declareVariable(int.class, "rightBlockIndex");
compareToMethod.getBody().comment("int rightBlockIndex = decodeSliceIndex(rightPageAddress)").append(rightBlockIndex.set(invokeStatic(SyntheticAddress.class, "decodeSliceIndex", int.class, rightPageAddress)));
Variable rightBlockPosition = scope.declareVariable(int.class, "rightBlockPosition");
compareToMethod.getBody().comment("int rightBlockPosition = decodePosition(rightPageAddress)").append(rightBlockPosition.set(invokeStatic(SyntheticAddress.class, "decodePosition", int.class, rightPageAddress)));
for (int i = 0; i < sortChannels.size(); i++) {
int sortChannel = sortChannels.get(i);
SortOrder sortOrder = sortOrders.get(i);
Type sortType = sortTypes.get(i);
MethodHandle compareBlockValue = getBlockPositionOrderingOperator(sortOrder, sortType);
BytecodeBlock block = new BytecodeBlock().setDescription("compare channel " + sortChannel + " " + sortOrder);
BytecodeExpression leftBlock = pagesIndex.invoke("getChannel", ObjectArrayList.class, constantInt(sortChannel)).invoke("get", Object.class, leftBlockIndex).cast(Block.class);
BytecodeExpression rightBlock = pagesIndex.invoke("getChannel", ObjectArrayList.class, constantInt(sortChannel)).invoke("get", Object.class, rightBlockIndex).cast(Block.class);
block.append(invokeDynamic(BOOTSTRAP_METHOD, ImmutableList.of(callSiteBinder.bind(compareBlockValue).getBindingId()), "compareBlockValue", compareBlockValue.type(), leftBlock, leftBlockPosition, rightBlock, rightBlockPosition));
LabelNode equal = new LabelNode("equal");
block.comment("if (compare != 0) return compare").dup().ifZeroGoto(equal).retInt().visitLabel(equal).pop(int.class);
compareToMethod.getBody().append(block);
}
// values are equal
compareToMethod.getBody().push(0).retInt();
}
use of io.airlift.bytecode.instruction.LabelNode in project trino by trinodb.
the class SwitchCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(BytecodeGeneratorContext generatorContext) {
// TODO: compile as
/*
hashCode = hashCode(<value>)
// all constant expressions before a non-constant
switch (hashCode) {
case ...:
if (<value> == <constant1>) {
...
}
else if (<value> == <constant2>) {
...
}
else if (...) {
}
case ...:
...
}
if (<value> == <non-constant1>) {
...
}
else if (<value> == <non-constant2>) {
...
}
...
// repeat with next sequence of constant expressions
*/
Scope scope = generatorContext.getScope();
// process value, else, and all when clauses
BytecodeNode valueBytecode = generatorContext.generate(value);
BytecodeNode elseValue;
if (this.elseValue.isEmpty()) {
elseValue = new BytecodeBlock().append(generatorContext.wasNull().set(constantTrue())).pushJavaDefault(returnType.getJavaType());
} else {
elseValue = generatorContext.generate(this.elseValue.get());
}
// determine the type of the value and result
Class<?> valueType = value.getType().getJavaType();
// evaluate the value and store it in a variable
LabelNode nullValue = new LabelNode("nullCondition");
Variable tempVariable = scope.createTempVariable(valueType);
BytecodeBlock block = new BytecodeBlock().append(valueBytecode).append(BytecodeUtils.ifWasNullClearPopAndGoto(scope, nullValue, void.class, valueType)).putVariable(tempVariable);
BytecodeNode getTempVariableNode = VariableInstruction.loadVariable(tempVariable);
// build the statements
elseValue = new BytecodeBlock().visitLabel(nullValue).append(elseValue);
// reverse list because current if statement builder doesn't support if/else so we need to build the if statements bottom up
for (int i = whenClauses.size() - 1; i >= 0; i--) {
SpecialForm clause = whenClauses.get(i);
RowExpression operand = clause.getArguments().get(0);
RowExpression result = clause.getArguments().get(1);
// call equals(value, operand)
// TODO: what if operand is null? It seems that the call will return "null" (which is cleared below)
// and the code only does the right thing because the value in the stack for that scenario is
// Java's default for boolean == false
// This code should probably be checking for wasNull after the call and "failing" the equality
// check if wasNull is true
BytecodeNode equalsCall = generatorContext.generateCall(equalsFunctions.get(i), ImmutableList.of(generatorContext.generate(operand), getTempVariableNode));
BytecodeBlock condition = new BytecodeBlock().append(equalsCall).append(generatorContext.wasNull().set(constantFalse()));
elseValue = new IfStatement("when").condition(condition).ifTrue(generatorContext.generate(result)).ifFalse(elseValue);
}
return block.append(elseValue);
}
use of io.airlift.bytecode.instruction.LabelNode in project trino by trinodb.
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;
}
use of io.airlift.bytecode.instruction.LabelNode in project trino by trinodb.
the class BytecodeUtils method generateFullInvocation.
private static BytecodeNode generateFullInvocation(Scope scope, String functionName, FunctionNullability functionNullability, List<Boolean> argumentIsFunctionType, Function<InvocationConvention, FunctionInvoker> functionInvokerProvider, Function<MethodHandle, BytecodeNode> instanceFactory, List<Function<Optional<Class<?>>, BytecodeNode>> argumentCompilers, CallSiteBinder binder) {
verify(argumentIsFunctionType.size() == argumentCompilers.size());
List<InvocationArgumentConvention> argumentConventions = new ArrayList<>();
List<BytecodeNode> arguments = new ArrayList<>();
for (int i = 0; i < argumentIsFunctionType.size(); i++) {
if (argumentIsFunctionType.get(i)) {
argumentConventions.add(FUNCTION);
arguments.add(null);
} else {
BytecodeNode argument = argumentCompilers.get(i).apply(Optional.empty());
argumentConventions.add(getPreferredArgumentConvention(argument, argumentCompilers.size(), functionNullability.isArgumentNullable(i)));
arguments.add(argument);
}
}
InvocationConvention invocationConvention = new InvocationConvention(argumentConventions, functionNullability.isReturnNullable() ? NULLABLE_RETURN : FAIL_ON_NULL, true, true);
FunctionInvoker functionInvoker = functionInvokerProvider.apply(invocationConvention);
Binding binding = binder.bind(functionInvoker.getMethodHandle());
LabelNode end = new LabelNode("end");
BytecodeBlock block = new BytecodeBlock().setDescription("invoke " + functionName);
Optional<BytecodeNode> instance = functionInvoker.getInstanceFactory().map(instanceFactory);
// Index of current parameter in the MethodHandle
int currentParameterIndex = 0;
// Index of parameter (without @IsNull) in Trino function
int realParameterIndex = 0;
// Index of function argument types
int lambdaArgumentIndex = 0;
MethodType methodType = binding.getType();
Class<?> returnType = methodType.returnType();
Class<?> unboxedReturnType = Primitives.unwrap(returnType);
List<Class<?>> stackTypes = new ArrayList<>();
boolean instanceIsBound = false;
while (currentParameterIndex < methodType.parameterArray().length) {
Class<?> type = methodType.parameterArray()[currentParameterIndex];
stackTypes.add(type);
if (instance.isPresent() && !instanceIsBound) {
checkState(type.equals(functionInvoker.getInstanceFactory().get().type().returnType()), "Mismatched type for instance parameter");
block.append(instance.get());
instanceIsBound = true;
} else if (type == ConnectorSession.class) {
block.append(scope.getVariable("session"));
} else {
switch(invocationConvention.getArgumentConvention(realParameterIndex)) {
case NEVER_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 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 BOXED_NULLABLE:
block.append(arguments.get(realParameterIndex));
block.append(boxPrimitiveIfNecessary(scope, type));
block.append(scope.getVariable("wasNull").set(constantFalse()));
break;
case BLOCK_POSITION:
InputReferenceNode inputReferenceNode = (InputReferenceNode) arguments.get(realParameterIndex);
block.append(inputReferenceNode.produceBlockAndPosition());
stackTypes.add(int.class);
if (!functionNullability.isArgumentNullable(realParameterIndex)) {
block.append(scope.getVariable("wasNull").set(inputReferenceNode.blockAndPositionIsNull()));
block.append(ifWasNullPopAndGoto(scope, end, unboxedReturnType, Lists.reverse(stackTypes)));
}
currentParameterIndex++;
break;
case FUNCTION:
Class<?> lambdaInterface = functionInvoker.getLambdaInterfaces().get(lambdaArgumentIndex);
block.append(argumentCompilers.get(realParameterIndex).apply(Optional.of(lambdaInterface)));
lambdaArgumentIndex++;
break;
default:
throw new UnsupportedOperationException(format("Unsupported argument conventsion type: %s", invocationConvention.getArgumentConvention(realParameterIndex)));
}
realParameterIndex++;
}
currentParameterIndex++;
}
block.append(invoke(binding, functionName));
if (functionNullability.isReturnNullable()) {
block.append(unboxPrimitiveIfNecessary(scope, returnType));
}
block.visitLabel(end);
return block;
}
Aggregations