use of io.airlift.bytecode.instruction.LabelNode in project hetu-core by openlookeng.
the class CursorProcessorCompiler method generateProcessMethod.
private static void generateProcessMethod(ClassDefinition classDefinition, int projections) {
Parameter session = arg("session", ConnectorSession.class);
Parameter yieldSignal = arg("yieldSignal", DriverYieldSignal.class);
Parameter cursor = arg("cursor", RecordCursor.class);
Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "process", type(CursorProcessorOutput.class), session, yieldSignal, cursor, pageBuilder);
Scope scope = method.getScope();
Variable completedPositionsVariable = scope.declareVariable(int.class, "completedPositions");
Variable finishedVariable = scope.declareVariable(boolean.class, "finished");
method.getBody().comment("int completedPositions = 0;").putVariable(completedPositionsVariable, 0).comment("boolean finished = false;").putVariable(finishedVariable, false);
// while loop loop body
LabelNode done = new LabelNode("done");
WhileLoop whileLoop = new WhileLoop().condition(constantTrue()).body(new BytecodeBlock().comment("if (pageBuilder.isFull() || yieldSignal.isSet()) return new CursorProcessorOutput(completedPositions, false);").append(new IfStatement().condition(or(pageBuilder.invoke("isFull", boolean.class), yieldSignal.invoke("isSet", boolean.class))).ifTrue(jump(done))).comment("if (!cursor.advanceNextPosition()) return new CursorProcessorOutput(completedPositions, true);").append(new IfStatement().condition(cursor.invoke("advanceNextPosition", boolean.class)).ifFalse(new BytecodeBlock().putVariable(finishedVariable, true).gotoLabel(done))).comment("do the projection").append(createProjectIfStatement(classDefinition, method, session, cursor, pageBuilder, projections)).comment("completedPositions++;").incrementVariable(completedPositionsVariable, (byte) 1));
method.getBody().append(whileLoop).visitLabel(done).append(newInstance(CursorProcessorOutput.class, completedPositionsVariable, finishedVariable).ret());
}
use of io.airlift.bytecode.instruction.LabelNode in project hetu-core by openlookeng.
the class DereferenceCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(FunctionHandle functionHandle, BytecodeGeneratorContext generator, Type returnType, List<RowExpression> arguments) {
checkArgument(arguments.size() == 2);
CallSiteBinder callSiteBinder = generator.getCallSiteBinder();
BytecodeBlock block = new BytecodeBlock().comment("DEREFERENCE").setDescription("DEREFERENCE");
Variable wasNull = generator.wasNull();
Variable rowBlock = generator.getScope().createTempVariable(Block.class);
int index = ((Number) ((ConstantExpression) arguments.get(1)).getValue()).intValue();
// clear the wasNull flag before evaluating the row value
block.putVariable(wasNull, false);
block.append(generator.generate(arguments.get(0))).putVariable(rowBlock);
IfStatement ifRowBlockIsNull = new IfStatement("if row block is null...").condition(wasNull);
Class<?> javaType = returnType.getJavaType();
LabelNode end = new LabelNode("end");
ifRowBlockIsNull.ifTrue().comment("if row block is null, push null to the stack and goto 'end' label (return)").putVariable(wasNull, true).pushJavaDefault(javaType).gotoLabel(end);
block.append(ifRowBlockIsNull);
IfStatement ifFieldIsNull = new IfStatement("if row field is null...");
ifFieldIsNull.condition().comment("call rowBlock.isNull(index)").append(rowBlock).push(index).invokeInterface(Block.class, "isNull", boolean.class, int.class);
ifFieldIsNull.ifTrue().comment("if the field is null, push null to stack").putVariable(wasNull, true).pushJavaDefault(javaType);
BytecodeExpression value = constantType(callSiteBinder, returnType).getValue(rowBlock, constantInt(index));
ifFieldIsNull.ifFalse().comment("otherwise call type.getTYPE(rowBlock, index)").append(value).putVariable(wasNull, false);
block.append(ifFieldIsNull).visitLabel(end);
return block;
}
use of io.airlift.bytecode.instruction.LabelNode in project hetu-core by openlookeng.
the class InCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(FunctionHandle functionHandle, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments) {
List<RowExpression> values = arguments.subList(1, arguments.size());
// empty IN statements are not allowed by the standard, and not possible here
// the implementation assumes this condition is always met
checkArgument(values.size() > 0, "values must not be empty");
Type type = arguments.get(0).getType();
Class<?> javaType = type.getJavaType();
SwitchGenerationCase switchGenerationCase = checkSwitchGenerationCase(type, values);
FunctionHandle hashCodeHandle = generatorContext.getFunctionManager().resolveOperatorFunctionHandle(HASH_CODE, fromTypes(type));
MethodHandle hashCodeFunction = generatorContext.getFunctionManager().getBuiltInScalarFunctionImplementation(hashCodeHandle).getMethodHandle();
FunctionHandle isIndeterminateHandle = generatorContext.getFunctionManager().resolveOperatorFunctionHandle(INDETERMINATE, fromTypes(type));
BuiltInScalarFunctionImplementation isIndeterminateFunction = generatorContext.getFunctionManager().getBuiltInScalarFunctionImplementation(isIndeterminateHandle);
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 (isDeterminateConstant(testValue, isIndeterminateFunction.getMethodHandle())) {
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();
Variable value = scope.createTempVariable(javaType);
BytecodeNode switchBlock;
Variable expression = scope.createTempVariable(int.class);
SwitchBuilder switchBuilder = new SwitchBuilder().expression(expression);
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), jump(match));
}
switchBuilder.defaultCase(jump(defaultLabel));
switchBlock = new BytecodeBlock().comment("lookupSwitch(<stackValue>))").append(new IfStatement().condition(invokeStatic(InCodeGenerator.class, "isInteger", boolean.class, value)).ifFalse(new BytecodeBlock().gotoLabel(defaultLabel))).append(expression.set(value.cast(int.class))).append(switchBuilder.build());
break;
case HASH_SWITCH:
for (Map.Entry<Integer, Collection<BytecodeNode>> bucket : hashBuckets.asMap().entrySet()) {
Collection<BytecodeNode> testValues = bucket.getValue();
BytecodeBlock caseBlock = buildInCase(generatorContext, scope, type, match, defaultLabel, value, testValues, false, isIndeterminateFunction);
switchBuilder.addCase(bucket.getKey(), caseBlock);
}
switchBuilder.defaultCase(jump(defaultLabel));
Binding hashCodeBinding = generatorContext.getCallSiteBinder().bind(hashCodeFunction);
switchBlock = new BytecodeBlock().comment("lookupSwitch(hashCode(<stackValue>))").getVariable(value).append(invoke(hashCodeBinding, HASH_CODE.name())).invokeStatic(Long.class, "hashCode", int.class, long.class).putVariable(expression).append(switchBuilder.build());
break;
case SET_CONTAINS:
Set<?> constantValuesSet = toFastutilHashSet(constantValues, type, metadata);
Binding constant = generatorContext.getCallSiteBinder().bind(constantValuesSet, constantValuesSet.getClass());
switchBlock = new BytecodeBlock().comment("inListSet.contains(<stackValue>)").append(new IfStatement().condition(new BytecodeBlock().comment("value").getVariable(value).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, match, noMatch, value, defaultBucket.build(), true, isIndeterminateFunction).setDescription("default");
BytecodeBlock block = new BytecodeBlock().comment("IN").append(generatorContext.generate(arguments.get(0))).append(ifWasNullPopAndGoto(scope, end, boolean.class, javaType)).putVariable(value).append(switchBlock).visitLabel(defaultLabel).append(defaultCaseBlock);
BytecodeBlock matchBlock = new BytecodeBlock().setDescription("match").visitLabel(match).append(generatorContext.wasNull().set(constantFalse())).push(true).gotoLabel(end);
block.append(matchBlock);
BytecodeBlock noMatchBlock = new BytecodeBlock().setDescription("noMatch").visitLabel(noMatch).push(false).gotoLabel(end);
block.append(noMatchBlock);
block.visitLabel(end);
return block;
}
use of io.airlift.bytecode.instruction.LabelNode in project hetu-core by openlookeng.
the class SwitchCodeGenerator method generateExpression.
@Override
public BytecodeNode generateExpression(FunctionHandle functionHandle, 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 SpecialForm && ((SpecialForm) last).getForm() == 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 SpecialForm && ((SpecialForm) clause).getForm() == WHEN);
RowExpression operand = ((SpecialForm) clause).getArguments().get(0);
RowExpression result = ((SpecialForm) clause).getArguments().get(1);
// call equals(value, operand)
FunctionHandle equalsFunction = generatorContext.getFunctionManager().resolveOperatorFunctionHandle(EQUAL, fromTypes(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(EQUAL.name(), generatorContext.getFunctionManager().getBuiltInScalarFunctionImplementation(equalsFunction), ImmutableList.of(generatorContext.generate(operand, Optional.empty()), 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 io.airlift.bytecode.instruction.LabelNode in project hetu-core by openlookeng.
the class BytecodeUtils method unboxPrimitiveIfNecessary.
public static BytecodeBlock unboxPrimitiveIfNecessary(Scope scope, Class<?> boxedType) {
BytecodeBlock block = new BytecodeBlock();
LabelNode end = new LabelNode("end");
Class<?> unboxedType = Primitives.unwrap(boxedType);
Variable wasNull = scope.getVariable("wasNull");
if (unboxedType.isPrimitive()) {
LabelNode notNull = new LabelNode("notNull");
block.dup(boxedType).ifNotNullGoto(notNull).append(wasNull.set(constantTrue())).comment("swap boxed null with unboxed default").pop(boxedType).pushJavaDefault(unboxedType).gotoLabel(end).visitLabel(notNull).append(unboxPrimitive(unboxedType));
} else {
block.dup(boxedType).ifNotNullGoto(end).append(wasNull.set(constantTrue()));
}
block.visitLabel(end);
return block;
}
Aggregations