Native Interface, example of wrapped class
At the moment, not all of this code works; in some cases the "bugs" indicate interfaces that need to be added to other parts of the system.
Also, we are investigating whether the wrapping can be handled right now by interface injection at the bytecode level. Interface injection is how we would like to do it, but the JVM does not support it yet, and it's not guaranteed that it will.
Sample Java class, to be accessed from Fortress
package p.k.g
import java.util.Date;
class C {
static public int i;
static public int f(long x);
public String s;
public C(String x) { ... }
public C(float x) { ... }
public String toString() { ... }
public boolean isNear(float x) { ... }
public Date nearestHoliday(Date x) { ... }
}
Fortress imports
These three imports introduce the names C (trait and factories), C.i (top level variable), and C.f (top level function).
Wrapper for static method C.f
We could choose to code generate static methods together with their containing class, though this is apparently not necessary. It does cut down on the multiplicity of classes to do this. Let's assume that the code below appears in the opaque wrapper for the class C.
public FInt f(FLong x) {
return FInt.make(p.k.g.C.f(x.getLong()));
}
static Closure f_long = new Closure(...) {
Fvalue apply(FValue x) {
return f((FLong) x);
}
};
Wrapper for static field C.i
This is a bit of a challenge: we think tjos ought to look like a top-level variable in a Fortress component, but we need to access it through a getter and a setter.
Wrapping class C: the general idea
The big problem with wrappers for Java objects is that if we create a full wrapper for a Java class, then we are obliged to create full wrappers for every Java class that is referred to in a type signature in that Java class. The JVM is allowed to ask for each of these wrapper types up front, before we know whether we'll even need them! Rather than generating all the ancillary classes (a class for the wrapper, and a class for the closure of each and every method) we'd like to be able to wrap types whose contents we don't care about "opaquely". An opaque wrapper exposes a JVM class to Fortress but doesn't expose any of the methods of the class. A full wrapper exposes all the methods.
Now we run into the problem that we want to be able to pass a wrapped object to a separately-compiled Fortress component, and have that component call methods on the wrapped object, even though our component did not itself look at the contents. This means that we have to guarantee somehow that when we wrap an object, we get the the most wrapped version we might ever need during the program run.
We do this by defining an abstract class that describes the basic wrapping functionality, then subclassing it with one of two identically-named classes that wrap either opaquely or transparently. We set up classpaths and/or class loaders so that we always load a transparent wrapper in preference to an opaque one if both are available. For the moment this requires that we put opaque and transparent wrappers in different places from each other.
Base wrapper for class C
Bytecodes equivalent to this code will be generated by the compiler, to make instances of the Java class p.k.g.C able to exist (but not interoperate) in a Fortress program. The opaque and full wrappers both have the same name, but appear in different entries on the classpath. In particular, the full wrapper, if it exists, shadows the opaque wrapper.
In the short run, everything is an FValue. There might be an intermediary JVM class called something like JavaObjectWrapper? that extends FValue that we extend instead; it depends upon whether we need to know about the methods in some common framework or not.
package fni.p.k.g
abstract class C_base extends FValue {
final p.k.g.C jval;
protected C_base(p.k.g.C x) { jval = x; }
public final p.k.g.C unwrapExact() { return jval; }
public final Object unwrap() { return jval; }
public final FType type() { return C_type.T; }
public static abstract C_base wrapExact(p.k.g.C x);
public static final C_base wrap(Object x) {
return wrapExact((p.k.g.C) x);
}
}
class C_type extends FTraitType {
static C_type T = C_type();
/* details TBD */
}
One tricky question -- we need to figure out where we can be aggressive in type signatures. Ideally we just have unwrap with a return type of p.k.g.C and do away with unwrapExact, which is basically useless. Similarly, there is good reason to suspect that wrap is not required and wrapExact ought to just be called wrap.
Another thing to think about here is whether we should be concrete about field jval in the superclass, or replicate the code in both subclasses. The main reason this would be relevant is if we are reflecting any part of the fortress type hierarchy in the type hierarchy of the byte code we generate: we'd want to be able to have wrappers for subclasses of C to inherit from subclasses of C_base, but such types shouldn't have a second jval field with a different type!
Opaque wrapper for class C
package fni.p.k.g
final class C extends C_base {
private C(p.k.g.C x) { super(x); }
public wrap(p.k.g.C x) { new C(x); }
}
Full wrapper for class C
Bytecodes equivalent to this code will be generated by the compiler, to make instances of the Java class p.k.g.C able to exist (but not interoperate) in a Fortress program. In the short run, everything is an FValue.
package fni.p.k.g
import com.sun.fortress.interpreter.evaluator.values.FBool;
import com.sun.fortress.interpreter.evaluator.values.FFloat;
import com.sun.fortress.interpreter.evaluator.values.FLong;
import com.sun.fortress.interpreter.evaluator.values.FString;
class C extends C_base {
private C(p.k.g.C x) {super(x); }
public wrap(p.k.g.C x) { new C(x); }
public com.sun.fortress.interpreter.glue.prim s(); /* getter */
/* This should look like a top-level function to the Fortress compiler, thus the use of a static method.
Otherwise we need special codegen hooks to generate direct constructor calls. */
static C factory_String(FString js) {
return new C(new p.k.g.C(js.getString()));
}
/* Another top-level Fortress function. */
static C factory_String(FFloat js) {
return new C(new p.k.g.C(js.getFloat()));
}
static Closure1 C_String = new Closure1(...) {
Fvalue apply(FValue x) {
return factory_String((FString) js);
}
};
static Closure1 C_float = new Closure1(...) {
Fvalue apply(FValue x) {
return factory_String((FFloat) js);
}
}
public FString toString() {
return FString.make(unwrapExact().toString());
}
public FBool isNear(FFloat x) {
return FBool.make(unwrapExact().isnear(x.getFloat()));
}
public Date nearestHoliday(fni.java.util.Date_opaque x) {
return new fni.java.util.Date(unwrapExact().nearestHoliday(x.unwrapExact()));
}
}
Note the use of Closure1 to indicate a type that implements a single-argument method (and can thus be invoked directly with a single argument, or perhaps indirectly through some interpreter-friendly interface).
An alternative for methods might be to use static singleton classes:
static final C_String extends Closure1 {
private C_String() { super(); }
static final C_String Closure = new C_String();
Fvalue apply(FValue x) {
return factory_String((FString) js);
}
}
A bit more verbose on the page; not sure how much of the verbosity is actually necessary. It's a bit closer to how we're implementing native closures today. The main reason to do this is to avoid loading and instantiating the C_String closure class unless we actually need the closure for something (a higher-order call or an interpreter-compatible handle on the function). And we avoid having a pile of static fields just tied up holding closure objects.
For that matter, the singleton pattern may not be necessary; these objects are stateless so we're mostly just avoiding repeated re-allocation of closures here. If we needed it, we could probably do this some other way that didn't involve the junk in the class declaration.

