Example #1
0
  private static void generateField(
      ClassDefinition definition, Block constructor, StateField stateField) {
    FieldDefinition field =
        definition.declareField(
            a(PRIVATE),
            UPPER_CAMEL.to(LOWER_CAMEL, stateField.getName()) + "Value",
            stateField.getType());

    // Generate getter
    definition
        .declareMethod(a(PUBLIC), stateField.getGetterName(), type(stateField.getType()))
        .getBody()
        .pushThis()
        .getField(field)
        .ret(stateField.getType());

    // Generate setter
    definition
        .declareMethod(
            a(PUBLIC),
            stateField.getSetterName(),
            type(void.class),
            arg("value", stateField.getType()))
        .getBody()
        .pushThis()
        .getVariable("value")
        .putField(field)
        .ret();

    constructor.pushThis();
    pushInitialValue(constructor, stateField);
    constructor.putField(field);
  }
Example #2
0
  private static Map<String, Class<?>> defineClasses(
      List<ClassDefinition> classDefinitions, DynamicClassLoader classLoader) {
    ClassInfoLoader classInfoLoader =
        ClassInfoLoader.createClassInfoLoader(classDefinitions, classLoader);

    if (DUMP_BYTE_CODE_TREE) {
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      DumpByteCodeVisitor dumpByteCode = new DumpByteCodeVisitor(new PrintStream(out));
      for (ClassDefinition classDefinition : classDefinitions) {
        dumpByteCode.visitClass(classDefinition);
      }
      System.out.println(new String(out.toByteArray(), StandardCharsets.UTF_8));
    }

    Map<String, byte[]> byteCodes = new LinkedHashMap<>();
    for (ClassDefinition classDefinition : classDefinitions) {
      ClassWriter cw = new SmartClassWriter(classInfoLoader);
      classDefinition.visit(cw);
      byte[] byteCode = cw.toByteArray();
      if (RUN_ASM_VERIFIER) {
        ClassReader reader = new ClassReader(byteCode);
        CheckClassAdapter.verify(reader, classLoader, true, new PrintWriter(System.out));
      }
      byteCodes.put(classDefinition.getType().getJavaClassName(), byteCode);
    }

    String dumpClassPath = DUMP_CLASS_FILES_TO.get();
    if (dumpClassPath != null) {
      for (Map.Entry<String, byte[]> entry : byteCodes.entrySet()) {
        File file =
            new File(
                dumpClassPath,
                ParameterizedType.typeFromJavaClassName(entry.getKey()).getClassName() + ".class");
        try {
          log.debug("ClassFile: " + file.getAbsolutePath());
          Files.createParentDirs(file);
          Files.write(entry.getValue(), file);
        } catch (IOException e) {
          log.error(e, "Failed to write generated class file to: %s" + file.getAbsolutePath());
        }
      }
    }
    if (DUMP_BYTE_CODE_RAW) {
      for (byte[] byteCode : byteCodes.values()) {
        ClassReader classReader = new ClassReader(byteCode);
        classReader.accept(
            new TraceClassVisitor(new PrintWriter(System.err)), ClassReader.SKIP_FRAMES);
      }
    }
    Map<String, Class<?>> classes = classLoader.defineClasses(byteCodes);
    try {
      for (Class<?> clazz : classes.values()) {
        Reflection.initialize(clazz);
      }
    } catch (VerifyError e) {
      throw new RuntimeException(e);
    }
    return classes;
  }
Example #3
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();
  }
Example #4
0
  private static <T> Class<? extends T> generateGroupedStateClass(
      Class<T> clazz, DynamicClassLoader classLoader) {
    ClassDefinition definition =
        new ClassDefinition(
            a(PUBLIC, FINAL),
            makeClassName("Grouped" + clazz.getSimpleName()),
            type(AbstractGroupedAccumulatorState.class),
            type(clazz),
            type(GroupedAccumulator.class));

    List<StateField> fields = enumerateFields(clazz);

    // Create constructor
    Block constructor =
        definition
            .declareConstructor(a(PUBLIC))
            .getBody()
            .pushThis()
            .invokeConstructor(AbstractGroupedAccumulatorState.class);
    // Create ensureCapacity
    Block ensureCapacity =
        definition
            .declareMethod(a(PUBLIC), "ensureCapacity", type(void.class), arg("size", long.class))
            .getBody();

    // Generate fields, constructor, and ensureCapacity
    List<FieldDefinition> fieldDefinitions = new ArrayList<>();
    for (StateField field : fields) {
      fieldDefinitions.add(generateGroupedField(definition, constructor, ensureCapacity, field));
    }

    constructor.ret();
    ensureCapacity.ret();

    // Generate getEstimatedSize
    Block getEstimatedSize =
        definition
            .declareMethod(a(PUBLIC), "getEstimatedSize", type(long.class))
            .getBody()
            .comment("long size = 0;")
            .push(0L);
    for (FieldDefinition field : fieldDefinitions) {
      getEstimatedSize
          .comment("size += %s.sizeOf();", field.getName())
          .pushThis()
          .getField(field)
          .invokeVirtual(field.getType(), "sizeOf", type(long.class))
          .longAdd();
    }
    getEstimatedSize.comment("return size;");
    getEstimatedSize.retLong();

    return defineClass(definition, clazz, classLoader);
  }
Example #5
0
  private static FieldDefinition generateGroupedField(
      ClassDefinition definition, Block constructor, Block ensureCapacity, StateField stateField) {
    Class<?> bigArrayType = getBigArrayType(stateField.getType());
    FieldDefinition field =
        definition.declareField(
            a(PRIVATE), UPPER_CAMEL.to(LOWER_CAMEL, stateField.getName()) + "Values", bigArrayType);

    // Generate getter
    definition
        .declareMethod(a(PUBLIC), stateField.getGetterName(), type(stateField.getType()))
        .getBody()
        .comment("return field.get(getGroupId());")
        .pushThis()
        .getField(field)
        .pushThis()
        .invokeVirtual(AbstractGroupedAccumulatorState.class, "getGroupId", long.class)
        .invokeVirtual(bigArrayType, "get", stateField.getType(), long.class)
        .ret(stateField.getType());

    // Generate setter
    definition
        .declareMethod(
            a(PUBLIC),
            stateField.getSetterName(),
            type(void.class),
            arg("value", stateField.getType()))
        .getBody()
        .comment("return field.set(getGroupId(), value);")
        .pushThis()
        .getField(field)
        .pushThis()
        .invokeVirtual(AbstractGroupedAccumulatorState.class, "getGroupId", long.class)
        .getVariable("value")
        .invokeVirtual(bigArrayType, "set", void.class, long.class, stateField.getType())
        .ret();

    ensureCapacity
        .pushThis()
        .getField(field)
        .getVariable("size")
        .invokeVirtual(field.getType(), "ensureCapacity", type(void.class), type(long.class));

    // Initialize field in constructor
    constructor.pushThis().newObject(field.getType()).dup();
    pushInitialValue(constructor, stateField);
    constructor.invokeConstructor(field.getType(), type(stateField.getType()));
    constructor.putField(field);

    return field;
  }
Example #6
0
  private static void generateGetSerializedType(
      ClassDefinition definition, List<StateField> fields, CallSiteBinder callSiteBinder) {
    CompilerContext compilerContext = new CompilerContext();
    Block body =
        definition
            .declareMethod(compilerContext, a(PUBLIC), "getSerializedType", type(Type.class))
            .getBody();

    Type type;
    if (fields.size() > 1) {
      type = VARCHAR;
    } else {
      Class<?> stackType = fields.get(0).getType();
      if (stackType == long.class) {
        type = BIGINT;
      } else if (stackType == double.class) {
        type = DOUBLE;
      } else if (stackType == boolean.class) {
        type = BOOLEAN;
      } else if (stackType == byte.class) {
        type = BIGINT;
      } else if (stackType == Slice.class) {
        type = VARCHAR;
      } else {
        throw new IllegalArgumentException("Unsupported type: " + stackType);
      }
    }

    body.comment("return %s", type.getName())
        .append(constantType(new CompilerContext(BOOTSTRAP_METHOD), callSiteBinder, type))
        .retObject();
  }
  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 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());
  }
Example #9
0
  public <T> AccumulatorStateSerializer<T> generateStateSerializer(
      Class<T> clazz, DynamicClassLoader classLoader) {
    AccumulatorStateMetadata metadata = getMetadataAnnotation(clazz);
    if (metadata != null && metadata.stateSerializerClass() != void.class) {
      try {
        return (AccumulatorStateSerializer<T>)
            metadata.stateSerializerClass().getConstructor().newInstance();
      } catch (InstantiationException
          | IllegalAccessException
          | NoSuchMethodException
          | InvocationTargetException e) {
        throw Throwables.propagate(e);
      }
    }

    ClassDefinition definition =
        new ClassDefinition(
            a(PUBLIC, FINAL),
            makeClassName(clazz.getSimpleName() + "Serializer"),
            type(Object.class),
            type(AccumulatorStateSerializer.class));

    CallSiteBinder callSiteBinder = new CallSiteBinder();

    // Generate constructor
    definition.declareDefaultConstructor(a(PUBLIC));

    List<StateField> fields = enumerateFields(clazz);
    generateGetSerializedType(definition, fields, callSiteBinder);
    generateSerialize(definition, clazz, fields);
    generateDeserialize(definition, clazz, fields);

    Class<? extends AccumulatorStateSerializer> serializerClass =
        defineClass(
            definition,
            AccumulatorStateSerializer.class,
            callSiteBinder.getBindings(),
            classLoader);
    try {
      return (AccumulatorStateSerializer<T>) serializerClass.newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
      throw Throwables.propagate(e);
    }
  }
Example #10
0
  private void generateToString(ClassDefinition classDefinition, String string) {
    // Constant strings can't be too large or the bytecode becomes invalid
    if (string.length() > 100) {
      string = string.substring(0, 100) + "...";
    }

    classDefinition
        .declareMethod(
            new CompilerContext(BOOTSTRAP_METHOD), a(PUBLIC), "toString", type(String.class))
        .getBody()
        .push(string)
        .retObject();
  }
  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());
  }
Example #13
0
  private static <T> void generateSerialize(
      ClassDefinition definition, Class<T> clazz, List<StateField> fields) {
    CompilerContext compilerContext = new CompilerContext();
    Block serializerBody =
        definition
            .declareMethod(
                compilerContext,
                a(PUBLIC),
                "serialize",
                type(void.class),
                arg("state", Object.class),
                arg("out", BlockBuilder.class))
            .getBody();

    if (fields.size() == 1) {
      generatePrimitiveSerializer(serializerBody, getGetter(clazz, fields.get(0)));
    } else {
      Variable slice = compilerContext.declareVariable(Slice.class, "slice");
      int size = serializedSizeOf(clazz);
      serializerBody
          .comment("Slice slice = Slices.allocate(%d);", size)
          .push(size)
          .invokeStatic(Slices.class, "allocate", Slice.class, int.class)
          .putVariable(slice);

      for (StateField field : fields) {
        generateSerializeFieldToSlice(
            serializerBody, slice, getGetter(clazz, field), offsetOfField(field, fields));
      }
      serializerBody
          .comment("out.appendSlice(slice);")
          .getVariable("out")
          .getVariable(slice)
          .push(0)
          .push(size)
          .invokeInterface(
              BlockBuilder.class,
              "writeBytes",
              BlockBuilder.class,
              Slice.class,
              int.class,
              int.class)
          .invokeInterface(BlockBuilder.class, "closeEntry", BlockBuilder.class)
          .pop();
    }
    serializerBody.ret();
  }
Example #14
0
  private static <T> Class<? extends T> generateSingleStateClass(
      Class<T> clazz, DynamicClassLoader classLoader) {
    ClassDefinition definition =
        new ClassDefinition(
            a(PUBLIC, FINAL),
            makeClassName("Single" + clazz.getSimpleName()),
            type(Object.class),
            type(clazz));

    // Store class size in static field
    FieldDefinition classSize =
        definition.declareField(a(PRIVATE, STATIC, FINAL), "CLASS_SIZE", long.class);
    definition
        .getClassInitializer()
        .getBody()
        .comment(
            "CLASS_SIZE = ClassLayout.parseClass(%s.class).instanceSize()", definition.getName())
        .push(definition.getType())
        .invokeStatic(ClassLayout.class, "parseClass", ClassLayout.class, Class.class)
        .invokeVirtual(ClassLayout.class, "instanceSize", int.class)
        .intToLong()
        .putStaticField(classSize);

    // Add getter for class size
    definition
        .declareMethod(new CompilerContext(null), a(PUBLIC), "getEstimatedSize", type(long.class))
        .getBody()
        .getStaticField(classSize)
        .retLong();

    // Generate constructor
    Block constructor =
        definition
            .declareConstructor(a(PUBLIC))
            .getBody()
            .pushThis()
            .invokeConstructor(Object.class);

    // Generate fields
    List<StateField> fields = enumerateFields(clazz);
    for (StateField field : fields) {
      generateField(definition, constructor, field);
    }

    constructor.ret();

    return defineClass(definition, clazz, classLoader);
  }
Example #15
0
  private static <T> void generateDeserialize(
      ClassDefinition definition, Class<T> clazz, List<StateField> fields) {
    CompilerContext compilerContext = new CompilerContext();
    Block deserializerBody =
        definition
            .declareMethod(
                compilerContext,
                a(PUBLIC),
                "deserialize",
                type(void.class),
                arg("block", com.facebook.presto.spi.block.Block.class),
                arg("index", int.class),
                arg("state", Object.class))
            .getBody();

    if (fields.size() == 1) {
      generatePrimitiveDeserializer(deserializerBody, getSetter(clazz, fields.get(0)));
    } else {
      Variable slice = compilerContext.declareVariable(Slice.class, "slice");
      deserializerBody
          .comment("Slice slice = block.getSlice(index, 0, block.getLength(index));")
          .getVariable("block")
          .getVariable("index")
          .push(0)
          .getVariable("block")
          .getVariable("index")
          .invokeInterface(
              com.facebook.presto.spi.block.Block.class, "getLength", int.class, int.class)
          .invokeInterface(
              com.facebook.presto.spi.block.Block.class,
              "getSlice",
              Slice.class,
              int.class,
              int.class,
              int.class)
          .putVariable(slice);

      for (StateField field : fields) {
        generateDeserializeFromSlice(
            deserializerBody, slice, getSetter(clazz, field), offsetOfField(field, fields));
      }
    }
    deserializerBody.ret();
  }
  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 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 Class<?> generateArrayConstructor(List<Class<?>> stackTypes, Type elementType) {
    List<String> stackTypeNames =
        stackTypes.stream().map(Class::getSimpleName).collect(toImmutableList());

    ClassDefinition definition =
        new ClassDefinition(
            a(PUBLIC, FINAL),
            CompilerUtils.makeClassName(Joiner.on("").join(stackTypeNames) + "ArrayConstructor"),
            type(Object.class));

    // Generate constructor
    definition.declareDefaultConstructor(a(PRIVATE));

    // Generate arrayConstructor()
    ImmutableList.Builder<Parameter> parameters = ImmutableList.builder();
    for (int i = 0; i < stackTypes.size(); i++) {
      Class<?> stackType = stackTypes.get(i);
      parameters.add(arg("arg" + i, stackType));
    }

    MethodDefinition method =
        definition.declareMethod(
            a(PUBLIC, STATIC), "arrayConstructor", type(Slice.class), parameters.build());
    Scope scope = method.getScope();
    Block body = method.getBody();

    Variable elementTypeVariable = scope.declareVariable(Type.class, "elementTypeVariable");
    CallSiteBinder binder = new CallSiteBinder();

    body.comment("elementTypeVariable = elementType;")
        .append(constantType(binder, elementType))
        .putVariable(elementTypeVariable);

    Variable valuesVariable = scope.declareVariable(List.class, "values");
    body.comment("List<Object> values = new ArrayList();")
        .newObject(ArrayList.class)
        .dup()
        .invokeConstructor(ArrayList.class)
        .putVariable(valuesVariable);

    for (int i = 0; i < stackTypes.size(); i++) {
      body.comment("values.add(arg%d);", i)
          .getVariable(valuesVariable)
          .append(scope.getVariable("arg" + i));
      Class<?> stackType = stackTypes.get(i);
      if (stackType.isPrimitive()) {
        body.append(ByteCodeUtils.boxPrimitiveIfNecessary(scope, stackType));
      }
      body.invokeInterface(List.class, "add", boolean.class, Object.class);
    }

    body.comment("return toStackRepresentation(values, elementType);")
        .getVariable(valuesVariable)
        .getVariable(elementTypeVariable)
        .invokeStatic(ArrayType.class, "toStackRepresentation", Slice.class, List.class, Type.class)
        .retObject();

    return defineClass(
        definition,
        Object.class,
        binder.getBindings(),
        new DynamicClassLoader(ArrayConstructor.class.getClassLoader()));
  }
  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 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());
  }
Example #21
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();
  }
Example #22
0
  private void generateFilterAndProjectCursorMethod(
      ClassDefinition classDefinition, List<RowExpression> projections) {
    MethodDefinition filterAndProjectMethod =
        classDefinition.declareMethod(
            new CompilerContext(BOOTSTRAP_METHOD),
            a(PUBLIC),
            "filterAndProjectRowOriented",
            type(int.class),
            arg("cursor", RecordCursor.class),
            arg("pageBuilder", PageBuilder.class));

    CompilerContext compilerContext = filterAndProjectMethod.getCompilerContext();

    LocalVariableDefinition completedPositionsVariable =
        compilerContext.declareVariable(int.class, "completedPositions");
    filterAndProjectMethod
        .getBody()
        .comment("int completedPositions = 0;")
        .putVariable(completedPositionsVariable, 0);

    //
    // for loop loop body
    //
    LabelNode done = new LabelNode("done");
    ForLoopBuilder forLoop =
        ForLoop.forLoopBuilder(compilerContext)
            .initialize(NOP)
            .condition(
                new Block(compilerContext)
                    .comment("completedPositions < 16384")
                    .getVariable(completedPositionsVariable)
                    .push(16384)
                    .invokeStatic(
                        CompilerOperations.class, "lessThan", boolean.class, int.class, int.class))
            .update(
                new Block(compilerContext)
                    .comment("completedPositions++")
                    .incrementVariable(completedPositionsVariable, (byte) 1));

    Block forLoopBody = new Block(compilerContext);
    forLoop.body(forLoopBody);

    forLoopBody
        .comment("if (pageBuilder.isFull()) break;")
        .append(
            new Block(compilerContext)
                .getVariable("pageBuilder")
                .invokeVirtual(PageBuilder.class, "isFull", boolean.class)
                .ifTrueGoto(done));

    forLoopBody
        .comment("if (!cursor.advanceNextPosition()) break;")
        .append(
            new Block(compilerContext)
                .getVariable("cursor")
                .invokeInterface(RecordCursor.class, "advanceNextPosition", boolean.class)
                .ifFalseGoto(done));

    // if (filter(cursor))
    IfStatementBuilder ifStatement = new IfStatementBuilder(compilerContext);
    ifStatement.condition(
        new Block(compilerContext)
            .pushThis()
            .getVariable("cursor")
            .invokeVirtual(
                classDefinition.getType(),
                "filter",
                type(boolean.class),
                type(RecordCursor.class)));

    Block trueBlock = new Block(compilerContext);
    ifStatement.ifTrue(trueBlock);
    if (projections.isEmpty()) {
      // pageBuilder.declarePosition();
      trueBlock
          .getVariable("pageBuilder")
          .invokeVirtual(PageBuilder.class, "declarePosition", void.class);
    } else {
      // project_43(block..., pageBuilder.getBlockBuilder(42)));
      for (int projectionIndex = 0; projectionIndex < projections.size(); projectionIndex++) {
        trueBlock.pushThis();
        trueBlock.getVariable("cursor");

        // pageBuilder.getBlockBuilder(0)
        trueBlock
            .getVariable("pageBuilder")
            .push(projectionIndex)
            .invokeVirtual(PageBuilder.class, "getBlockBuilder", BlockBuilder.class, int.class);

        // project(block..., blockBuilder)
        trueBlock.invokeVirtual(
            classDefinition.getType(),
            "project_" + projectionIndex,
            type(void.class),
            type(RecordCursor.class),
            type(BlockBuilder.class));
      }
    }
    forLoopBody.append(ifStatement.build());

    filterAndProjectMethod
        .getBody()
        .append(forLoop.build())
        .visitLabel(done)
        .comment("return completedPositions;")
        .getVariable("completedPositions")
        .retInt();
  }
Example #23
0
  private void generateFilterAndProjectRowOriented(
      ClassDefinition classDefinition, RowExpression filter, List<RowExpression> projections) {
    MethodDefinition filterAndProjectMethod =
        classDefinition.declareMethod(
            new CompilerContext(BOOTSTRAP_METHOD),
            a(PUBLIC),
            "filterAndProjectRowOriented",
            type(void.class),
            arg("page", com.facebook.presto.operator.Page.class),
            arg("pageBuilder", PageBuilder.class));

    CompilerContext compilerContext = filterAndProjectMethod.getCompilerContext();

    LocalVariableDefinition positionVariable =
        compilerContext.declareVariable(int.class, "position");

    LocalVariableDefinition rowsVariable = compilerContext.declareVariable(int.class, "rows");
    filterAndProjectMethod
        .getBody()
        .comment("int rows = page.getPositionCount();")
        .getVariable("page")
        .invokeVirtual(com.facebook.presto.operator.Page.class, "getPositionCount", int.class)
        .putVariable(rowsVariable);

    List<Integer> allInputChannels =
        getInputChannels(Iterables.concat(projections, ImmutableList.of(filter)));
    for (int channel : allInputChannels) {
      LocalVariableDefinition blockVariable =
          compilerContext.declareVariable(
              com.facebook.presto.spi.block.Block.class, "block_" + channel);
      filterAndProjectMethod
          .getBody()
          .comment("Block %s = page.getBlock(%s);", blockVariable.getName(), channel)
          .getVariable("page")
          .push(channel)
          .invokeVirtual(
              com.facebook.presto.operator.Page.class,
              "getBlock",
              com.facebook.presto.spi.block.Block.class,
              int.class)
          .putVariable(blockVariable);
    }

    //
    // for loop body
    //

    // for (position = 0; position < rows; position++)
    ForLoopBuilder forLoop =
        forLoopBuilder(compilerContext)
            .comment("for (position = 0; position < rows; position++)")
            .initialize(new Block(compilerContext).putVariable(positionVariable, 0))
            .condition(
                new Block(compilerContext)
                    .getVariable(positionVariable)
                    .getVariable(rowsVariable)
                    .invokeStatic(
                        CompilerOperations.class, "lessThan", boolean.class, int.class, int.class))
            .update(new Block(compilerContext).incrementVariable(positionVariable, (byte) 1));

    Block forLoopBody = new Block(compilerContext);

    IfStatementBuilder ifStatement =
        new IfStatementBuilder(compilerContext).comment("if (filter(position, blocks...)");
    Block condition = new Block(compilerContext);
    condition.pushThis();
    condition.getVariable(positionVariable);
    List<Integer> filterInputChannels = getInputChannels(filter);
    for (int channel : filterInputChannels) {
      condition.getVariable("block_" + channel);
    }
    condition.invokeVirtual(
        classDefinition.getType(),
        "filter",
        type(boolean.class),
        ImmutableList.<ParameterizedType>builder()
            .add(type(int.class))
            .addAll(
                nCopies(
                    filterInputChannels.size(), type(com.facebook.presto.spi.block.Block.class)))
            .build());
    ifStatement.condition(condition);

    Block trueBlock = new Block(compilerContext);
    if (projections.isEmpty()) {
      trueBlock
          .comment("pageBuilder.declarePosition()")
          .getVariable("pageBuilder")
          .invokeVirtual(PageBuilder.class, "declarePosition", void.class);
    } else {
      // pageBuilder.getBlockBuilder(0).append(block.getDouble(0);
      for (int projectionIndex = 0; projectionIndex < projections.size(); projectionIndex++) {
        trueBlock.comment(
            "project_%s(position, blocks..., pageBuilder.getBlockBuilder(%s))",
            projectionIndex, projectionIndex);
        trueBlock.pushThis();
        List<Integer> projectionInputs = getInputChannels(projections.get(projectionIndex));
        trueBlock.getVariable(positionVariable);
        for (int channel : projectionInputs) {
          trueBlock.getVariable("block_" + channel);
        }

        // pageBuilder.getBlockBuilder(0)
        trueBlock
            .getVariable("pageBuilder")
            .push(projectionIndex)
            .invokeVirtual(PageBuilder.class, "getBlockBuilder", BlockBuilder.class, int.class);

        // project(position, block_0, block_1, blockBuilder)
        trueBlock.invokeVirtual(
            classDefinition.getType(),
            "project_" + projectionIndex,
            type(void.class),
            ImmutableList.<ParameterizedType>builder()
                .add(type(int.class))
                .addAll(
                    nCopies(
                        projectionInputs.size(), type(com.facebook.presto.spi.block.Block.class)))
                .add(type(BlockBuilder.class))
                .build());
      }
    }
    ifStatement.ifTrue(trueBlock);

    forLoopBody.append(ifStatement.build());
    filterAndProjectMethod.getBody().append(forLoop.body(forLoopBody).build());

    filterAndProjectMethod.getBody().ret();
  }
  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;
  }
Example #25
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);
  }
Example #26
0
  public <T> AccumulatorStateFactory<T> generateStateFactory(
      Class<T> clazz, DynamicClassLoader classLoader) {
    AccumulatorStateMetadata metadata = getMetadataAnnotation(clazz);
    if (metadata != null && metadata.stateFactoryClass() != void.class) {
      try {
        return (AccumulatorStateFactory<T>)
            metadata.stateFactoryClass().getConstructor().newInstance();
      } catch (InstantiationException
          | IllegalAccessException
          | NoSuchMethodException
          | InvocationTargetException e) {
        throw Throwables.propagate(e);
      }
    }

    Class<? extends T> singleStateClass = generateSingleStateClass(clazz, classLoader);
    Class<? extends T> groupedStateClass = generateGroupedStateClass(clazz, classLoader);

    ClassDefinition definition =
        new ClassDefinition(
            a(PUBLIC, FINAL),
            makeClassName(clazz.getSimpleName() + "Factory"),
            type(Object.class),
            type(AccumulatorStateFactory.class));

    // Generate constructor
    definition.declareDefaultConstructor(a(PUBLIC));

    // Generate single state creation method
    definition
        .declareMethod(a(PUBLIC), "createSingleState", type(Object.class))
        .getBody()
        .newObject(singleStateClass)
        .dup()
        .invokeConstructor(singleStateClass)
        .retObject();

    // Generate grouped state creation method
    definition
        .declareMethod(a(PUBLIC), "createGroupedState", type(Object.class))
        .getBody()
        .newObject(groupedStateClass)
        .dup()
        .invokeConstructor(groupedStateClass)
        .retObject();

    // Generate getters for state class
    definition
        .declareMethod(a(PUBLIC), "getSingleStateClass", type(Class.class, singleStateClass))
        .getBody()
        .push(singleStateClass)
        .retObject();

    definition
        .declareMethod(a(PUBLIC), "getGroupedStateClass", type(Class.class, groupedStateClass))
        .getBody()
        .push(groupedStateClass)
        .retObject();

    Class<? extends AccumulatorStateFactory> factoryClass =
        defineClass(definition, AccumulatorStateFactory.class, classLoader);
    try {
      return (AccumulatorStateFactory<T>) factoryClass.newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
      throw Throwables.propagate(e);
    }
  }