private static <T> void generateSerialize( ClassDefinition definition, Class<T> clazz, List<StateField> fields) { CompilerContext compilerContext = new CompilerContext(); Block serializerBody = definition .declareMethod( compilerContext, a(PUBLIC), "serialize", type(void.class), arg("state", Object.class), arg("out", BlockBuilder.class)) .getBody(); if (fields.size() == 1) { generatePrimitiveSerializer(serializerBody, getGetter(clazz, fields.get(0))); } else { Variable slice = compilerContext.declareVariable(Slice.class, "slice"); int size = serializedSizeOf(clazz); serializerBody .comment("Slice slice = Slices.allocate(%d);", size) .push(size) .invokeStatic(Slices.class, "allocate", Slice.class, int.class) .putVariable(slice); for (StateField field : fields) { generateSerializeFieldToSlice( serializerBody, slice, getGetter(clazz, field), offsetOfField(field, fields)); } serializerBody .comment("out.appendSlice(slice);") .getVariable("out") .getVariable(slice) .push(0) .push(size) .invokeInterface( BlockBuilder.class, "writeBytes", BlockBuilder.class, Slice.class, int.class, int.class) .invokeInterface(BlockBuilder.class, "closeEntry", BlockBuilder.class) .pop(); } serializerBody.ret(); }
private static <T> void generateDeserialize( ClassDefinition definition, Class<T> clazz, List<StateField> fields) { CompilerContext compilerContext = new CompilerContext(); Block deserializerBody = definition .declareMethod( compilerContext, a(PUBLIC), "deserialize", type(void.class), arg("block", com.facebook.presto.spi.block.Block.class), arg("index", int.class), arg("state", Object.class)) .getBody(); if (fields.size() == 1) { generatePrimitiveDeserializer(deserializerBody, getSetter(clazz, fields.get(0))); } else { Variable slice = compilerContext.declareVariable(Slice.class, "slice"); deserializerBody .comment("Slice slice = block.getSlice(index, 0, block.getLength(index));") .getVariable("block") .getVariable("index") .push(0) .getVariable("block") .getVariable("index") .invokeInterface( com.facebook.presto.spi.block.Block.class, "getLength", int.class, int.class) .invokeInterface( com.facebook.presto.spi.block.Block.class, "getSlice", Slice.class, int.class, int.class, int.class) .putVariable(slice); for (StateField field : fields) { generateDeserializeFromSlice( deserializerBody, slice, getSetter(clazz, field), offsetOfField(field, fields)); } } deserializerBody.ret(); }
private Class<?> generateProjectMethod( CallSiteBinder callSiteBinder, ClassDefinition classDefinition, String methodName, RowExpression projection, boolean sourceIsCursor) { MethodDefinition projectionMethod; if (sourceIsCursor) { projectionMethod = classDefinition.declareMethod( new CompilerContext(BOOTSTRAP_METHOD), a(PUBLIC), methodName, type(void.class), arg("cursor", RecordCursor.class), arg("output", BlockBuilder.class)); } else { ImmutableList.Builder<NamedParameterDefinition> parameters = ImmutableList.builder(); parameters.add(arg("position", int.class)); parameters.addAll(toBlockParameters(getInputChannels(projection))); parameters.add(arg("output", BlockBuilder.class)); projectionMethod = classDefinition.declareMethod( new CompilerContext(BOOTSTRAP_METHOD), a(PUBLIC), methodName, type(void.class), parameters.build()); } projectionMethod.comment("Projection: %s", projection.toString()); // generate body code CompilerContext context = projectionMethod.getCompilerContext(); context.declareVariable(type(boolean.class), "wasNull"); Block getSessionByteCode = new Block(context) .pushThis() .getField(classDefinition.getType(), "session", type(ConnectorSession.class)); ByteCodeNode body = compileExpression(callSiteBinder, projection, sourceIsCursor, context, getSessionByteCode); projectionMethod .getBody() .comment("boolean wasNull = false;") .putVariable("wasNull", false) .getVariable("output") .append(body); Type projectionType = projection.getType(); Block notNullBlock = new Block(context); if (projectionType.getJavaType() == boolean.class) { notNullBlock .comment("output.append(<booleanStackValue>);") .invokeInterface(BlockBuilder.class, "appendBoolean", BlockBuilder.class, boolean.class) .pop(); } else if (projectionType.getJavaType() == long.class) { notNullBlock .comment("output.append(<longStackValue>);") .invokeInterface(BlockBuilder.class, "appendLong", BlockBuilder.class, long.class) .pop(); } else if (projectionType.getJavaType() == double.class) { notNullBlock .comment("output.append(<doubleStackValue>);") .invokeInterface(BlockBuilder.class, "appendDouble", BlockBuilder.class, double.class) .pop(); } else if (projectionType.getJavaType() == Slice.class) { notNullBlock .comment("output.append(<sliceStackValue>);") .invokeInterface(BlockBuilder.class, "appendSlice", BlockBuilder.class, Slice.class) .pop(); } else { throw new UnsupportedOperationException("Type " + projectionType + " can not be output yet"); } Block nullBlock = new Block(context) .comment("output.appendNull();") .pop(projectionType.getJavaType()) .invokeInterface(BlockBuilder.class, "appendNull", BlockBuilder.class) .pop(); projectionMethod .getBody() .comment("if the result was null, appendNull; otherwise append the value") .append( new IfStatement( context, new Block(context).getVariable("wasNull"), nullBlock, notNullBlock)) .ret(); return projectionType.getJavaType(); }
private void generateFilterAndProjectCursorMethod( ClassDefinition classDefinition, List<RowExpression> projections) { MethodDefinition filterAndProjectMethod = classDefinition.declareMethod( new CompilerContext(BOOTSTRAP_METHOD), a(PUBLIC), "filterAndProjectRowOriented", type(int.class), arg("cursor", RecordCursor.class), arg("pageBuilder", PageBuilder.class)); CompilerContext compilerContext = filterAndProjectMethod.getCompilerContext(); LocalVariableDefinition completedPositionsVariable = compilerContext.declareVariable(int.class, "completedPositions"); filterAndProjectMethod .getBody() .comment("int completedPositions = 0;") .putVariable(completedPositionsVariable, 0); // // for loop loop body // LabelNode done = new LabelNode("done"); ForLoopBuilder forLoop = ForLoop.forLoopBuilder(compilerContext) .initialize(NOP) .condition( new Block(compilerContext) .comment("completedPositions < 16384") .getVariable(completedPositionsVariable) .push(16384) .invokeStatic( CompilerOperations.class, "lessThan", boolean.class, int.class, int.class)) .update( new Block(compilerContext) .comment("completedPositions++") .incrementVariable(completedPositionsVariable, (byte) 1)); Block forLoopBody = new Block(compilerContext); forLoop.body(forLoopBody); forLoopBody .comment("if (pageBuilder.isFull()) break;") .append( new Block(compilerContext) .getVariable("pageBuilder") .invokeVirtual(PageBuilder.class, "isFull", boolean.class) .ifTrueGoto(done)); forLoopBody .comment("if (!cursor.advanceNextPosition()) break;") .append( new Block(compilerContext) .getVariable("cursor") .invokeInterface(RecordCursor.class, "advanceNextPosition", boolean.class) .ifFalseGoto(done)); // if (filter(cursor)) IfStatementBuilder ifStatement = new IfStatementBuilder(compilerContext); ifStatement.condition( new Block(compilerContext) .pushThis() .getVariable("cursor") .invokeVirtual( classDefinition.getType(), "filter", type(boolean.class), type(RecordCursor.class))); Block trueBlock = new Block(compilerContext); ifStatement.ifTrue(trueBlock); if (projections.isEmpty()) { // pageBuilder.declarePosition(); trueBlock .getVariable("pageBuilder") .invokeVirtual(PageBuilder.class, "declarePosition", void.class); } else { // project_43(block..., pageBuilder.getBlockBuilder(42))); for (int projectionIndex = 0; projectionIndex < projections.size(); projectionIndex++) { trueBlock.pushThis(); trueBlock.getVariable("cursor"); // pageBuilder.getBlockBuilder(0) trueBlock .getVariable("pageBuilder") .push(projectionIndex) .invokeVirtual(PageBuilder.class, "getBlockBuilder", BlockBuilder.class, int.class); // project(block..., blockBuilder) trueBlock.invokeVirtual( classDefinition.getType(), "project_" + projectionIndex, type(void.class), type(RecordCursor.class), type(BlockBuilder.class)); } } forLoopBody.append(ifStatement.build()); filterAndProjectMethod .getBody() .append(forLoop.build()) .visitLabel(done) .comment("return completedPositions;") .getVariable("completedPositions") .retInt(); }
private void generateFilterAndProjectRowOriented( ClassDefinition classDefinition, RowExpression filter, List<RowExpression> projections) { MethodDefinition filterAndProjectMethod = classDefinition.declareMethod( new CompilerContext(BOOTSTRAP_METHOD), a(PUBLIC), "filterAndProjectRowOriented", type(void.class), arg("page", com.facebook.presto.operator.Page.class), arg("pageBuilder", PageBuilder.class)); CompilerContext compilerContext = filterAndProjectMethod.getCompilerContext(); LocalVariableDefinition positionVariable = compilerContext.declareVariable(int.class, "position"); LocalVariableDefinition rowsVariable = compilerContext.declareVariable(int.class, "rows"); filterAndProjectMethod .getBody() .comment("int rows = page.getPositionCount();") .getVariable("page") .invokeVirtual(com.facebook.presto.operator.Page.class, "getPositionCount", int.class) .putVariable(rowsVariable); List<Integer> allInputChannels = getInputChannels(Iterables.concat(projections, ImmutableList.of(filter))); for (int channel : allInputChannels) { LocalVariableDefinition blockVariable = compilerContext.declareVariable( com.facebook.presto.spi.block.Block.class, "block_" + channel); filterAndProjectMethod .getBody() .comment("Block %s = page.getBlock(%s);", blockVariable.getName(), channel) .getVariable("page") .push(channel) .invokeVirtual( com.facebook.presto.operator.Page.class, "getBlock", com.facebook.presto.spi.block.Block.class, int.class) .putVariable(blockVariable); } // // for loop body // // for (position = 0; position < rows; position++) ForLoopBuilder forLoop = forLoopBuilder(compilerContext) .comment("for (position = 0; position < rows; position++)") .initialize(new Block(compilerContext).putVariable(positionVariable, 0)) .condition( new Block(compilerContext) .getVariable(positionVariable) .getVariable(rowsVariable) .invokeStatic( CompilerOperations.class, "lessThan", boolean.class, int.class, int.class)) .update(new Block(compilerContext).incrementVariable(positionVariable, (byte) 1)); Block forLoopBody = new Block(compilerContext); IfStatementBuilder ifStatement = new IfStatementBuilder(compilerContext).comment("if (filter(position, blocks...)"); Block condition = new Block(compilerContext); condition.pushThis(); condition.getVariable(positionVariable); List<Integer> filterInputChannels = getInputChannels(filter); for (int channel : filterInputChannels) { condition.getVariable("block_" + channel); } condition.invokeVirtual( classDefinition.getType(), "filter", type(boolean.class), ImmutableList.<ParameterizedType>builder() .add(type(int.class)) .addAll( nCopies( filterInputChannels.size(), type(com.facebook.presto.spi.block.Block.class))) .build()); ifStatement.condition(condition); Block trueBlock = new Block(compilerContext); if (projections.isEmpty()) { trueBlock .comment("pageBuilder.declarePosition()") .getVariable("pageBuilder") .invokeVirtual(PageBuilder.class, "declarePosition", void.class); } else { // pageBuilder.getBlockBuilder(0).append(block.getDouble(0); for (int projectionIndex = 0; projectionIndex < projections.size(); projectionIndex++) { trueBlock.comment( "project_%s(position, blocks..., pageBuilder.getBlockBuilder(%s))", projectionIndex, projectionIndex); trueBlock.pushThis(); List<Integer> projectionInputs = getInputChannels(projections.get(projectionIndex)); trueBlock.getVariable(positionVariable); for (int channel : projectionInputs) { trueBlock.getVariable("block_" + channel); } // pageBuilder.getBlockBuilder(0) trueBlock .getVariable("pageBuilder") .push(projectionIndex) .invokeVirtual(PageBuilder.class, "getBlockBuilder", BlockBuilder.class, int.class); // project(position, block_0, block_1, blockBuilder) trueBlock.invokeVirtual( classDefinition.getType(), "project_" + projectionIndex, type(void.class), ImmutableList.<ParameterizedType>builder() .add(type(int.class)) .addAll( nCopies( projectionInputs.size(), type(com.facebook.presto.spi.block.Block.class))) .add(type(BlockBuilder.class)) .build()); } } ifStatement.ifTrue(trueBlock); forLoopBody.append(ifStatement.build()); filterAndProjectMethod.getBody().append(forLoop.body(forLoopBody).build()); filterAndProjectMethod.getBody().ret(); }
public WhileLoop build() { WhileLoop whileLoop = new WhileLoop(context, comment, condition, body, beginLabel, endLabel); context.popIterationScope(); return whileLoop; }
public WhileLoopBuilder(CompilerContext context) { this.context = context; context.pushIterationScope(beginLabel, endLabel); }