InterfaceInjection

Version 7 by john.rose
on Jan 26, 2009 15:15.

compared with
Current by thobe
on Feb 17, 2009 06:18.

Key
This line was removed.
This word was removed. This word was added.
This line was added.

Changes (13)

View page history

h3. Implementation Notes
 
See [HotSpotInternals:InterfaceCalls] for a discussion of how interface call sites work.

Each {{klass}} structure already includes (allocated inline) a 2-dimensional ragged table of its statically defined interfaces. The spine of the table has pairs, {{<oop iklass, offset_t itable>}}. The spine is terminated by a tuple <NULL, 0>.. The itable offsets are relative to the enclosing {{klass}} (the receiver type).
Each itable is an array of the form {{methodOop target\[N\]}}, where {{N}} is the number of methods in the interface.
 
Interface dispatch (for polymorphic call sites) searches the spine of the table, and dips into the matching itable, picking out the target method corresponding to the index (in [0..N-1|0..N-1]) of the abstract method in the interface.

See definition of {{klassItable::setup_itable_offset_table}} around line 1100 of [klassVtable.cpp|http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/share/vm/oops/klassVtable.cpp]. The pair type is {{itableOffsetEntry}}, present in every concrete {{instanceKlass}}.
Since the offset entries on the spine of the table have two words, one word of the terminating entry can have a sentinel value, and the other is free to point to a linked list of extension records. So we repurpose the second word head of a linked list of extension records: <NULL, extension>.
There is one extension record for one interface injection event. They are linked through "next" fields (in an arbitrary order), and the incoming interface {{klass}} is matched against their "key" fields. A matching extension record has N additional words, all methodOops; those N words are exactly like a statically defined embedded itable. The extension records are actually just system arrays (type {{Object\[\]}}) whose lengths are {{2+N}}, with key at element 0, "next" link at element 1, and the implementation methods (if any) at elements 2 through {{2+N-1}}.

In order to pack these dynamic itables, MethodHandles must be lowered to methodOops. For the special case of direct method handles, the original methodOop can be reused. For other (adapted or bound) method handles, a new methodOop must be created to wrap the method handle. This is a dark and dirty secret that nobody but the JVM will know about. (See the auto-generation of invoke methods in methodOop.cpp of [meth.patch|http://hg.openjdk.java.net/mlvm/mlvm/langtools/file/tip/meth.patch].)
The [meth.patch|http://hg.openjdk.java.net/mlvm/mlvm/langtools/file/tip/meth.patch] code already uses the oop-in-a-constant-pool technique for autogenerated {{MethodHandle.invoke}} methods (of which there is an infinite variety).
h3. Design decisions and considerations

* The need to be able to do dynamic invocations in {{<clinit>}} of an interface is less than minimal. It should be safe to reuse the {{_bootstrap_method}} {{oop}} in {{instanceKlass}} for storing the injector for injectable interfaces.
* The injector for an injectable interface is defined by the {{<clinit>}} method on the injectable interface. This is done by invoking {{InterfaceInjector.setInjector(InterfaceInjector)}} from {{<clinit>}}.
* How should an interface be marked as injectable? Options include:
** Adding a flag that marks an interface as injectable. The following flags have no meaning for classes yet:
*** {{0x0040}} - {{JVM_ACC_VOLATILE}} for fields, {{JVM_ACC_BRIDGE}} for methods
*** {{0x0080}} - {{JVM_ACC_TRANSIENT}} for fields, {{JVM_ACC_VARARGS}} for methods
*** {{0x0100}} - {{JVM_ACC_NATIVE}} for methods
** Adding an injectable annotation to the class file, and make sure that this annotation gets loaded early enough.
** Eagerly load all interfaces. The interfaces that define an injector during class initialization are defined as injectable.
*** To reduce the need for eager loading the constant pool could be scanned to determine if the interface references the {{setInjector}}-method.
h3. Other tricky parts
This needs a linked list search and a whole new negative logic side. As with invokeinterface, if the initial searches fail, there needs to be a backoff and upcall to the JVM, to possibly inject the interface. Since negative interface checks are too common to handle this way (via an upcall) some negative filtering needs to be put in. We could do it in a couple of ways:
* Interface klasses which are not injectable (the vast majority) should have bits in their header which identifies them as such, so that instanceof can return false more quickly. A good way to do this may be to add a second {{Klass::secondary_super_cache}} just for injectable interfaces; then the secondary_super_offset for an interface will take one of two distinct values (instead of the single value it takes today), depending on which secondary_super_cache it uses. This simultaneously makes it easy to detect injectables (by {{secondary_super_offset == offsetof(&secondary_super_cache\[1\]))}} and also allocates a word in every {{klass}} to optimize the lookup of injected interfaces.
* (Can delay this for the POC.) Introduce a negative super type cache: {{Klass::secondary_non_super_cache}}. Use it as a first resort, to avoid upcalls on negative type tests of injectables.

h4. negative injection record on each {{klass}}
h4. Java API design.
Requires great precision to say exactly when injection requests happen, how they are resolved, and how the resolutions affect subsequent execution. The basic idea is to have each _exact_, _concrete_ type get injected at most once, and exactly once if an (exact) instance of that type (exactly) gets an invokeinterface, checkcast, or instanceof. (Or reflective or optimized versions thereof\!)

If two types are related by inheritance, it may be best to query supertypes before subtypes. (But never {{Object}}.)
h4. Compile-time optimizations
If interfaces are marked as being injectable or not, then the JIT would not have to emit the code for looking up the interface in the extension list if it's not injectable. To do this
the method that emits the instructions needs to have access to the {{klass}} representing the interface; this needs to be done through the {{ciKlass}} API.
Customizing code like that is usually only done by the JIT's optimizer. (Esp. the server JIT.) The interpreter can usually afford (until proven otherwise\!) to use the most generic code sequences.

There are five places where interface types must be checked by the JIT:

h3. References

* [http://blogs.sun.com/jrose/entry/interface_injection_in_the_vm]
* http://blogs.sun.com/jrose/entry/interface_injection_in_the_vm [http://journal.thobe.org/2008/07/my-jvm-whishlist-pt-1-interface.html]
* http://journal.thobe.org/2008/07/my-jvm-whishlist-pt-1-interface.html

The individuals who post here are part of the extended Sun Microsystems community and they might not be employed or in any way formally affiliated with Sun Microsystems. The opinions expressed here are their own, are not necessarily reviewed in advance by anyone but the individual authors, and neither Sun nor any other party necessarily agrees with them.

Copyright 1994-2009 Sun Microsystems, Inc.
Powered by Atlassian Confluence
Sun Guidelines on Public Discourse Privacy Policy Terms of Use Trademarks Site Map Employment Investor Relations Contact