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
|