use of com.facebook.presto.bytecode.MethodDefinition 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.MethodDefinition in project presto by prestodb.
the class ArrayTransformFunction method generateTransform.
private static Class<?> generateTransform(Type inputType, Type outputType) {
CallSiteBinder binder = new CallSiteBinder();
Class<?> inputJavaType = Primitives.wrap(inputType.getJavaType());
Class<?> outputJavaType = Primitives.wrap(outputType.getJavaType());
ClassDefinition definition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("ArrayTransform"), type(Object.class));
definition.declareDefaultConstructor(a(PRIVATE));
// define createPageBuilder
MethodDefinition createPageBuilderMethod = definition.declareMethod(a(PUBLIC, STATIC), "createPageBuilder", type(PageBuilder.class));
createPageBuilderMethod.getBody().append(newInstance(PageBuilder.class, constantType(binder, new ArrayType(outputType)).invoke("getTypeParameters", List.class)).ret());
// define transform method
Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
Parameter block = arg("block", Block.class);
Parameter function = arg("function", MethodHandle.class);
MethodDefinition method = definition.declareMethod(a(PUBLIC, STATIC), "transform", type(Block.class), ImmutableList.of(pageBuilder, 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 blockBuilder = scope.declareVariable(BlockBuilder.class, "blockBuilder");
Variable inputElement = scope.declareVariable(inputJavaType, "inputElement");
Variable outputElement = scope.declareVariable(outputJavaType, "outputElement");
// invoke block.getPositionCount()
body.append(positionCount.set(block.invoke("getPositionCount", int.class)));
// reset page builder if it is full
body.append(new IfStatement().condition(pageBuilder.invoke("isFull", boolean.class)).ifTrue(pageBuilder.invoke("reset", void.class)));
// get block builder
body.append(blockBuilder.set(pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, constantInt(0))));
BytecodeNode loadInputElement;
if (!inputType.equals(UNKNOWN)) {
loadInputElement = new IfStatement().condition(block.invoke("isNull", boolean.class, position)).ifTrue(inputElement.set(constantNull(inputJavaType))).ifFalse(inputElement.set(constantType(binder, inputType).getValue(block, position).cast(inputJavaType)));
} else {
loadInputElement = new BytecodeBlock().append(inputElement.set(constantNull(inputJavaType)));
}
BytecodeNode writeOutputElement;
if (!outputType.equals(UNKNOWN)) {
writeOutputElement = new IfStatement().condition(equal(outputElement, constantNull(outputJavaType))).ifTrue(blockBuilder.invoke("appendNull", BlockBuilder.class).pop()).ifFalse(constantType(binder, outputType).writeValue(blockBuilder, outputElement.cast(outputType.getJavaType())));
} else {
writeOutputElement = new BytecodeBlock().append(blockBuilder.invoke("appendNull", BlockBuilder.class).pop());
}
body.append(new ForLoop().initialize(position.set(constantInt(0))).condition(lessThan(position, positionCount)).update(incrementVariable(position, (byte) 1)).body(new BytecodeBlock().append(loadInputElement).append(outputElement.set(function.invoke("invokeExact", outputJavaType, inputElement))).append(writeOutputElement)));
body.append(pageBuilder.invoke("declarePositions", void.class, positionCount));
body.append(blockBuilder.invoke("getRegion", Block.class, subtract(blockBuilder.invoke("getPositionCount", int.class), positionCount), positionCount).ret());
return defineClass(definition, Object.class, binder.getBindings(), ArrayTransformFunction.class.getClassLoader());
}
use of com.facebook.presto.bytecode.MethodDefinition in project presto by prestodb.
the class VarArgsToArrayAdapterGenerator method generateVarArgsToArrayAdapter.
public static MethodHandleAndConstructor generateVarArgsToArrayAdapter(Class<?> returnType, Class<?> javaType, int argsLength, MethodHandle function, MethodHandle userStateFactory) {
requireNonNull(returnType, "returnType is null");
requireNonNull(javaType, "javaType is null");
requireNonNull(function, "function is null");
requireNonNull(userStateFactory, "userStateFactory is null");
MethodType methodType = function.type();
Class<?> javaArrayType = toArrayClass(javaType);
checkArgument(methodType.returnType() == returnType, "returnType does not match");
checkArgument(methodType.parameterList().equals(ImmutableList.of(Object.class, javaArrayType)), "parameter types do not match");
CallSiteBinder callSiteBinder = new CallSiteBinder();
ClassDefinition classDefinition = new ClassDefinition(a(PUBLIC, FINAL), makeClassName("VarArgsToListAdapter"), type(Object.class));
classDefinition.declareDefaultConstructor(a(PRIVATE));
// generate userState constructor
MethodDefinition stateFactoryDefinition = classDefinition.declareMethod(a(PUBLIC, STATIC), "createState", type(VarArgsToArrayAdapterState.class));
stateFactoryDefinition.getBody().comment("create userState for current instance").append(newInstance(VarArgsToArrayAdapterState.class, loadConstant(callSiteBinder, userStateFactory, MethodHandle.class).invoke("invokeExact", Object.class), newArray(type(javaArrayType), argsLength).cast(Object.class)).ret());
// generate adapter method
ImmutableList.Builder<Parameter> parameterListBuilder = ImmutableList.builder();
parameterListBuilder.add(arg("userState", VarArgsToArrayAdapterState.class));
for (int i = 0; i < argsLength; i++) {
parameterListBuilder.add(arg("input_" + i, javaType));
}
ImmutableList<Parameter> parameterList = parameterListBuilder.build();
MethodDefinition methodDefinition = classDefinition.declareMethod(a(PUBLIC, STATIC), "varArgsToArray", type(returnType), parameterList);
BytecodeBlock body = methodDefinition.getBody();
BytecodeExpression userState = parameterList.get(0).getField("userState", Object.class);
BytecodeExpression args = parameterList.get(0).getField("args", Object.class).cast(javaArrayType);
for (int i = 0; i < argsLength; i++) {
body.append(args.setElement(i, parameterList.get(i + 1)));
}
body.append(loadConstant(callSiteBinder, function, MethodHandle.class).invoke("invokeExact", returnType, userState, args).ret());
// define class
Class<?> generatedClass = defineClass(classDefinition, Object.class, callSiteBinder.getBindings(), VarArgsToArrayAdapterGenerator.class.getClassLoader());
return new MethodHandleAndConstructor(Reflection.methodHandle(generatedClass, "varArgsToArray", ImmutableList.builder().add(VarArgsToArrayAdapterState.class).addAll(nCopies(argsLength, javaType)).build().toArray(new Class<?>[argsLength])), Reflection.methodHandle(generatedClass, "createState"));
}
use of com.facebook.presto.bytecode.MethodDefinition in project presto by prestodb.
the class PageProcessorCompiler method generateMethods.
@Override
public void generateMethods(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, RowExpression filter, List<RowExpression> projections) {
CachedInstanceBinder cachedInstanceBinder = new CachedInstanceBinder(classDefinition, callSiteBinder);
ImmutableList.Builder<MethodDefinition> projectMethods = ImmutableList.builder();
ImmutableList.Builder<MethodDefinition> projectColumnarMethods = ImmutableList.builder();
ImmutableList.Builder<MethodDefinition> projectDictionaryMethods = ImmutableList.builder();
for (int i = 0; i < projections.size(); i++) {
MethodDefinition project = generateProjectMethod(classDefinition, callSiteBinder, cachedInstanceBinder, "project_" + i, projections.get(i));
MethodDefinition projectColumnar = generateProjectColumnarMethod(classDefinition, callSiteBinder, "projectColumnar_" + i, projections.get(i), project);
MethodDefinition projectRLE = generateProjectRLEMethod(classDefinition, "projectRLE_" + i, projections.get(i), project, projectColumnar);
MethodDefinition projectDictionary = generateProjectDictionaryMethod(classDefinition, "projectDictionary_" + i, projections.get(i), project, projectColumnar, projectRLE);
projectMethods.add(project);
projectColumnarMethods.add(projectColumnar);
projectDictionaryMethods.add(projectDictionary);
}
List<MethodDefinition> projectMethodDefinitions = projectMethods.build();
List<MethodDefinition> projectColumnarMethodDefinitions = projectColumnarMethods.build();
List<MethodDefinition> projectDictionaryMethodDefinitions = projectDictionaryMethods.build();
generateProcessMethod(classDefinition, filter, projections, projectMethodDefinitions);
generateGetNonLazyPageMethod(classDefinition, filter, projections);
generateProcessColumnarMethod(classDefinition, projections, projectColumnarMethodDefinitions);
generateProcessColumnarDictionaryMethod(classDefinition, projections, projectDictionaryMethodDefinitions);
generateFilterPageMethod(classDefinition, filter);
generateFilterMethod(classDefinition, callSiteBinder, cachedInstanceBinder, filter);
generateConstructor(classDefinition, cachedInstanceBinder, projections.size());
}
use of com.facebook.presto.bytecode.MethodDefinition in project presto by prestodb.
the class PageProcessorCompiler method generateFilterPageMethod.
private void generateFilterPageMethod(ClassDefinition classDefinition, RowExpression filter) {
Parameter session = arg("session", ConnectorSession.class);
Parameter page = arg("page", Page.class);
MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "filterPage", type(int[].class), session, page);
method.comment("Filter: %s rows in the page", filter.toString());
Scope scope = method.getScope();
Variable thisVariable = method.getThis();
BytecodeBlock body = method.getBody();
Variable positionCount = scope.declareVariable("positionCount", body, page.invoke("getPositionCount", int.class));
Variable selectedPositions = scope.declareVariable("selectedPositions", body, newArray(type(int[].class), positionCount));
Variable selectedCount = scope.declareVariable("selectedCount", body, constantInt(0));
Variable position = scope.declareVariable(int.class, "position");
List<Integer> filterChannels = getInputChannels(filter);
// extract block variables
ImmutableList.Builder<Variable> blockVariablesBuilder = ImmutableList.builder();
for (int channel : filterChannels) {
Variable blockVariable = scope.declareVariable("block_" + channel, body, page.invoke("getBlock", Block.class, constantInt(channel)));
blockVariablesBuilder.add(blockVariable);
}
List<Variable> blockVariables = blockVariablesBuilder.build();
if (filterChannels.size() == 1 && determinismEvaluator.isDeterministic(filter)) {
BytecodeBlock ifFilterOnDictionaryBlock = getBytecodeFilterOnDictionary(session, scope, blockVariables.get(0));
BytecodeBlock ifFilterOnRLEBlock = getBytecodeFilterOnRLE(session, scope, blockVariables.get(0));
body.append(new IfStatement().condition(blockVariables.get(0).instanceOf(DictionaryBlock.class)).ifTrue(ifFilterOnDictionaryBlock));
body.append(new IfStatement().condition(blockVariables.get(0).instanceOf(RunLengthEncodedBlock.class)).ifTrue(ifFilterOnRLEBlock));
}
body.append(new ForLoop().initialize(position.set(constantInt(0))).condition(lessThan(position, positionCount)).update(position.increment()).body(new IfStatement().condition(invokeFilter(thisVariable, session, blockVariables, position)).ifTrue(new BytecodeBlock().append(selectedPositions.setElement(selectedCount, position)).append(selectedCount.increment()))));
body.append(invokeStatic(Arrays.class, "copyOf", int[].class, selectedPositions, selectedCount).ret());
}
Aggregations