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()); }
private static BytecodeNode invokeProject( Variable objRef, Variable session, List<? extends Variable> blockVariables, BytecodeExpression position, Variable pageBuilder, BytecodeExpression projectionIndex, MethodDefinition projectionMethod) { BytecodeExpression blockBuilder = pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, projectionIndex); List<BytecodeExpression> params = ImmutableList.<BytecodeExpression>builder() .add(session) .addAll(blockVariables) .add(position) .add(blockBuilder) .build(); return new BytecodeBlock().append(objRef.invoke(projectionMethod, params)); }
private static MethodDefinition generateProjectDictionaryMethod( ClassDefinition classDefinition, String methodName, RowExpression projection, MethodDefinition project, MethodDefinition projectColumnar) { 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); List<Parameter> params = 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) { body.append(thisVariable.invoke(projectColumnar, params).ret()); return method; } Variable inputBlock = scope.declareVariable( "inputBlock", body, page.invoke( "getBlock", Block.class, constantInt(Iterables.getOnlyElement(inputChannels)))); IfStatement ifStatement = new IfStatement() .condition(inputBlock.instanceOf(DictionaryBlock.class)) .ifFalse(thisVariable.invoke(projectColumnar, params).ret()); body.append(ifStatement); 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 ids = scope.declareVariable(Slice.class, "ids"); Variable dictionaryCount = scope.declareVariable(int.class, "dictionaryCount"); 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)); body.comment("Extract dictionary and ids") .append( dictionary.set( inputBlock.cast(DictionaryBlock.class).invoke("getDictionary", Block.class))) .append(ids.set(inputBlock.cast(DictionaryBlock.class).invoke("getIds", Slice.class))) .append(dictionaryCount.set(dictionary.invoke("getPositionCount", int.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, ids.invoke( "getInt", int.class, multiply( selectedPositions.getElement(position), constantInt(SIZE_OF_INT)))))); body.append( newInstance( DictionaryBlock.class, cardinality, outputDictionary, invokeStatic(Slices.class, "wrappedIntArray", Slice.class, outputIds)) .cast(Block.class) .ret()); return method; }
private static MethodDefinition generateProjectColumnarMethod( ClassDefinition classDefinition, CallSiteBinder callSiteBinder, String methodName, RowExpression projection, MethodDefinition projectionMethod) { 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); List<Parameter> params = 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(); ImmutableList.Builder<Variable> builder = ImmutableList.<Variable>builder(); for (int channel : getInputChannels(projection)) { Variable blockVariable = scope.declareVariable( "block_" + channel, body, page.invoke("getBlock", Block.class, constantInt(channel))); builder.add(blockVariable); } List<Variable> inputs = builder.build(); Variable positionCount = scope.declareVariable("positionCount", body, page.invoke("getPositionCount", int.class)); Variable position = scope.declareVariable("position", body, constantInt(0)); Variable cardinality = scope.declareVariable("cardinality", body, selectedPositions.length()); Variable outputBlock = scope.declareVariable(Block.class, "outputBlock"); Variable blockBuilder = scope.declareVariable( "blockBuilder", body, pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, projectionIndex)); Variable type = scope.declareVariable( "type", body, pageBuilder.invoke("getType", Type.class, projectionIndex)); BytecodeBlock projectBlock = new BytecodeBlock() .append( new ForLoop() .initialize(position.set(constantInt(0))) .condition(lessThan(position, cardinality)) .update(position.increment()) .body( invokeProject( thisVariable, session, inputs, selectedPositions.getElement(position), pageBuilder, projectionIndex, projectionMethod))) .append(outputBlock.set(blockBuilder.invoke("build", Block.class))); if (isIdentityExpression(projection)) { // if nothing is filtered out, copy the entire block, else project it body.append( new IfStatement() .condition(equal(cardinality, positionCount)) .ifTrue(outputBlock.set(inputs.get(0))) .ifFalse(projectBlock)); } else if (isConstantExpression(projection)) { // if projection is a constant, create RLE block of constant expression with cardinality // positions ConstantExpression constantExpression = (ConstantExpression) projection; verify(getInputChannels(projection).isEmpty()); BytecodeExpression value = loadConstant(callSiteBinder, constantExpression.getValue(), Object.class); body.append( outputBlock.set( invokeStatic( RunLengthEncodedBlock.class, "create", Block.class, type, value, cardinality))); } else { body.append(projectBlock); } body.append(outputBlock.ret()); return method; }