use of com.facebook.presto.bytecode.BytecodeNode 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;
}
use of com.facebook.presto.bytecode.BytecodeNode in project presto by prestodb.
the class OrCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generator, Type returnType, List<RowExpression> arguments) {
Preconditions.checkArgument(arguments.size() == 2);
Variable wasNull = generator.wasNull();
BytecodeBlock block = new BytecodeBlock().comment("OR").setDescription("OR");
BytecodeNode left = generator.generate(arguments.get(0));
BytecodeNode right = generator.generate(arguments.get(1));
block.append(left);
IfStatement ifLeftIsNull = new IfStatement("if left wasNull...").condition(wasNull);
LabelNode end = new LabelNode("end");
ifLeftIsNull.ifTrue(new BytecodeBlock().comment("clear the null flag, pop left value off stack, and push left null flag on the stack (true)").append(wasNull.set(constantFalse())).pop(// discard left value
arguments.get(0).getType().getJavaType()).push(true));
LabelNode leftIsFalse = new LabelNode("leftIsFalse");
ifLeftIsNull.ifFalse(new BytecodeBlock().comment("if left is true, push true, and goto end").ifFalseGoto(leftIsFalse).push(true).gotoLabel(end).comment("left was false; push left null flag on the stack (false)").visitLabel(leftIsFalse).push(false));
block.append(ifLeftIsNull);
// At this point we know the left expression was either NULL or FALSE. The stack contains a single boolean
// value for this expression which indicates if the left value was NULL.
// eval right!
block.append(right);
IfStatement ifRightIsNull = new IfStatement("if right wasNull...").condition(wasNull);
// this leaves a single boolean on the stack which is ignored since the value in NULL
ifRightIsNull.ifTrue().comment("right was null, pop the right value off the stack; wasNull flag remains set to TRUE").pop(arguments.get(1).getType().getJavaType());
LabelNode rightIsTrue = new LabelNode("rightIsTrue");
ifRightIsNull.ifFalse().comment("if right is true, pop left null flag off stack, push true and goto end").ifFalseGoto(rightIsTrue).pop(boolean.class).push(true).gotoLabel(end).comment("right was false; store left null flag (on stack) in wasNull variable, and push false").visitLabel(rightIsTrue).putVariable(wasNull).push(false);
block.append(ifRightIsNull).visitLabel(end);
return block;
}
use of com.facebook.presto.bytecode.BytecodeNode in project presto by prestodb.
the class InCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments) {
BytecodeNode value = generatorContext.generate(arguments.get(0));
List<RowExpression> values = arguments.subList(1, arguments.size());
ImmutableList.Builder<BytecodeNode> valuesBytecode = ImmutableList.builder();
for (int i = 1; i < arguments.size(); i++) {
BytecodeNode testNode = generatorContext.generate(arguments.get(i));
valuesBytecode.add(testNode);
}
Type type = arguments.get(0).getType();
Class<?> javaType = type.getJavaType();
SwitchGenerationCase switchGenerationCase = checkSwitchGenerationCase(type, values);
Signature hashCodeSignature = internalOperator(HASH_CODE, BIGINT, ImmutableList.of(type));
MethodHandle hashCodeFunction = generatorContext.getRegistry().getScalarFunctionImplementation(hashCodeSignature).getMethodHandle();
ImmutableListMultimap.Builder<Integer, BytecodeNode> hashBucketsBuilder = ImmutableListMultimap.builder();
ImmutableList.Builder<BytecodeNode> defaultBucket = ImmutableList.builder();
ImmutableSet.Builder<Object> constantValuesBuilder = ImmutableSet.builder();
for (RowExpression testValue : values) {
BytecodeNode testBytecode = generatorContext.generate(testValue);
if (testValue instanceof ConstantExpression && ((ConstantExpression) testValue).getValue() != null) {
ConstantExpression constant = (ConstantExpression) testValue;
Object object = constant.getValue();
switch(switchGenerationCase) {
case DIRECT_SWITCH:
case SET_CONTAINS:
constantValuesBuilder.add(object);
break;
case HASH_SWITCH:
try {
int hashCode = toIntExact(Long.hashCode((Long) hashCodeFunction.invoke(object)));
hashBucketsBuilder.put(hashCode, testBytecode);
} catch (Throwable throwable) {
throw new IllegalArgumentException("Error processing IN statement: error calculating hash code for " + object, throwable);
}
break;
default:
throw new IllegalArgumentException("Not supported switch generation case: " + switchGenerationCase);
}
} else {
defaultBucket.add(testBytecode);
}
}
ImmutableListMultimap<Integer, BytecodeNode> hashBuckets = hashBucketsBuilder.build();
ImmutableSet<Object> constantValues = constantValuesBuilder.build();
LabelNode end = new LabelNode("end");
LabelNode match = new LabelNode("match");
LabelNode noMatch = new LabelNode("noMatch");
LabelNode defaultLabel = new LabelNode("default");
Scope scope = generatorContext.getScope();
BytecodeNode switchBlock;
BytecodeBlock switchCaseBlocks = new BytecodeBlock();
LookupSwitch.LookupSwitchBuilder switchBuilder = lookupSwitchBuilder();
switch(switchGenerationCase) {
case DIRECT_SWITCH:
// For these types, it's safe to not use presto HASH_CODE and EQUAL operator.
for (Object constantValue : constantValues) {
switchBuilder.addCase(toIntExact((Long) constantValue), match);
}
switchBuilder.defaultCase(defaultLabel);
switchBlock = new BytecodeBlock().comment("lookupSwitch(<stackValue>))").dup(javaType).append(new IfStatement().condition(new BytecodeBlock().dup(javaType).invokeStatic(InCodeGenerator.class, "isInteger", boolean.class, long.class)).ifFalse(new BytecodeBlock().pop(javaType).gotoLabel(defaultLabel))).longToInt().append(switchBuilder.build());
break;
case HASH_SWITCH:
for (Map.Entry<Integer, Collection<BytecodeNode>> bucket : hashBuckets.asMap().entrySet()) {
LabelNode label = new LabelNode("inHash" + bucket.getKey());
switchBuilder.addCase(bucket.getKey(), label);
Collection<BytecodeNode> testValues = bucket.getValue();
BytecodeBlock caseBlock = buildInCase(generatorContext, scope, type, label, match, defaultLabel, testValues, false);
switchCaseBlocks.append(caseBlock.setDescription("case " + bucket.getKey()));
}
switchBuilder.defaultCase(defaultLabel);
Binding hashCodeBinding = generatorContext.getCallSiteBinder().bind(hashCodeFunction);
switchBlock = new BytecodeBlock().comment("lookupSwitch(hashCode(<stackValue>))").dup(javaType).append(invoke(hashCodeBinding, hashCodeSignature)).invokeStatic(Long.class, "hashCode", int.class, long.class).append(switchBuilder.build()).append(switchCaseBlocks);
break;
case SET_CONTAINS:
Set<?> constantValuesSet = toFastutilHashSet(constantValues, type, registry);
Binding constant = generatorContext.getCallSiteBinder().bind(constantValuesSet, constantValuesSet.getClass());
switchBlock = new BytecodeBlock().comment("inListSet.contains(<stackValue>)").append(new IfStatement().condition(new BytecodeBlock().comment("value").dup(javaType).comment("set").append(loadConstant(constant)).invokeStatic(FastutilSetHelper.class, "in", boolean.class, javaType.isPrimitive() ? javaType : Object.class, constantValuesSet.getClass())).ifTrue(jump(match)));
break;
default:
throw new IllegalArgumentException("Not supported switch generation case: " + switchGenerationCase);
}
BytecodeBlock defaultCaseBlock = buildInCase(generatorContext, scope, type, defaultLabel, match, noMatch, defaultBucket.build(), true).setDescription("default");
BytecodeBlock block = new BytecodeBlock().comment("IN").append(value).append(ifWasNullPopAndGoto(scope, end, boolean.class, javaType)).append(switchBlock).append(defaultCaseBlock);
BytecodeBlock matchBlock = new BytecodeBlock().setDescription("match").visitLabel(match).pop(javaType).append(generatorContext.wasNull().set(constantFalse())).push(true).gotoLabel(end);
block.append(matchBlock);
BytecodeBlock noMatchBlock = new BytecodeBlock().setDescription("noMatch").visitLabel(noMatch).pop(javaType).push(false).gotoLabel(end);
block.append(noMatchBlock);
block.visitLabel(end);
return block;
}
use of com.facebook.presto.bytecode.BytecodeNode in project presto by prestodb.
the class PageProcessorCompiler method generateFilterMethod.
private void generateFilterMethod(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, RowExpression filter) {
PreGeneratedExpressions preGeneratedExpressions = generateMethodsForLambdaAndTry(classDefinition, callSiteBinder, cachedInstanceBinder, filter, "filter");
Parameter session = arg("session", ConnectorSession.class);
List<Parameter> blocks = toBlockParameters(getInputChannels(filter));
Parameter position = arg("position", int.class);
MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "filter", type(boolean.class), ImmutableList.<Parameter>builder().add(session).addAll(blocks).add(position).build());
method.comment("Filter: %s", filter.toString());
BytecodeBlock body = method.getBody();
Scope scope = method.getScope();
Variable wasNullVariable = scope.declareVariable("wasNull", body, constantFalse());
BytecodeExpressionVisitor visitor = new BytecodeExpressionVisitor(callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(callSiteBinder), metadata.getFunctionRegistry(), preGeneratedExpressions);
BytecodeNode visitorBody = filter.accept(visitor, scope);
Variable result = scope.declareVariable(boolean.class, "result");
body.append(visitorBody).putVariable(result).append(new IfStatement().condition(wasNullVariable).ifTrue(constantFalse().ret()).ifFalse(result.ret()));
}
use of com.facebook.presto.bytecode.BytecodeNode in project presto by prestodb.
the class TryCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext context, Type returnType, List<RowExpression> arguments) {
checkArgument(arguments.size() == 1, "try methods only contain a single expression");
checkArgument(getOnlyElement(arguments) instanceof CallExpression, "try methods must contain a call expression");
CallExpression innerCallExpression = (CallExpression) getOnlyElement(arguments);
checkState(tryMethodsMap.containsKey(innerCallExpression), "try methods map does not contain this try call");
MethodDefinition definition = tryMethodsMap.get(innerCallExpression);
ImmutableList<Variable> invokeArguments = definition.getParameters().stream().map(parameter -> context.getScope().getVariable(parameter.getName())).collect(toImmutableList());
return new BytecodeBlock().append(context.getScope().getThis().invoke(definition, invokeArguments)).append(unboxPrimitiveIfNecessary(context.getScope(), Primitives.wrap(innerCallExpression.getType().getJavaType())));
}
Aggregations