use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.
the class AccumulatorCompiler method generateConstructor.
private static void generateConstructor(ClassDefinition definition, List<StateFieldAndDescriptor> stateFieldAndDescriptors, List<FieldDefinition> inputChannelFields, FieldDefinition maskChannelField, List<FieldDefinition> lambdaProviderFields, boolean grouped) {
Parameter stateDescriptors = arg("stateDescriptors", type(List.class, AccumulatorStateDescriptor.class));
Parameter inputChannels = arg("inputChannels", type(List.class, Integer.class));
Parameter maskChannel = arg("maskChannel", type(Optional.class, Integer.class));
Parameter lambdaProviders = arg("lambdaProviders", type(List.class, LambdaProvider.class));
MethodDefinition method = definition.declareConstructor(a(PUBLIC), stateDescriptors, inputChannels, maskChannel, lambdaProviders);
BytecodeBlock body = method.getBody();
Variable thisVariable = method.getThis();
body.comment("super();").append(thisVariable).invokeConstructor(Object.class);
for (int i = 0; i < stateFieldAndDescriptors.size(); i++) {
body.append(thisVariable.setField(stateFieldAndDescriptors.get(i).getStateSerializerField(), stateDescriptors.invoke("get", Object.class, constantInt(i)).cast(AccumulatorStateDescriptor.class).invoke("getSerializer", AccumulatorStateSerializer.class)));
body.append(thisVariable.setField(stateFieldAndDescriptors.get(i).getStateFactoryField(), stateDescriptors.invoke("get", Object.class, constantInt(i)).cast(AccumulatorStateDescriptor.class).invoke("getFactory", AccumulatorStateFactory.class)));
}
for (int i = 0; i < lambdaProviderFields.size(); i++) {
body.append(thisVariable.setField(lambdaProviderFields.get(i), lambdaProviders.invoke("get", Object.class, constantInt(i)).cast(LambdaProvider.class)));
}
body.append(thisVariable.setField(maskChannelField, invokeStatic(type(CompilerOperations.class), "optionalChannelToIntOrNegative", type(int.class), ImmutableList.of(type(Optional.class, Integer.class)), generateRequireNotNull(maskChannel))));
// Validate inputChannels argument list
body.append(generateRequireNotNull(inputChannels)).push(inputChannelFields.size()).invokeStatic(type(CompilerOperations.class), "validateChannelsListLength", type(void.class), ImmutableList.of(type(List.class, Integer.class), type(int.class)));
// Initialize inputChannels fields
if (!inputChannelFields.isEmpty()) {
// Assign each inputChannel field from the list or assign -1 if the input list is empty (eg: intermediate aggregations don't use the input parameters)
BytecodeBlock assignFromList = new BytecodeBlock().comment("(this.inputChannel = %s.get(i), ...)", inputChannels.getName());
BytecodeBlock assignNegative = new BytecodeBlock().comment("(this.inputChannel = -1, ...)");
for (int i = 0; i < inputChannelFields.size(); i++) {
FieldDefinition inputChannelField = inputChannelFields.get(i);
assignFromList.append(thisVariable.setField(inputChannelField, inputChannels.invoke("get", Object.class, constantInt(i)).cast(int.class)));
assignNegative.append(thisVariable.setField(inputChannelField, constantInt(-1)));
}
body.append(new IfStatement("if(%s.isEmpty())", inputChannels.getName()).condition(new BytecodeBlock().append(inputChannels).invokeInterface(List.class, "isEmpty", boolean.class)).ifTrue(assignNegative).ifFalse(assignFromList));
}
String createState;
if (grouped) {
createState = "createGroupedState";
} else {
createState = "createSingleState";
}
for (StateFieldAndDescriptor stateFieldAndDescriptor : stateFieldAndDescriptors) {
FieldDefinition stateField = stateFieldAndDescriptor.getStateField();
BytecodeExpression stateFactory = thisVariable.getField(stateFieldAndDescriptor.getStateFactoryField());
body.append(thisVariable.setField(stateField, stateFactory.invoke(createState, Object.class).cast(stateField.getType())));
}
body.ret();
}
use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.
the class AccumulatorCompiler method generateInputForLoop.
private static BytecodeBlock generateInputForLoop(List<FieldDefinition> stateField, List<ParameterMetadata> parameterMetadatas, MethodHandle inputFunction, Scope scope, List<Variable> parameterVariables, List<Class> lambdaInterfaces, List<FieldDefinition> lambdaProviderFields, Variable masksBlock, CallSiteBinder callSiteBinder, boolean grouped) {
// For-loop over rows
Variable page = scope.getVariable("page");
Variable positionVariable = scope.declareVariable(int.class, "position");
Variable rowsVariable = scope.declareVariable(int.class, "rows");
BytecodeBlock block = new BytecodeBlock().append(page).invokeVirtual(Page.class, "getPositionCount", int.class).putVariable(rowsVariable).initializeVariable(positionVariable);
BytecodeNode loopBody = generateInvokeInputFunction(scope, stateField, positionVariable, parameterVariables, parameterMetadatas, lambdaInterfaces, lambdaProviderFields, inputFunction, callSiteBinder, grouped);
// Wrap with null checks
List<Boolean> nullable = new ArrayList<>();
for (ParameterMetadata metadata : parameterMetadatas) {
switch(metadata.getParameterType()) {
case INPUT_CHANNEL:
case BLOCK_INPUT_CHANNEL:
nullable.add(false);
break;
case NULLABLE_BLOCK_INPUT_CHANNEL:
nullable.add(true);
break;
// do nothing
default:
}
}
checkState(nullable.size() == parameterVariables.size(), "Number of parameters does not match");
for (int i = 0; i < parameterVariables.size(); i++) {
if (!nullable.get(i)) {
Variable variableDefinition = parameterVariables.get(i);
loopBody = new IfStatement("if(!%s.isNull(position))", variableDefinition.getName()).condition(new BytecodeBlock().getVariable(variableDefinition).getVariable(positionVariable).invokeInterface(Block.class, "isNull", boolean.class, int.class)).ifFalse(loopBody);
}
}
loopBody = new IfStatement("if(testMask(%s, position))", masksBlock.getName()).condition(new BytecodeBlock().getVariable(masksBlock).getVariable(positionVariable).invokeStatic(CompilerOperations.class, "testMask", boolean.class, Block.class, int.class)).ifTrue(loopBody);
BytecodeNode forLoop = new ForLoop().initialize(new BytecodeBlock().putVariable(positionVariable, 0)).condition(new BytecodeBlock().getVariable(positionVariable).getVariable(rowsVariable).invokeStatic(CompilerOperations.class, "lessThan", boolean.class, int.class, int.class)).update(new BytecodeBlock().incrementVariable(positionVariable, (byte) 1)).body(loopBody);
for (int i = 0; i < parameterVariables.size(); i++) {
if (!nullable.get(i)) {
Variable variableDefinition = parameterVariables.get(i);
forLoop = new IfStatement("if(!(%s instanceof RunLengthEncodedBlock && %s.isNull(0)))", variableDefinition.getName(), variableDefinition.getName()).condition(and(variableDefinition.instanceOf(RunLengthEncodedBlock.class), variableDefinition.invoke("isNull", boolean.class, constantInt(0)))).ifFalse(forLoop);
}
}
// Skip input blocks that eliminate all input positions
forLoop = new IfStatement("if(!(%s instanceof RunLengthEncodedBlock && !testMask(%s, 0)))", masksBlock.getName(), masksBlock.getName()).condition(and(masksBlock.instanceOf(RunLengthEncodedBlock.class), not(invokeStatic(type(CompilerOperations.class), "testMask", type(boolean.class), ImmutableList.of(type(Block.class), type(int.class)), masksBlock, constantInt(0))))).ifFalse(forLoop);
block.append(new IfStatement("if(%s > 0)", rowsVariable.getName()).condition(new BytecodeBlock().getVariable(rowsVariable).push(0).invokeStatic(CompilerOperations.class, "greaterThan", boolean.class, int.class, int.class)).ifTrue(forLoop));
return block;
}
use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.
the class AccumulatorCompiler method generateBlockNonNullPositionForLoop.
// Generates a for-loop with a local variable named "position" defined, with the current position in the block,
// loopBody will only be executed for non-null positions in the Block
private static BytecodeBlock generateBlockNonNullPositionForLoop(Scope scope, Variable positionVariable, BytecodeBlock loopBody) {
Variable rowsVariable = scope.declareVariable(int.class, "rows");
Variable blockVariable = scope.getVariable("block");
BytecodeBlock block = new BytecodeBlock().append(blockVariable).invokeInterface(Block.class, "getPositionCount", int.class).putVariable(rowsVariable);
IfStatement ifStatement = new IfStatement("if(!block.isNull(position))").condition(new BytecodeBlock().append(blockVariable).append(positionVariable).invokeInterface(Block.class, "isNull", boolean.class, int.class)).ifFalse(loopBody);
block.append(new ForLoop().initialize(positionVariable.set(constantInt(0))).condition(new BytecodeBlock().append(positionVariable).append(rowsVariable).invokeStatic(CompilerOperations.class, "lessThan", boolean.class, int.class, int.class)).update(new BytecodeBlock().incrementVariable(positionVariable, (byte) 1)).body(ifStatement));
return block;
}
use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.
the class AbstractMinMaxBy method generateInputMethod.
private void generateInputMethod(ClassDefinition definition, CallSiteBinder binder, MethodHandle compareMethod, Type keyType, Type valueType, Class<?> stateClass) {
Parameter state = arg("state", stateClass);
Parameter value = arg("value", Block.class);
Parameter key = arg("key", Block.class);
Parameter position = arg("position", int.class);
MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "input", type(void.class), state, value, key, position);
SqlTypeBytecodeExpression keySqlType = constantType(binder, keyType);
BytecodeBlock ifBlock = new BytecodeBlock().append(state.invoke("setFirst", void.class, keySqlType.getValue(key, position))).append(state.invoke("setFirstNull", void.class, constantBoolean(false))).append(state.invoke("setSecondNull", void.class, value.invoke("isNull", boolean.class, position)));
BytecodeNode setValueNode;
if (valueType.getJavaType().isPrimitive()) {
SqlTypeBytecodeExpression valueSqlType = constantType(binder, valueType);
setValueNode = state.invoke("setSecond", void.class, valueSqlType.getValue(value, position));
} else {
// Do not get value directly given it creates object overhead.
// Such objects would live long enough in Block or SliceBigArray to cause GC pressure.
setValueNode = new BytecodeBlock().append(state.invoke("setSecondBlock", void.class, value)).append(state.invoke("setSecondPosition", void.class, position));
}
ifBlock.append(new IfStatement().condition(value.invoke("isNull", boolean.class, position)).ifFalse(setValueNode));
method.getBody().append(new IfStatement().condition(or(state.invoke("isFirstNull", boolean.class), and(not(key.invoke("isNull", boolean.class, position)), loadConstant(binder, compareMethod, MethodHandle.class).invoke("invokeExact", boolean.class, keySqlType.getValue(key, position), state.invoke("getFirst", keyType.getJavaType()))))).ifTrue(ifBlock)).ret();
}
use of com.facebook.presto.bytecode.control.IfStatement in project presto by prestodb.
the class MapTransformKeyFunction method generateTransformKey.
private static 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 properties = arg("properties", SqlFunctionProperties.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, properties, 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(newInstance(TypedSet.class, constantType(binder, transformedKeyType), divide(positionCount, constantInt(2)), constantString(MAP_TRANSFORM_KEY_FUNCTION.getSignature().getNameSuffix()))));
// 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 {
// 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(PrestoException.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, properties, 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("contains", boolean.class, blockBuilder.cast(Block.class), position)).ifTrue(throwDuplicatedKeyException).ifFalse(typedSet.invoke("add", boolean.class, blockBuilder.cast(Block.class), position).pop()))));
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(), MapTransformKeyFunction.class.getClassLoader());
return methodHandle(generatedClass, "transform", Object.class, SqlFunctionProperties.class, Block.class, BinaryFunctionInterface.class);
}
Aggregations