Partial compiler triggering ASM

Tronje Krop <[email protected]>
Newsgroups gmane.comp.java.objectweb.asm
Organization TU-Darmstadt
Message-ID <[email protected]>
Hi all,

since a view weeks I think about a compatibility module that allows
to map source code between different tools that provided the same
concepts but different interfaces. Actually I do this because I like
to enable users to use my tool without adapting their code to my
interface from the other tools doing similar stuff.

E.g. I have the following API:

class OtherAPI {
  public static long gettime();
  public static void settime(long time);
  public static interface Timeless {};
}

and want to map this to the following API:

class MyAPI {
  public static long getTime();
  public static void setTime(long time);
  public static @interface Timeless {
    Mode mode default PRIVATE;
  }:
  public static enum Mode {
    PUBLIC, PRIVATE
  };
}

This is a very simple example, but its non-trivial.

===

I started with the org.objectweb.asm.Remapper but after some time it
turned out I needed a more general approach that allowed to not only
map or delete names and types of classes, methods, fields, and anno-
tations, but enables me to substitute marker interfaces against more
complex annotations or specific load, store, and invoke instructions
against arbitrary call patterns.

The positive point is, that the context of the necessary substitu-
tions in general is perfectly defined by types and names of class,
methods with argument list, field names, or annotations.


E.g. in the above example I need to substitute OtherAPI.Timeless
in ClassVisitor.visit(... , String[] ifaces) against an reduced
interface array and call something like:

cv.visitAnnotation("MyAPI/Timeless", true).visitEnd();

The thing that makes it difficult is setting a non-default value
for the mode, which requires something like:

av = cv.visitAnnotation("MyAPI/Timeless", true);
av.visitEnum("mode", "LMyAPI/Timeless$Mode;", "PUBLIC");
av.visitEnd();

I started to extend the Remapper and my first idea was to define
a mapping like:

OtherAPI/Timeless =>
  @MyAPI/Timeless(mode = LMyAPI/Timeless$Mode;.PUBLIC)

Now I need to handle this in the remapper as follows:

int compile = type.indexOf('(');
if (compile != -1) {
  AnnotationVisitor av = mv.visitAnnotation(type.substring(1, compile -
1), true);
  Compiler.SINGELTON.create(av).compile(type.substring(compile +
1)).visitEnd();
} else {
  mv.visitAnnotation(type.substring(1), true).visitEnd();
}

The problem is how to conduct the compiling for the annotation.

===

As a first step I designed a compiler framework as follows,
base on a generic Adapter and Adapter.Factory concept:


public final class Compiler extends Adapter.Factory {
  public static final Compiler.SINGELTON = new Compiler();

  public static interface Visitor<Type> {
    public Type compile(Tokenizer token);
    public Type compile(String token);
  }

  protected static final class Annotation extends
Adapter.Annotation<Compiler>
      implements Visitor<AnnotationVisitor> {
    public Annotation(AnnotationVisitor av, Compiler af) {
      super(av, af);
    }

    public AnnotationVisitor compile(Tokenizer token) {
      // Do the compiler stuff here!
      return this.av;
    }

    public AnnotationVisitor compile(String token) {
      return this.compile(new Tokenizer(token));
    }
  }

  protected static final class Field extends Adapter.Field<Compiler>
      implements Visitor<FieldVisitor> {
    public Field(FieldVisitor fv, Compiler af) {
      super(fv, af);
    }

    public FieldVisitor compile(Tokenizer token) {
      // Do the compiler stuff here!
      return this.fv;
    }

    public FieldVisitor compile(String token) {
      return this.compile(new Tokenizer(token));
    }
  }

  protected static final class Method extends Adapter.Method<Compiler>
      implements Visitor<MethodVisitor> {
    public Method(MethodVisitor mv, Compiler af) {
      super(mv, af);
    }

    public MethodVisitor compile(Tokenizer token) {
      // Do the compiler stuff here!
      return this.mv;
    }

    public MethodVisitor compile(String token) {
      return this.compile(new Tokenizer(token));
    }
  }

  protected static final class Class extends Adapter.Class<Compiler>
      implements Visitor<ClassVisitor> {
    public Class(ClassVisitor cv, Compiler af) {
      super(cv, af);
    }

    public ClassVisitor compile(Tokenizer token) {
      // Do the compiler stuff here!
      return this.cv;
    }

    public ClassVisitor compile(String token) {
      return this.compile(new Tokenizer(token));
    }
  }

  public Annotation create(AnnotationVisitor av) {
    return new Annotation(av, this);
  }

  public Field create(FieldVisitor fv) {
    return new Field(fv, this);
  }

  public Method create(MethodVisitor mv) {
    return new Method(mv, this);
  }

  public Class create(ClassVisitor cv) {
    return new Class(cv, this);
  }
}

This envisioned compiler integrated into this framework now should
allow to compile arbitrary (partial) code artifacts to bytecode in
a way compatible with ASM, i.e. it should issue events on the
visitor interfaces.

By integrating it with the visitor concept the bytecode portions
can be introduced at any place. Wouldn't it be nice to have such
a framework in backup to allow modifications similar to
Javassist?

===

My problem is, I'm far from being a compiler expert and moreover
I didn't even know which language the framework should compile ;-).
As it must compile partial code-blocks, some kind of assembler
output similar to TraceClassAdapter might be good choice, but it
may also be a high-level language as Java itself.

* Does anybody have an Idea where to continue?

* Does someone know a compiler that might be integrated easily?

* Or is there already a ready to use framework?

Any help is appreciated.


Best regards,

Tronje


PS: I know, I can handle my original problem by writing a number of
class, method, field and annotation adapters for each interface I
want to provide compatibility for. But thats less fun ;-)
message-footer.txt (text/plain, 238 B)
-- 
You receive this message as a subscriber of the [email protected] mailing list.
To unsubscribe: mailto:[email protected]
For general help: mailto:[email protected]?subject=help
OW2 mailing lists service home page: http://www.ow2.org/wws
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.