Ejemplo n.º 1
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);
    }
  }
  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()));
  }