private void generateFilterMethod( CallSiteBinder callSiteBinder, ClassDefinition classDefinition, RowExpression filter, boolean sourceIsCursor) { MethodDefinition filterMethod; if (sourceIsCursor) { filterMethod = classDefinition.declareMethod( new CompilerContext(BOOTSTRAP_METHOD), a(PUBLIC), "filter", type(boolean.class), arg("cursor", RecordCursor.class)); } else { filterMethod = classDefinition.declareMethod( new CompilerContext(BOOTSTRAP_METHOD), a(PUBLIC), "filter", type(boolean.class), ImmutableList.<NamedParameterDefinition>builder() .add(arg("position", int.class)) .addAll(toBlockParameters(getInputChannels(filter))) .build()); } filterMethod.comment("Filter: %s", filter.toString()); filterMethod.getCompilerContext().declareVariable(type(boolean.class), "wasNull"); Block getSessionByteCode = new Block(filterMethod.getCompilerContext()) .pushThis() .getField(classDefinition.getType(), "session", type(ConnectorSession.class)); ByteCodeNode body = compileExpression( callSiteBinder, filter, sourceIsCursor, filterMethod.getCompilerContext(), getSessionByteCode); LabelNode end = new LabelNode("end"); filterMethod .getBody() .comment("boolean wasNull = false;") .putVariable("wasNull", false) .append(body) .getVariable("wasNull") .ifFalseGoto(end) .pop(boolean.class) .push(false) .visitLabel(end) .retBoolean(); }
private MethodDefinition generateProjectMethod( ClassDefinition classDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, String methodName, RowExpression projection) { Parameter session = arg("session", ConnectorSession.class); List<Parameter> inputs = toBlockParameters(getInputChannels(projection)); Parameter position = arg("position", int.class); Parameter output = arg("output", BlockBuilder.class); MethodDefinition method = classDefinition.declareMethod( a(PUBLIC), methodName, type(void.class), ImmutableList.<Parameter>builder() .add(session) .addAll(inputs) .add(position) .add(output) .build()); method.comment("Projection: %s", projection.toString()); Scope scope = method.getScope(); BytecodeBlock body = method.getBody(); Variable wasNullVariable = scope.declareVariable("wasNull", body, constantFalse()); BytecodeExpressionVisitor visitor = new BytecodeExpressionVisitor( callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(callSiteBinder, position, wasNullVariable), metadata.getFunctionRegistry()); body.getVariable(output) .comment("evaluate projection: " + projection.toString()) .append(projection.accept(visitor, scope)) .append(generateWrite(callSiteBinder, scope, wasNullVariable, projection.getType())) .ret(); return method; }
private ByteCodeNode compileExpression( CallSiteBinder callSiteBinder, RowExpression expression, boolean sourceIsCursor, CompilerContext context, Block getSessionByteCode) { ByteCodeExpressionVisitor visitor = new ByteCodeExpressionVisitor( callSiteBinder, getSessionByteCode, metadata.getFunctionRegistry(), sourceIsCursor); return expression.accept(visitor, context); }
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 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 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 TypedOperatorClass compileScanFilterAndProjectOperator( RowExpression filter, List<RowExpression> projections, DynamicClassLoader classLoader) { CallSiteBinder callSiteBinder = new CallSiteBinder(); ClassDefinition classDefinition = new ClassDefinition( new CompilerContext(BOOTSTRAP_METHOD), a(PUBLIC, FINAL), typeFromPathName("ScanFilterAndProjectOperator_" + CLASS_ID.incrementAndGet()), type(AbstractScanFilterAndProjectOperator.class)); // declare fields FieldDefinition sessionField = classDefinition.declareField(a(PRIVATE, FINAL), "session", ConnectorSession.class); classDefinition.declareField(a(PRIVATE, VOLATILE, STATIC), "callSites", Map.class); // constructor classDefinition .declareConstructor( new CompilerContext(BOOTSTRAP_METHOD), a(PUBLIC), arg("operatorContext", OperatorContext.class), arg("sourceId", PlanNodeId.class), arg("dataStreamProvider", DataStreamProvider.class), arg("columns", type(Iterable.class, ColumnHandle.class)), arg("types", type(Iterable.class, Type.class))) .getBody() .comment("super(operatorContext, sourceId, dataStreamProvider, columns, types);") .pushThis() .getVariable("operatorContext") .getVariable("sourceId") .getVariable("dataStreamProvider") .getVariable("columns") .getVariable("types") .invokeConstructor( AbstractScanFilterAndProjectOperator.class, OperatorContext.class, PlanNodeId.class, DataStreamProvider.class, Iterable.class, Iterable.class) .comment("this.session = operatorContext.getSession();") .pushThis() .getVariable("operatorContext") .invokeVirtual(OperatorContext.class, "getSession", ConnectorSession.class) .putField(sessionField) .ret(); generateFilterAndProjectRowOriented(classDefinition, filter, projections); generateFilterAndProjectCursorMethod(classDefinition, projections); // // filter method // generateFilterMethod(callSiteBinder, classDefinition, filter, true); generateFilterMethod(callSiteBinder, classDefinition, filter, false); // // project methods // List<Type> types = new ArrayList<>(); int projectionIndex = 0; for (RowExpression projection : projections) { generateProjectMethod( callSiteBinder, classDefinition, "project_" + projectionIndex, projection, true); generateProjectMethod( callSiteBinder, classDefinition, "project_" + projectionIndex, projection, false); types.add(projection.getType()); projectionIndex++; } // // toString method // generateToString( classDefinition, toStringHelper(classDefinition.getType().getJavaClassName()) .add("filter", filter) .add("projections", projections) .toString()); Class<? extends SourceOperator> filterAndProjectClass = defineClass(classDefinition, SourceOperator.class, classLoader); setCallSitesField(filterAndProjectClass, callSiteBinder.getBindings()); return new TypedOperatorClass(filterAndProjectClass, types); }
public ByteCodeNode generate(RowExpression expression) { return expression.accept(byteCodeGenerator, context); }