Description
Context: Issue #524
Context: Issue #534
Allowing JVM-hosted code to invoke managed code requires the use of Java Callable Wrappers for all Java.Lang.Object
subclasses. The Java Callable Wrapper contains Java native
method declarations for all methods implemented in managed code, e.g. by overriding a virtual
method, implementing an interface method, or placing [Java.Interop.ExportAttribute]
on a method.
Java Callable Wrappers are currently implemented by using Java source code as an intermediary: JavaCallableWrapperGenerator
generates Java source code, which is later compiled by javac
to produce Java byte code for later inclusion into an Android application.
We have historically pondered updating Xamarin.Android.Tools.Bytecode
to be a read/write API instead of a read-only API, largely for performance reasons: we could avoid the overhead of writing .java
files and invoking javac
if we just directly emitted a .jar
file containing relevant .class
files.
We now have another reason to ponder this idea: Full Kotlin support. Kotlin "name mangles" method names in various contexts, emitting Java byte code method names which are not valid Java identifiers:
// Kotlin
package example;
public open abstract class AbstractUnsigned {
public abstract fun m(value : UInt)
}
// javap example.AbstractUnsigned
public abstract class example.AbstractUnsigned {
public abstract void m-WZ4Q5Ns(int);
public example.AbstractUnsigned();
}
Note the example.AbstractUnsigned.m-WZ4Q5Ns()
method: it cannot be overridden from Java:
// error: JavaSubclassAbstractUnsigned is not abstract and does not override abstract method m-WZ4Q5Ns(int) in AbstractUnsigned
class JavaSubclassAbstractUnsigned extends example.AbstractUnsigned {
}
class JavaSubclassAbstractUnsigned extends example.AbstractUnsigned {
public void m-WZ4Q5Ns(int value) {
// error: '(' expected
// public void m-WZ4Q5Ns(int value) {
// ^
// error: invalid method declaration; return type required
// public void m-WZ4Q5Ns(int value) {
// ^
}
}
So long as we use Java source code as an intermediary, we cannot override or implement Kotlin name-mangled methods.
We could use Kotlin as an intermediate language ("Kotlin Callable Wrappers," anyone?)...
...but why add Kotlin as an intermediate language when we could instead just write Java byte code directly. This would allow the Java Callable Wrapper process to be faster -- no javac
invocation would be required -- and means that we avoid any "pesky" issues caused by Kotlin name mangling.