use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
the class BytecodeUtils method generateInvocation.
public static BytecodeNode generateInvocation(Scope scope, String name, ScalarFunctionImplementation function, Optional<BytecodeNode> instance, List<BytecodeNode> arguments, Binding binding) {
MethodType methodType = binding.getType();
Class<?> returnType = methodType.returnType();
Class<?> unboxedReturnType = Primitives.unwrap(returnType);
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;
boolean boundInstance = false;
while (currentParameterIndex < methodType.parameterArray().length) {
Class<?> type = methodType.parameterArray()[currentParameterIndex];
stackTypes.add(type);
if (function.getInstanceFactory().isPresent() && !boundInstance) {
checkState(type.equals(function.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 {
block.append(arguments.get(realParameterIndex));
if (!function.getNullableArguments().get(realParameterIndex)) {
checkArgument(!Primitives.isWrapperType(type), "Non-nullable argument must not be primitive wrapper type");
block.append(ifWasNullPopAndGoto(scope, end, unboxedReturnType, Lists.reverse(stackTypes)));
} else {
if (function.getNullFlags().get(realParameterIndex)) {
if (type == Void.class) {
block.append(boxPrimitiveIfNecessary(scope, type));
}
block.append(scope.getVariable("wasNull"));
stackTypes.add(boolean.class);
currentParameterIndex++;
} else {
block.append(boxPrimitiveIfNecessary(scope, type));
}
block.append(scope.getVariable("wasNull").set(constantFalse()));
}
realParameterIndex++;
}
currentParameterIndex++;
}
block.append(invoke(binding, name));
if (function.isNullable()) {
block.append(unboxPrimitiveIfNecessary(scope, returnType));
}
block.visitLabel(end);
return block;
}
use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
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 if (type == Void.class) {
notNull.pushNull().checkCast(Void.class);
return notNull;
} 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);
}
use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
the class BytecodeUtils method generateWrite.
public static BytecodeNode generateWrite(CallSiteBinder callSiteBinder, Scope scope, Variable wasNullVariable, Type type) {
if (type.getJavaType() == void.class) {
return new BytecodeBlock().comment("output.appendNull();").invokeInterface(BlockBuilder.class, "appendNull", BlockBuilder.class).pop();
}
Class<?> valueJavaType = type.getJavaType();
if (!valueJavaType.isPrimitive() && valueJavaType != Slice.class) {
valueJavaType = Object.class;
}
String methodName = "write" + Primitives.wrap(valueJavaType).getSimpleName();
// the stack contains [output, value]
// We should be able to insert the code to get the output variable and compute the value
// at the right place instead of assuming they are in the stack. We should also not need to
// use temp variables to re-shuffle the stack to the right shape before Type.writeXXX is called
// Unfortunately, because of the assumptions made by try_cast, we can't get around it yet.
// TODO: clean up once try_cast is fixed
Variable tempValue = scope.createTempVariable(valueJavaType);
Variable tempOutput = scope.createTempVariable(BlockBuilder.class);
return new BytecodeBlock().comment("if (wasNull)").append(new IfStatement().condition(wasNullVariable).ifTrue(new BytecodeBlock().comment("output.appendNull();").pop(valueJavaType).invokeInterface(BlockBuilder.class, "appendNull", BlockBuilder.class).pop()).ifFalse(new BytecodeBlock().comment("%s.%s(output, %s)", type.getTypeSignature(), methodName, valueJavaType.getSimpleName()).putVariable(tempValue).putVariable(tempOutput).append(loadConstant(callSiteBinder.bind(type, Type.class))).getVariable(tempOutput).getVariable(tempValue).invokeInterface(Type.class, methodName, void.class, BlockBuilder.class, valueJavaType)));
}
use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
the class JoinCompiler method generateAppendToMethod.
private static void generateAppendToMethod(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, List<Type> types, List<Integer> outputChannels, List<FieldDefinition> channelFields) {
Parameter blockIndex = arg("blockIndex", int.class);
Parameter blockPosition = arg("blockPosition", int.class);
Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
Parameter outputChannelOffset = arg("outputChannelOffset", int.class);
MethodDefinition appendToMethod = classDefinition.declareMethod(a(PUBLIC), "appendTo", type(void.class), blockIndex, blockPosition, pageBuilder, outputChannelOffset);
Variable thisVariable = appendToMethod.getThis();
BytecodeBlock appendToBody = appendToMethod.getBody();
int pageBuilderOutputChannel = 0;
for (int outputChannel : outputChannels) {
Type type = types.get(outputChannel);
BytecodeExpression typeExpression = constantType(callSiteBinder, type);
BytecodeExpression block = thisVariable.getField(channelFields.get(outputChannel)).invoke("get", Object.class, blockIndex).cast(Block.class);
appendToBody.comment("%s.appendTo(channel_%s.get(outputChannel), blockPosition, pageBuilder.getBlockBuilder(outputChannelOffset + %s));", type.getClass(), outputChannel, pageBuilderOutputChannel).append(typeExpression).append(block).append(blockPosition).append(pageBuilder).append(outputChannelOffset).push(pageBuilderOutputChannel++).append(OpCode.IADD).invokeVirtual(PageBuilder.class, "getBlockBuilder", BlockBuilder.class, int.class).invokeInterface(Type.class, "appendTo", void.class, Block.class, int.class, BlockBuilder.class);
}
appendToBody.ret();
}
use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
the class JoinProbeCompiler method generateConstructor.
private static void generateConstructor(ClassDefinition classDefinition, List<Integer> probeChannels, Optional<Integer> probeHashChannel, FieldDefinition lookupSourceField, List<FieldDefinition> blockFields, List<FieldDefinition> probeChannelFields, FieldDefinition probeBlocksArrayField, FieldDefinition probePageField, FieldDefinition pageField, FieldDefinition probeHashBlockField, FieldDefinition positionField, FieldDefinition positionCountField) {
Parameter lookupSource = arg("lookupSource", LookupSource.class);
Parameter page = arg("page", Page.class);
MethodDefinition constructorDefinition = classDefinition.declareConstructor(a(PUBLIC), lookupSource, page);
Variable thisVariable = constructorDefinition.getThis();
BytecodeBlock constructor = constructorDefinition.getBody().comment("super();").append(thisVariable).invokeConstructor(Object.class);
constructor.comment("this.lookupSource = lookupSource;").append(thisVariable.setField(lookupSourceField, lookupSource));
constructor.comment("this.positionCount = page.getPositionCount();").append(thisVariable.setField(positionCountField, page.invoke("getPositionCount", int.class)));
constructor.comment("Set block fields");
for (int index = 0; index < blockFields.size(); index++) {
constructor.append(thisVariable.setField(blockFields.get(index), page.invoke("getBlock", Block.class, constantInt(index))));
}
constructor.comment("Set probe channel fields");
for (int index = 0; index < probeChannelFields.size(); index++) {
constructor.append(thisVariable.setField(probeChannelFields.get(index), thisVariable.getField(blockFields.get(probeChannels.get(index)))));
}
constructor.comment("this.probeBlocks = new Block[<probeChannelCount>];");
constructor.append(thisVariable).push(probeChannelFields.size()).newArray(Block.class).putField(probeBlocksArrayField);
for (int index = 0; index < probeChannelFields.size(); index++) {
constructor.append(thisVariable).getField(probeBlocksArrayField).push(index).append(thisVariable).getField(probeChannelFields.get(index)).putObjectArrayElement();
}
constructor.comment("this.page = page").append(thisVariable.setField(pageField, page));
constructor.comment("this.probePage = new Page(probeBlocks)").append(thisVariable.setField(probePageField, newInstance(Page.class, thisVariable.getField(probeBlocksArrayField))));
if (probeHashChannel.isPresent()) {
Integer index = probeHashChannel.get();
constructor.comment("this.probeHashBlock = blocks[hashChannel.get()]").append(thisVariable.setField(probeHashBlockField, thisVariable.getField(blockFields.get(index))));
}
constructor.comment("this.position = -1;").append(thisVariable.setField(positionField, constantInt(-1)));
constructor.ret();
}
Aggregations