[armedbear-devel] Why does jcall use reflection?

Alessio Stalla alessiostalla at gmail.com
Sat Jan 9 09:56:08 UTC 2010


On Sat, Jan 9, 2010 at 2:17 AM, Axel Rauschmayer <axel at rauschma.de> wrote:
>> It is dubious whether enhancing the compiler to eliminate reflection
>> for some jcall invocations would be worth the effort. Since Java
>> objects are boxed in ABCL, the compiler would need to generate code to
>> unbox the arguments and box the return value, and place appropriate
>> exception handlers. This would likely increase the size and complexity
>> of the generated code quite a lot. Also, I believe that to optimize a
>> significant number of jcall invocations we need type inference, and
>> that's not an easy task.
>> Of course, the implementation of jcall has to do the very same
>> boxing/unboxing, besides the reflective call itself; it is inevitably
>> less efficient. But I think that, unless your code is made mostly of
>> calls to Java methods, the difference is tolerable.
>
> Naively (=not knowing how it all fits into the bigger ABCL picture), I would expect Java objects not to be boxed and the compiler to be helped by some kind of foreign function declaration. That is, all types are declared statically, dynamic single dispatch should be handled by the JVM. This would mean an initial point of pain (writing the declarations), but elegant usage afterwards. A small script should be able to generate this kind of declarations.
>
> (defjvar foo java.util.StringBuilder)
> (defjfun sb-to-string java.util.StringBuilder)
>
> (setf foo (new java.util.StringBuilder))
> (sb-to-string foo)
>
> Am I making sense or is this off the mark?

The main reason for boxing Java objects is probably to ensure that
ABCL can deal with all objects through a common interface - the base
class LispObject. Had not this been the case, the methods in most
classes in the Java part of ABCL would have had to accept arbitrary
Objects and do type checks at runtime:

LispObject type;
if(parameter instanceof LispObject) {
  type = ((LispObject) parameter).typeOf();
} else {
  type = Symbol.JAVA_OBJECT;
}

which would have been ugly and inefficient.

That said, it would be possible for the compiler to avoid some of the
boxing/unboxing in certain cases, perhaps with the help of
declarations.

> The good thing is that any kind of Java calls are always going to be encapsulated inside a lisp interface, so that migrating to something different later is never an issue. I have a feeling that supporting Java's collection APIs (including iterators and Iterable) and Java's streams would be helpful when connecting from ABCL, but I'll have to work some more on my ABCL API for Sesame [1], to be sure.

wrt. streams, the machinery is pretty much already there - ABCL stream
classes are wrappers around Java streams and reader/writers. There's
currently no way to access that from Lisp except manually
instantianting ABCL's stream classes with the Java FFI.
One possibility is to add the capability to automatically translate
streams returned from Java, like it already happens with strings and
numbers; I have code to do that somewhere, an abandoned experiment. My
only concern is efficiency: streams are going to be translated (boxed)
even if not used as Lisp streams, and unboxed when passed again to
Java, and this operation is heavier than usual because ABCL's streams
are not mere boxes, they have some initialization logic.
An alternative would be to provide operators to do the conversion
manually, e.g. (as-lisp-stream java-stream). Then the burden would be
on the programmer, but the translation would only be performed when
needed.

Bye,
Alessio




More information about the armedbear-devel mailing list