use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
the class ArrayConstructor method generateArrayConstructor.
private static Class<?> generateArrayConstructor(List<Class<?>> stackTypes, Type elementType) {
List<String> stackTypeNames = stackTypes.stream().map(Class::getSimpleName).collect(toImmutableList());
ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), CompilerUtils.makeClassName(Joiner.on("").join(stackTypeNames) + "ArrayConstructor"), type(Object.class));
// Generate constructor
definition.declareDefaultConstructor(a(PRIVATE));
// Generate arrayConstructor()
ImmutableList.Builder<Parameter> parameters = ImmutableList.builder();
for (int i = 0; i < stackTypes.size(); i++) {
Class<?> stackType = stackTypes.get(i);
parameters.add(arg("arg" + i, stackType));
}
MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "arrayConstructor", type(Block.class), parameters.build());
Scope scope = method.getScope();
BytecodeBlock body = method.getBody();
Variable blockBuilderVariable = scope.declareVariable(BlockBuilder.class, "blockBuilder");
CallSiteBinder binder = new CallSiteBinder();
BytecodeExpression createBlockBuilder = blockBuilderVariable.set(constantType(binder, elementType).invoke("createBlockBuilder", BlockBuilder.class, newInstance(BlockBuilderStatus.class), constantInt(stackTypes.size())));
body.append(createBlockBuilder);
for (int i = 0; i < stackTypes.size(); i++) {
if (elementType.getJavaType() == void.class) {
body.append(blockBuilderVariable.invoke("appendNull", BlockBuilder.class));
} else {
Variable argument = scope.getVariable("arg" + i);
IfStatement ifStatement = new IfStatement().condition(equal(argument, constantNull(stackTypes.get(i)))).ifTrue(blockBuilderVariable.invoke("appendNull", BlockBuilder.class).pop()).ifFalse(constantType(binder, elementType).writeValue(blockBuilderVariable, argument.cast(elementType.getJavaType())));
body.append(ifStatement);
}
}
body.append(blockBuilderVariable.invoke("build", Block.class).ret());
return defineClass(definition, Object.class, binder.getBindings(), new DynamicClassLoader(ArrayConstructor.class.getClassLoader()));
}
use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
the class StateCompiler method generateGroupedStateClass.
private static <T> Class<? extends T> generateGroupedStateClass(Class<T> clazz, Map<String, Type> fieldTypes, DynamicClassLoader classLoader) {
ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("Grouped" + clazz.getSimpleName()), type(AbstractGroupedAccumulatorState.class), type(clazz), type(GroupedAccumulator.class));
List<StateField> fields = enumerateFields(clazz, fieldTypes);
// Create constructor
MethodDefinition constructor = definition.declareConstructor(a(PUBLIC));
constructor.getBody().append(constructor.getThis()).invokeConstructor(AbstractGroupedAccumulatorState.class);
// Create ensureCapacity
MethodDefinition ensureCapacity = definition.declareMethod(a(PUBLIC), "ensureCapacity", type(void.class), arg("size", long.class));
// Generate fields, constructor, and ensureCapacity
List<FieldDefinition> fieldDefinitions = new ArrayList<>();
for (StateField field : fields) {
fieldDefinitions.add(generateGroupedField(definition, constructor, ensureCapacity, field));
}
constructor.getBody().ret();
ensureCapacity.getBody().ret();
// Generate getEstimatedSize
MethodDefinition getEstimatedSize = definition.declareMethod(a(PUBLIC), "getEstimatedSize", type(long.class));
BytecodeBlock body = getEstimatedSize.getBody();
Variable size = getEstimatedSize.getScope().declareVariable(long.class, "size");
// initialize size to 0L
body.append(size.set(constantLong(0)));
// add field to size
for (FieldDefinition field : fieldDefinitions) {
body.append(size.set(add(size, getEstimatedSize.getThis().getField(field).invoke("sizeOf", long.class))));
}
// return size
body.append(size.ret());
return defineClass(definition, clazz, classLoader);
}
use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
the class StateCompiler method generateDeserialize.
private static <T> void generateDeserialize(ClassDefinition definition, CallSiteBinder binder, Class<T> clazz, List<StateField> fields) {
Parameter block = arg("block", Block.class);
Parameter index = arg("index", int.class);
Parameter state = arg("state", Object.class);
MethodDefinition method = definition.declareMethod(a(PUBLIC), "deserialize", type(void.class), block, index, state);
BytecodeBlock deserializerBody = method.getBody();
Scope scope = method.getScope();
if (fields.size() == 1) {
StateField field = fields.get(0);
Method setter = getSetter(clazz, field);
if (!field.isPrimitiveType()) {
deserializerBody.append(new IfStatement().condition(block.invoke("isNull", boolean.class, index)).ifTrue(state.cast(setter.getDeclaringClass()).invoke(setter, constantNull(field.getType()))).ifFalse(state.cast(setter.getDeclaringClass()).invoke(setter, constantType(binder, field.getSqlType()).getValue(block, index))));
} else {
// For primitive type, we need to cast here because we serialize byte fields with TINYINT (whose java type is long).
deserializerBody.append(state.cast(setter.getDeclaringClass()).invoke(setter, constantType(binder, field.getSqlType()).getValue(block, index).cast(field.getType())));
}
} else {
Variable row = scope.declareVariable(Block.class, "row");
deserializerBody.append(row.set(block.invoke("getObject", Object.class, index, constantClass(Block.class)).cast(Block.class)));
int position = 0;
for (StateField field : fields) {
Method setter = getSetter(clazz, field);
if (!field.isPrimitiveType()) {
deserializerBody.append(new IfStatement().condition(row.invoke("isNull", boolean.class, constantInt(position))).ifTrue(state.cast(setter.getDeclaringClass()).invoke(setter, constantNull(field.getType()))).ifFalse(state.cast(setter.getDeclaringClass()).invoke(setter, constantType(binder, field.getSqlType()).getValue(row, constantInt(position)))));
} else {
// For primitive type, we need to cast here because we serialize byte fields with TINYINT (whose java type is long).
deserializerBody.append(state.cast(setter.getDeclaringClass()).invoke(setter, constantType(binder, field.getSqlType()).getValue(row, constantInt(position)).cast(field.getType())));
}
position++;
}
}
deserializerBody.ret();
}
use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
the class RowToRowCast method generateRowCast.
private static Class<?> generateRowCast(Type fromType, Type toType, FunctionRegistry functionRegistry) {
List<Type> toTypes = toType.getTypeParameters();
List<Type> fromTypes = fromType.getTypeParameters();
CallSiteBinder binder = new CallSiteBinder();
// Embed the MD5 hash code of input and output types into the generated class name instead of the raw type names,
// which could prevent the class name from hitting the length limitation and invalid characters.
byte[] md5Suffix = Hashing.md5().hashBytes((fromType + "$" + toType).getBytes()).asBytes();
ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), CompilerUtils.makeClassName(Joiner.on("$").join("RowCast", BaseEncoding.base16().encode(md5Suffix))), type(Object.class));
Parameter session = arg("session", ConnectorSession.class);
Parameter value = arg("value", Block.class);
MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "castRow", type(Block.class), session, value);
Scope scope = method.getScope();
BytecodeBlock body = method.getBody();
Variable wasNull = scope.declareVariable(boolean.class, "wasNull");
Variable blockBuilder = scope.createTempVariable(BlockBuilder.class);
body.append(wasNull.set(constantBoolean(false)));
CachedInstanceBinder cachedInstanceBinder = new CachedInstanceBinder(definition, binder);
// create the interleave block builder
body.newObject(InterleavedBlockBuilder.class).dup().append(constantType(binder, toType).invoke("getTypeParameters", List.class)).append(newInstance(BlockBuilderStatus.class)).append(constantInt(toTypes.size())).invokeConstructor(InterleavedBlockBuilder.class, List.class, BlockBuilderStatus.class, int.class).putVariable(blockBuilder);
// loop through to append member blocks
for (int i = 0; i < toTypes.size(); i++) {
Signature signature = internalOperator(CAST.name(), toTypes.get(i).getTypeSignature(), ImmutableList.of(fromTypes.get(i).getTypeSignature()));
ScalarFunctionImplementation function = functionRegistry.getScalarFunctionImplementation(signature);
Type currentFromType = fromTypes.get(i);
if (currentFromType.equals(UNKNOWN)) {
body.append(blockBuilder.invoke("appendNull", BlockBuilder.class).pop());
continue;
}
BytecodeExpression fromElement = constantType(binder, currentFromType).getValue(value, constantInt(i));
BytecodeExpression toElement = invokeFunction(scope, cachedInstanceBinder, signature.getName(), function, fromElement);
IfStatement ifElementNull = new IfStatement("if the element in the row type is null...");
ifElementNull.condition(value.invoke("isNull", boolean.class, constantInt(i))).ifTrue(blockBuilder.invoke("appendNull", BlockBuilder.class).pop()).ifFalse(constantType(binder, toTypes.get(i)).writeValue(blockBuilder, toElement));
body.append(ifElementNull);
}
// call blockBuilder.build()
body.append(blockBuilder.invoke("build", Block.class)).retObject();
// create constructor
MethodDefinition constructorDefinition = definition.declareConstructor(a(PUBLIC));
BytecodeBlock constructorBody = constructorDefinition.getBody();
Variable thisVariable = constructorDefinition.getThis();
constructorBody.comment("super();").append(thisVariable).invokeConstructor(Object.class);
cachedInstanceBinder.generateInitializations(thisVariable, constructorBody);
constructorBody.ret();
return defineClass(definition, Object.class, binder.getBindings(), RowToRowCast.class.getClassLoader());
}
use of com.facebook.presto.bytecode.BytecodeBlock in project presto by prestodb.
the class NullIfCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments) {
Scope scope = generatorContext.getScope();
RowExpression first = arguments.get(0);
RowExpression second = arguments.get(1);
LabelNode notMatch = new LabelNode("notMatch");
// push first arg on the stack
BytecodeBlock block = new BytecodeBlock().comment("check if first arg is null").append(generatorContext.generate(first)).append(BytecodeUtils.ifWasNullPopAndGoto(scope, notMatch, void.class));
Type firstType = first.getType();
Type secondType = second.getType();
// if (equal(cast(first as <common type>), cast(second as <common type>))
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, new BytecodeBlock().dup(firstType.getJavaType()), firstType, equalsSignature.getArgumentTypes().get(0)), cast(generatorContext, generatorContext.generate(second), secondType, equalsSignature.getArgumentTypes().get(1))));
BytecodeBlock conditionBlock = new BytecodeBlock().append(equalsCall).append(BytecodeUtils.ifWasNullClearPopAndGoto(scope, notMatch, void.class, boolean.class));
// if first and second are equal, return null
BytecodeBlock trueBlock = new BytecodeBlock().append(generatorContext.wasNull().set(constantTrue())).pop(first.getType().getJavaType()).pushJavaDefault(first.getType().getJavaType());
// else return first (which is still on the stack
block.append(new IfStatement().condition(conditionBlock).ifTrue(trueBlock).ifFalse(notMatch));
return block;
}
Aggregations