use of com.facebook.presto.bytecode.Variable 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.Variable in project presto by prestodb.
the class RowConstructorCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext context, Type rowType, List<RowExpression> arguments) {
BytecodeBlock block = new BytecodeBlock().setDescription("Constructor for " + rowType.toString());
CallSiteBinder binder = context.getCallSiteBinder();
Scope scope = context.getScope();
List<Type> types = rowType.getTypeParameters();
block.comment("BlockBuilder blockBuilder = new InterleavedBlockBuilder(types, new BlockBuilderStatus(), 1);");
Variable blockBuilder = scope.createTempVariable(BlockBuilder.class);
Binding typesBinding = binder.bind(types, List.class);
block.append(blockBuilder.set(newInstance(InterleavedBlockBuilder.class, loadConstant(typesBinding), newInstance(BlockBuilderStatus.class), constantInt(1))));
for (int i = 0; i < arguments.size(); ++i) {
Type fieldType = types.get(i);
Class<?> javaType = fieldType.getJavaType();
if (javaType == void.class) {
block.comment(i + "-th field type of row is undefined");
block.append(blockBuilder.invoke("appendNull", BlockBuilder.class).pop());
} else {
Variable field = scope.createTempVariable(javaType);
block.comment("Clean wasNull and Generate + " + i + "-th field of row");
block.append(context.wasNull().set(constantFalse()));
block.append(context.generate(arguments.get(i)));
block.putVariable(field);
block.append(new IfStatement().condition(context.wasNull()).ifTrue(blockBuilder.invoke("appendNull", BlockBuilder.class).pop()).ifFalse(constantType(binder, fieldType).writeValue(blockBuilder, field).pop()));
}
}
block.comment("put (Block) blockBuilder.build(); wasNull = false;");
block.append(blockBuilder.invoke("build", Block.class));
block.append(context.wasNull().set(constantFalse()));
return block;
}
use of com.facebook.presto.bytecode.Variable in project presto by prestodb.
the class SwitchCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments) {
// TODO: compile as
/*
hashCode = hashCode(<value>)
// all constant expressions before a non-constant
switch (hashCode) {
case ...:
if (<value> == <constant1>) {
...
}
else if (<value> == <constant2>) {
...
}
else if (...) {
}
case ...:
...
}
if (<value> == <non-constant1>) {
...
}
else if (<value> == <non-constant2>) {
...
}
...
// repeat with next sequence of constant expressions
*/
Scope scope = generatorContext.getScope();
// process value, else, and all when clauses
RowExpression value = arguments.get(0);
BytecodeNode valueBytecode = generatorContext.generate(value);
BytecodeNode elseValue;
List<RowExpression> whenClauses;
RowExpression last = arguments.get(arguments.size() - 1);
if (last instanceof CallExpression && ((CallExpression) last).getSignature().getName().equals("WHEN")) {
whenClauses = arguments.subList(1, arguments.size());
elseValue = new BytecodeBlock().append(generatorContext.wasNull().set(constantTrue())).pushJavaDefault(returnType.getJavaType());
} else {
whenClauses = arguments.subList(1, arguments.size() - 1);
elseValue = generatorContext.generate(last);
}
// determine the type of the value and result
Class<?> valueType = value.getType().getJavaType();
// evaluate the value and store it in a variable
LabelNode nullValue = new LabelNode("nullCondition");
Variable tempVariable = scope.createTempVariable(valueType);
BytecodeBlock block = new BytecodeBlock().append(valueBytecode).append(BytecodeUtils.ifWasNullClearPopAndGoto(scope, nullValue, void.class, valueType)).putVariable(tempVariable);
BytecodeNode getTempVariableNode = VariableInstruction.loadVariable(tempVariable);
// build the statements
elseValue = new BytecodeBlock().visitLabel(nullValue).append(elseValue);
// reverse list because current if statement builder doesn't support if/else so we need to build the if statements bottom up
for (RowExpression clause : Lists.reverse(whenClauses)) {
Preconditions.checkArgument(clause instanceof CallExpression && ((CallExpression) clause).getSignature().getName().equals("WHEN"));
RowExpression operand = ((CallExpression) clause).getArguments().get(0);
RowExpression result = ((CallExpression) clause).getArguments().get(1);
// call equals(value, operand)
Signature equalsFunction = generatorContext.getRegistry().resolveOperator(OperatorType.EQUAL, ImmutableList.of(value.getType(), operand.getType()));
// TODO: what if operand is null? It seems that the call will return "null" (which is cleared below)
// and the code only does the right thing because the value in the stack for that scenario is
// Java's default for boolean == false
// This code should probably be checking for wasNull after the call and "failing" the equality
// check if wasNull is true
BytecodeNode equalsCall = generatorContext.generateCall(equalsFunction.getName(), generatorContext.getRegistry().getScalarFunctionImplementation(equalsFunction), ImmutableList.of(generatorContext.generate(operand), getTempVariableNode));
BytecodeBlock condition = new BytecodeBlock().append(equalsCall).append(generatorContext.wasNull().set(constantFalse()));
elseValue = new IfStatement("when").condition(condition).ifTrue(generatorContext.generate(result)).ifFalse(elseValue);
}
return block.append(elseValue);
}
use of com.facebook.presto.bytecode.Variable 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.Variable 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