Survey of Implementations of Java Reflection

[Home] [Flint] [JavaFlint] [Project page]

Surveyed:

Jalapeno, OpenJIT, JavaInJava (Sun), Standard Sun, Blackdown, Kaffe, Marmot (Microsoft), GNU Classpath, Bullettrain, Rivet

- Jalapeno project
> uses MAGIC (ie. inlined machine code during compilation) See below.

- OpenJIT
> just uses standard JDK libraries.

- JavaInJava (Sun 1998)
> just uses standard JDK reflection libraries - ie. native code

- Sun's JDK
- Blackdown
- Kaffe
> implement the libraries in native code (see my notes for description of their code)

- Marmot (Microsoft)
> From the technical report [FKRST 00] (page 2):
Some other Java features are not presently supported in Marmot, but could in 
principle be supported without undue effort. These include ... reflection.

- GNU Classpath project
> does not (cannot?) handle reflection

- BulletTrain
> Implemented in native code. See below.

- Rivet (MIT)
> another Java in Java thing, see below.

 

Conclusion:

Everyone (except Rivet, which is different) is using native code at some level to implement reflection!

Email correspondence

From:  Bowen Alpern (914) 945-3447 
Subject: Re: Jalapeno: Java Reflection

As I remember it the issues with reflection that required Magic had to
do with reflective access to the fields and methods of an object.  We
can (and do) construct the lists of fields and methods of a class in
Java.  However, to read (or write) a field in that list of a given 
object of the class requires loading (storing) a value at a particular
offset from the reference to the object.  This is not allowed by Java.
We use methods of the special MAGIC class to do this.  (Our compilers
inline special machine code sequences for the methods of this class.
We don't call C except to access operating system services.)

Reflective method invocation is even harder to implement in pure Java.
The Java method that is supposed to do this takes an object representing
a method (obtained as above) and a list of parameters (the primitives of
which are wrapped up as objects).  The reflective invocation method must
unwrap the arguments, get them into the appropriate registers or spill
area of the calling stack frame, find the address of the indicated
method body, branch (and link) to it, intercept any return value, wrap it
if it is primative, and pass the wrapped result back to its caller. 
Java doesn't know anything about registers, stack frames, addresses, or
branching.  All of these operations are performed using methods of the
MAGIC class as above.  Again, no C code is required.

I hope this is helpful.  If you have more questions, do not hesitate
to ask.

   Bowen

From:   Derek L Bruening 
Subject: Re: Rivet project: Java Reflection

We did implement the Java reflection API for Rivet.  Reflection
requires access to the runtime representation of classes.  We
implemented it in Java in tandem with our Java virtual machine, which
we wrote in Java.

The issue is not really "high level code" versus "native code", it is
compile-time versus runtime.  There is nothing in the reflection API
that needs to be written in native code for the system that the Java
virtual machine runs on.  It simply requires information that is only
present at runtime inside the Java virtual machine.

If you want to avoid access to the runtime, and know statically the
identity of a class being reflected upon, you could hardcode the
reflection results at compile time.  However, the reflected class may
change before it is dynamically loaded and the actual reflection call
is made, and then the hardcoded information may be incorrect.  (Some
calls, like java.lang.reflect.Method.invoke(), should remain
correct...the only bad thing I can think of for invoke() is that the
wrong exceptions might be thrown for cases like a nonexistent method).

I'm not sure where the Java virtual machine fits into your
intermediate language picture, but you can certainly implement
reflection in Java if your virtual machine/runtime has the appropriate
hooks.

Hopefully that was useful to you,

- Derek

From:   David Chase 
Subject: Re: Bullettrain and Java Reflection

>Specifically, are methods such as the "invoke()" method of the Method
>class implemented in native code (C or machine code)?

It's a bit complicated.  Much of our runtime system is
written in an unsafe extension to Java; I wouldn't want
to actually call it Java, but it is surely not C.  The basic
idea is that we assemble an array of bit representations of
non-pointer parameters, then (with GC suspended) fill in
the bit representations of the pointer parameters, then
we call an assembly-language stub that copies the
parameters onto the stack, calls the routine, and
(implicitly) unsuspends GC.  I can show you that, just
to demonstrate how tiny that code is:

_declspec(naked) void invoke() { __asm {
         pushl ebp
         movl operands(esp,ebp)
         movl operands(disp(ebp,8),edx)
         movl operands(disp(ebp,12),eax)
         movl operands(disp(eax,tracedArrayLengthOffset),ebx)
L1:
         sub  operands(1,ebx)
         jl   L2
         movl operands([eax+ebx*4+tracedArrayDataOffset],ecx)
         pushl ecx
         jmp L1
... // Inline encoding of unwind information omitted.
L2:
         call edx
         leave
         ret
}}

We'd like to cut out that intermediate copying step,
but if you consider all the other overhead associated
with reflection, it would not help that much, and it
would actually require some relatively delicate compiler
hacking. GC suspension has no direct cost; we simply direct
the compiler (in unsafe code) to not check to see
if a GC is needed by another thread.  Obviously,
the GC-suspending code cannot allocate any memory.
We could also reduce the overhead a little bit by
allocating on demand a large enough array to hold
the temporary parameter stack, but (again) this
would not be a substantial optimization in the context
of all the other work associated with reflection.
(However, it would be a lot easier than the tricky
work required to get rid of the temporary array
altogether).

It's relatively easy to imagine other ways of doing
this; for each Method, we could create a map array
that directs assembly language code to either
copy over an object or extract a field from that
object (recall that the input to a reflection call
is an array of objects and boxed primitives; depending
on the signature of the called method, the primitives
are unboxed); this would probably run a little quicker.
Obviously, this has to run with the GC suspended, but
given the usual case for parameter list sizes, this is
not going to be a problem.

David Chase


Last updated 2000-10-04