private static void generateFilterPageMethod( ClassDefinition classDefinition, RowExpression filter) { Parameter session = arg("session", ConnectorSession.class); Parameter page = arg("page", Page.class); MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "filterPage", type(int[].class), session, page); method.comment("Filter: %s rows in the page", filter.toString()); Scope scope = method.getScope(); Variable thisVariable = method.getThis(); BytecodeBlock body = method.getBody(); Variable positionCount = scope.declareVariable("positionCount", body, page.invoke("getPositionCount", int.class)); Variable selectedPositions = scope.declareVariable( "selectedPositions", body, newArray(type(int[].class), positionCount)); List<Integer> filterChannels = getInputChannels(filter); // extract block variables ImmutableList.Builder<Variable> blockVariablesBuilder = ImmutableList.<Variable>builder(); for (int channel : filterChannels) { Variable blockVariable = scope.declareVariable( "block_" + channel, body, page.invoke("getBlock", Block.class, constantInt(channel))); blockVariablesBuilder.add(blockVariable); } List<Variable> blockVariables = blockVariablesBuilder.build(); Variable selectedCount = scope.declareVariable("selectedCount", body, constantInt(0)); Variable position = scope.declareVariable(int.class, "position"); IfStatement ifStatement = new IfStatement(); ifStatement .condition(invokeFilter(thisVariable, session, blockVariables, position)) .ifTrue() .append(selectedPositions.setElement(selectedCount, position)) .append(selectedCount.increment()); body.append( new ForLoop() .initialize(position.set(constantInt(0))) .condition(lessThan(position, positionCount)) .update(position.increment()) .body(ifStatement)); body.append( invokeStatic(Arrays.class, "copyOf", int[].class, selectedPositions, selectedCount).ret()); }
private static void generateGetNonLazyPageMethod( ClassDefinition classDefinition, RowExpression filter, List<RowExpression> projections) { Parameter page = arg("page", Page.class); MethodDefinition method = classDefinition.declareMethod(a(PRIVATE), "getNonLazyPage", type(Page.class), page); Scope scope = method.getScope(); BytecodeBlock body = method.getBody(); List<Integer> allInputChannels = getInputChannels(concat(projections, ImmutableList.of(filter))); if (allInputChannels.isEmpty()) { body.append(page.ret()); return; } Variable index = scope.declareVariable(int.class, "index"); Variable channelCount = scope.declareVariable("channelCount", body, page.invoke("getChannelCount", int.class)); Variable blocks = scope.declareVariable("blocks", body, newArray(type(Block[].class), channelCount)); Variable inputBlock = scope.declareVariable(Block.class, "inputBlock"); Variable positionCount = scope.declareVariable("positionCount", body, page.invoke("getPositionCount", int.class)); Variable createNewPage = scope.declareVariable("createNewPage", body, constantFalse()); ForLoop forLoop = new ForLoop() .initialize(index.set(constantInt(0))) .condition(lessThan(index, channelCount)) .update(index.increment()) .body( new BytecodeBlock() .append(inputBlock.set(page.invoke("getBlock", Block.class, index))) .append( new IfStatement() .condition(inputBlock.instanceOf(LazyBlock.class)) .ifTrue( new BytecodeBlock() .append( blocks.setElement( index, inputBlock .cast(LazyBlock.class) .invoke("getBlock", Block.class))) .append(createNewPage.set(constantTrue()))) .ifFalse(blocks.setElement(index, inputBlock)))); body.append(forLoop); body.append( new IfStatement() .condition(createNewPage) .ifTrue(page.set(newInstance(Page.class, positionCount, blocks)))); body.append(page.ret()); }
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; }