use of com.facebook.presto.bytecode.MethodDefinition in project presto by prestodb.
the class PageProcessorCompiler method generateMethodsForLambdaAndTry.
private PreGeneratedExpressions generateMethodsForLambdaAndTry(ClassDefinition containerClassDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, RowExpression projection, String methodPrefix) {
Set<RowExpression> lambdaAndTryExpressions = ImmutableSet.copyOf(extractLambdaAndTryExpressions(projection));
ImmutableMap.Builder<CallExpression, MethodDefinition> tryMethodMap = ImmutableMap.builder();
ImmutableMap.Builder<LambdaDefinitionExpression, FieldDefinition> lambdaFieldMap = ImmutableMap.builder();
int counter = 0;
for (RowExpression expression : lambdaAndTryExpressions) {
if (expression instanceof CallExpression) {
CallExpression tryExpression = (CallExpression) expression;
verify(!Signatures.TRY.equals(tryExpression.getSignature().getName()));
Parameter session = arg("session", ConnectorSession.class);
List<Parameter> blocks = toBlockParameters(getInputChannels(tryExpression.getArguments()));
Parameter position = arg("position", int.class);
BytecodeExpressionVisitor innerExpressionVisitor = new BytecodeExpressionVisitor(callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(callSiteBinder), metadata.getFunctionRegistry(), new PreGeneratedExpressions(tryMethodMap.build(), lambdaFieldMap.build()));
List<Parameter> inputParameters = ImmutableList.<Parameter>builder().add(session).addAll(blocks).add(position).build();
MethodDefinition tryMethod = defineTryMethod(innerExpressionVisitor, containerClassDefinition, methodPrefix + "_try_" + counter, inputParameters, Primitives.wrap(tryExpression.getType().getJavaType()), tryExpression, callSiteBinder);
tryMethodMap.put(tryExpression, tryMethod);
} else if (expression instanceof LambdaDefinitionExpression) {
LambdaDefinitionExpression lambdaExpression = (LambdaDefinitionExpression) expression;
PreGeneratedExpressions preGeneratedExpressions = new PreGeneratedExpressions(tryMethodMap.build(), lambdaFieldMap.build());
FieldDefinition methodHandleField = LambdaBytecodeGenerator.preGenerateLambdaExpression(lambdaExpression, methodPrefix + "_lambda_" + counter, containerClassDefinition, preGeneratedExpressions, callSiteBinder, cachedInstanceBinder, metadata.getFunctionRegistry());
lambdaFieldMap.put(lambdaExpression, methodHandleField);
} else {
throw new VerifyException(format("unexpected expression: %s", expression.toString()));
}
counter++;
}
return new PreGeneratedExpressions(tryMethodMap.build(), lambdaFieldMap.build());
}
use of com.facebook.presto.bytecode.MethodDefinition in project presto by prestodb.
the class PageProcessorCompiler method generateProcessColumnarMethod.
private static void generateProcessColumnarMethod(ClassDefinition classDefinition, List<RowExpression> projections, List<MethodDefinition> projectColumnarMethods) {
Parameter session = arg("session", ConnectorSession.class);
Parameter page = arg("page", Page.class);
Parameter types = arg("types", List.class);
MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "processColumnar", type(Page.class), session, page, types);
Scope scope = method.getScope();
BytecodeBlock body = method.getBody();
Variable thisVariable = method.getThis();
Variable selectedPositions = scope.declareVariable("selectedPositions", body, thisVariable.invoke("filterPage", int[].class, session, page));
Variable cardinality = scope.declareVariable("cardinality", body, selectedPositions.length());
body.comment("if no rows selected return null").append(new IfStatement().condition(equal(cardinality, constantInt(0))).ifTrue(constantNull(Page.class).ret()));
if (projections.isEmpty()) {
// if no projections, return new page with selected rows
body.append(newInstance(Page.class, cardinality, newArray(type(Block[].class), 0)).ret());
return;
}
Variable pageBuilder = scope.declareVariable("pageBuilder", body, newInstance(PageBuilder.class, cardinality, types));
Variable outputBlocks = scope.declareVariable("outputBlocks", body, newArray(type(Block[].class), projections.size()));
for (int projectionIndex = 0; projectionIndex < projections.size(); projectionIndex++) {
List<BytecodeExpression> params = ImmutableList.<BytecodeExpression>builder().add(session).add(page).add(selectedPositions).add(pageBuilder).add(constantInt(projectionIndex)).build();
body.append(outputBlocks.setElement(projectionIndex, thisVariable.invoke(projectColumnarMethods.get(projectionIndex), params)));
}
// create new page from outputBlocks
body.append(newInstance(Page.class, cardinality, outputBlocks).ret());
}
use of com.facebook.presto.bytecode.MethodDefinition in project presto by prestodb.
the class PageProcessorCompiler method generateProcessMethod.
private static void generateProcessMethod(ClassDefinition classDefinition, RowExpression filter, List<RowExpression> projections, List<MethodDefinition> projectionMethods) {
Parameter session = arg("session", ConnectorSession.class);
Parameter page = arg("page", Page.class);
Parameter start = arg("start", int.class);
Parameter end = arg("end", int.class);
Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "process", type(int.class), session, page, start, end, pageBuilder);
Scope scope = method.getScope();
BytecodeBlock body = method.getBody();
Variable thisVariable = method.getThis();
// extract blocks
List<Integer> allInputChannels = getInputChannels(concat(projections, ImmutableList.of(filter)));
ImmutableMap.Builder<Integer, Variable> builder = ImmutableMap.builder();
for (int channel : allInputChannels) {
Variable blockVariable = scope.declareVariable("block_" + channel, body, page.invoke("getBlock", Block.class, constantInt(channel)));
builder.put(channel, blockVariable);
}
Map<Integer, Variable> channelBlocks = builder.build();
Map<RowExpression, List<Variable>> expressionInputBlocks = getExpressionInputBlocks(projections, filter, channelBlocks);
// projection body
Variable position = scope.declareVariable(int.class, "position");
BytecodeBlock project = new BytecodeBlock().append(pageBuilder.invoke("declarePosition", void.class));
for (int projectionIndex = 0; projectionIndex < projections.size(); projectionIndex++) {
RowExpression projection = projections.get(projectionIndex);
project.append(invokeProject(thisVariable, session, expressionInputBlocks.get(projection), position, pageBuilder, constantInt(projectionIndex), projectionMethods.get(projectionIndex)));
}
LabelNode done = new LabelNode("done");
// for loop loop body
ForLoop loop = new ForLoop().initialize(position.set(start)).condition(lessThan(position, end)).update(position.set(add(position, constantInt(1)))).body(new BytecodeBlock().append(new IfStatement().condition(pageBuilder.invoke("isFull", boolean.class)).ifTrue(jump(done))).append(new IfStatement().condition(invokeFilter(thisVariable, session, expressionInputBlocks.get(filter), position)).ifTrue(project)));
body.append(loop).visitLabel(done).append(position.ret());
}
use of com.facebook.presto.bytecode.MethodDefinition in project presto by prestodb.
the class LambdaBytecodeGenerator method defineLambdaMethodAndField.
private static FieldDefinition defineLambdaMethodAndField(BytecodeExpressionVisitor innerExpressionVisitor, ClassDefinition classDefinition, String fieldAndMethodName, List<Parameter> inputParameters, LambdaDefinitionExpression lambda) {
Class<?> returnType = Primitives.wrap(lambda.getBody().getType().getJavaType());
MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), fieldAndMethodName, type(returnType), inputParameters);
Scope scope = method.getScope();
Variable wasNull = scope.declareVariable(boolean.class, "wasNull");
BytecodeNode compiledBody = lambda.getBody().accept(innerExpressionVisitor, scope);
method.getBody().putVariable(wasNull, false).append(compiledBody).append(boxPrimitiveIfNecessary(scope, returnType)).ret(returnType);
FieldDefinition methodHandleField = classDefinition.declareField(a(PRIVATE, STATIC, FINAL), fieldAndMethodName, type(MethodHandle.class));
classDefinition.getClassInitializer().getBody().append(setStatic(methodHandleField, invokeStatic(Reflection.class, "methodHandle", MethodHandle.class, constantClass(classDefinition.getType()), constantString(fieldAndMethodName), newArray(type(Class[].class), inputParameters.stream().map(Parameter::getType).map(BytecodeExpressions::constantClass).collect(toImmutableList())))));
return methodHandleField;
}
use of com.facebook.presto.bytecode.MethodDefinition in project presto by prestodb.
the class PageProcessorCompiler method generateProjectDictionaryMethod.
private MethodDefinition generateProjectDictionaryMethod(ClassDefinition classDefinition, String methodName, RowExpression projection, MethodDefinition project, MethodDefinition projectColumnar, MethodDefinition projectRLE) {
Parameter session = arg("session", ConnectorSession.class);
Parameter page = arg("page", Page.class);
Parameter selectedPositions = arg("selectedPositions", int[].class);
Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
Parameter projectionIndex = arg("projectionIndex", int.class);
Parameter dictionarySourceIds = arg("dictionarySourceIds", Map.class);
List<Parameter> params = ImmutableList.<Parameter>builder().add(session).add(page).add(selectedPositions).add(pageBuilder).add(projectionIndex).add(dictionarySourceIds).build();
List<Parameter> columnarParams = ImmutableList.<Parameter>builder().add(session).add(page).add(selectedPositions).add(pageBuilder).add(projectionIndex).build();
MethodDefinition method = classDefinition.declareMethod(a(PRIVATE), methodName, type(Block.class), params);
BytecodeBlock body = method.getBody();
Scope scope = method.getScope();
Variable thisVariable = method.getThis();
List<Integer> inputChannels = getInputChannels(projection);
if (inputChannels.size() != 1 || !determinismEvaluator.isDeterministic(projection)) {
body.append(thisVariable.invoke(projectColumnar, columnarParams).ret());
return method;
}
Variable inputBlock = scope.declareVariable("inputBlock", body, page.invoke("getBlock", Block.class, constantInt(getOnlyElement(inputChannels))));
body.append(new IfStatement().condition(inputBlock.instanceOf(RunLengthEncodedBlock.class)).ifTrue(thisVariable.invoke(projectRLE, columnarParams).ret()));
body.append(new IfStatement().condition(inputBlock.instanceOf(DictionaryBlock.class)).ifFalse(thisVariable.invoke(projectColumnar, columnarParams).ret()));
Variable blockBuilder = scope.declareVariable("blockBuilder", body, pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, projectionIndex));
Variable cardinality = scope.declareVariable("cardinality", body, selectedPositions.length());
Variable dictionary = scope.declareVariable(Block.class, "dictionary");
Variable dictionaryCount = scope.declareVariable(int.class, "dictionaryCount");
Variable inputSourceId = scope.declareVariable(DictionaryId.class, "inputSourceId");
Variable outputSourceId = scope.declareVariable(DictionaryId.class, "outputSourceId");
Variable outputDictionary = scope.declareVariable(Block.class, "outputDictionary");
Variable outputIds = scope.declareVariable(int[].class, "outputIds");
BytecodeExpression inputDictionaries = thisVariable.getField("inputDictionaries", Block[].class);
BytecodeExpression outputDictionaries = thisVariable.getField("outputDictionaries", Block[].class);
Variable position = scope.declareVariable("position", body, constantInt(0));
BytecodeExpression castDictionaryBlock = inputBlock.cast(DictionaryBlock.class);
body.comment("Extract dictionary, ids, positionCount and dictionarySourceId").append(dictionary.set(castDictionaryBlock.invoke("getDictionary", Block.class))).append(dictionaryCount.set(dictionary.invoke("getPositionCount", int.class))).append(inputSourceId.set(castDictionaryBlock.invoke("getDictionarySourceId", DictionaryId.class)));
BytecodeBlock projectDictionary = new BytecodeBlock().comment("Project dictionary").append(new ForLoop().initialize(position.set(constantInt(0))).condition(lessThan(position, dictionaryCount)).update(position.increment()).body(invokeProject(thisVariable, session, ImmutableList.of(dictionary), position, pageBuilder, projectionIndex, project))).append(outputDictionary.set(blockBuilder.invoke("build", Block.class))).append(inputDictionaries.setElement(projectionIndex, dictionary)).append(outputDictionaries.setElement(projectionIndex, outputDictionary));
body.comment("Use processed dictionary, if available, else project it").append(new IfStatement().condition(equal(inputDictionaries.getElement(projectionIndex), dictionary)).ifTrue(outputDictionary.set(outputDictionaries.getElement(projectionIndex))).ifFalse(projectDictionary));
body.comment("Filter ids").append(outputIds.set(newArray(type(int[].class), cardinality))).append(new ForLoop().initialize(position.set(constantInt(0))).condition(lessThan(position, cardinality)).update(position.increment()).body(outputIds.setElement(position, castDictionaryBlock.invoke("getId", int.class, selectedPositions.getElement(position)))));
body.append(outputSourceId.set(dictionarySourceIds.invoke("get", Object.class, inputSourceId.cast(Object.class)).cast(DictionaryId.class)));
body.append(new IfStatement().condition(equal(outputSourceId, constantNull(DictionaryId.class))).ifTrue(new BytecodeBlock().append(outputSourceId.set(invokeStatic(DictionaryId.class, "randomDictionaryId", DictionaryId.class))).append(dictionarySourceIds.invoke("put", Object.class, inputSourceId.cast(Object.class), outputSourceId.cast(Object.class))).pop()));
body.append(newInstance(DictionaryBlock.class, cardinality, outputDictionary, outputIds, constantFalse(), outputSourceId).cast(Block.class).ret());
return method;
}
Aggregations