public static void assertSetPoint(Function<ByteCodeExpression, ByteCodeExpression> setX) throws Exception { Function<Scope, ByteCodeNode> nodeGenerator = scope -> { Variable point = scope.declareVariable(Point.class, "point"); ByteCodeExpression setExpression = setX.apply(point); assertEquals(setExpression.toString(), "point.x = 42;"); return new ByteCodeBlock() .append(point.set(newInstance(Point.class, constantInt(3), constantInt(7)))) .append(setExpression) .append(point.ret()); }; assertByteCodeNode(nodeGenerator, type(Point.class), new Point(42, 7)); }
public IncrementVariableInstruction(Variable variable, byte increment) { super(variable); String type = variable.getType().getClassName(); Preconditions.checkArgument( ImmutableList.of("byte", "short", "int").contains(type), "variable must be an byte, short or int, but is %s", type); this.increment = increment; }
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 void generateFilterMethod( ClassDefinition classDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, RowExpression filter) { Parameter session = arg("session", ConnectorSession.class); Parameter position = arg("position", int.class); List<Parameter> blocks = toBlockParameters(getInputChannels(filter)); 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, position, wasNullVariable), metadata.getFunctionRegistry()); 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())); }
private static void generateConstructor( ClassDefinition classDefinition, CachedInstanceBinder cachedInstanceBinder, int projectionCount) { MethodDefinition constructorDefinition = classDefinition.declareConstructor(a(PUBLIC)); FieldDefinition inputDictionaries = classDefinition.declareField(a(PRIVATE, FINAL), "inputDictionaries", Block[].class); FieldDefinition outputDictionaries = classDefinition.declareField(a(PRIVATE, FINAL), "outputDictionaries", Block[].class); BytecodeBlock body = constructorDefinition.getBody(); Variable thisVariable = constructorDefinition.getThis(); body.comment("super();").append(thisVariable).invokeConstructor(Object.class); body.append( thisVariable.setField(inputDictionaries, newArray(type(Block[].class), projectionCount))); body.append( thisVariable.setField(outputDictionaries, newArray(type(Block[].class), projectionCount))); cachedInstanceBinder.generateInitializations(thisVariable, body); body.ret(); }
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; }
private static void generateProcessMethod( ClassDefinition classDefinition, RowExpression filter, List<RowExpression> projections, List<MethodDefinition> projectionMethods) { Parameter session = arg("session", ConnectorSession.class); Parameter page = arg("page", Page.class); Parameter start = arg("start", int.class); Parameter end = arg("end", int.class); Parameter pageBuilder = arg("pageBuilder", PageBuilder.class); MethodDefinition method = classDefinition.declareMethod( a(PUBLIC), "process", type(int.class), session, page, start, end, pageBuilder); Scope scope = method.getScope(); BytecodeBlock body = method.getBody(); Variable thisVariable = method.getThis(); // extract blocks List<Integer> allInputChannels = getInputChannels(concat(projections, ImmutableList.of(filter))); ImmutableMap.Builder<Integer, Variable> builder = ImmutableMap.builder(); for (int channel : allInputChannels) { Variable blockVariable = scope.declareVariable( "block_" + channel, body, page.invoke("getBlock", Block.class, constantInt(channel))); builder.put(channel, blockVariable); } Map<Integer, Variable> channelBlocks = builder.build(); Map<RowExpression, List<Variable>> expressionInputBlocks = getExpressionInputBlocks(projections, filter, channelBlocks); // projection body Variable position = scope.declareVariable(int.class, "position"); BytecodeBlock project = new BytecodeBlock().append(pageBuilder.invoke("declarePosition", void.class)); for (int projectionIndex = 0; projectionIndex < projections.size(); projectionIndex++) { RowExpression projection = projections.get(projectionIndex); project.append( invokeProject( thisVariable, session, expressionInputBlocks.get(projection), position, pageBuilder, constantInt(projectionIndex), projectionMethods.get(projectionIndex))); } LabelNode done = new LabelNode("done"); // for loop loop body ForLoop loop = new ForLoop() .initialize(position.set(start)) .condition(lessThan(position, end)) .update(position.set(add(position, constantInt(1)))) .body( new BytecodeBlock() .append( new IfStatement() .condition(pageBuilder.invoke("isFull", boolean.class)) .ifTrue(jump(done))) .append( new IfStatement() .condition( invokeFilter( thisVariable, session, expressionInputBlocks.get(filter), position)) .ifTrue(project))); body.append(loop).visitLabel(done).append(position.ret()); }