Пример #1
0
  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();
  }
Пример #2
0
  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;
  }
Пример #3
0
 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);
 }
Пример #4
0
  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()));
  }
Пример #5
0
  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());
  }
Пример #6
0
  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();
  }
Пример #7
0
  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);
 }