JEP 276: Dynamic Linking of Language-Defined Object Models
Summary
Provide a facility for linking high-level operations on objects such as "read a property", "write a property", "invoke a callable object", etc., expressed as names in INVOKEDYNAMIC call sites. Provide a default linker for the usual semantics of these operations on plain Java objects, as well as a facility for installing language-specific linkers.
Goals
The primary goal is allowing compilation of high-level object operations on expressions whose type is unknown at compile time to INVOKEDYNAMIC instructions, e.g., obj.color
becomes INVOKEDYNAMIC "dyn:getProp:color"
. The provided infrastructure will at run time dispatch a link request for these call sites to a set of linkers that have knowledge of specific object types, and can produce method handles for appropriate implementation of the operations.
These facilities provide a basis for the implementation of runtimes for programs written in languages that have a concept of object expressions whose types are not known at compile time, and need to express typical object-oriented operations on such objects.
The ability to compose multiple language runtime linkers allows a reasonable amount of interoperability between multiple language runtimes that cohabit in a single JVM process; an INVOKEDYNAMIC call site emitted by one language's compiler should be linkable by another language's linker when an object belonging to one runtime is passed to another runtime.
Non-Goals
We do not wish to provide linking semantics for operations for any single programming language or execution environment for any such language. We will not change the JVMS-described mechanism for bootstrapping a call site; we merely use it.
Motivation
INVOKEDYNAMIC provides a JVM-level foundation for the application-specific linking of methods. It does not provide a way to express higher-level operations on objects, nor methods that implement them. These operations are the usual regimen of operations in object-oriented environments: property access, access of elements of collections, invocation of constructors, invocation of named methods (potentially with multiple dispatch, e.g., link- and run-time equivalents of Java overloaded method resolution). These are all functions that are normally desired in a language on the JVM, yet every language implementation traditionally had to separately reinvent them. While there is an expected variability in the semantics of such operations between languages (they need to have some discriminator, after all, otherwise they'd all be the same language), they all have a common need: linking to Java platform objects (often referred to as "Plain Old Java Objects", i.e., instances of Java classes not belonging to or generated by the language runtime) in a manner that semantically matches their usage in the Java language.
Nashorn is a successful proof of the viability of the approach; when it encounters an expression of the form, e.g., obj.foo
, the Nashorn bytecode compiler can just emit an INVOKEDYNAMIC "dyn:getProp:foo"
, and then defer to the dynamic linker at runtime to provide the implementation for property getters depending on whether the expression evaluates to a JavaScript object, some plain Java object, or something else.
Providing a linking facility from a dynamic language to Java also provides almost everything needed to link the language to itself, too, which Nashorn does: It has a unified linking mechanism that will dispatch to either its own linker or to the "plain Java object" linker as appropriate. Furthermore, if a runtime has a unified linking architecture to both itself and Java objects, the ability to link to objects coming from yet another language runtime in the same JVM effectively comes for free, providing a reasonable degree of cross-language interoperability.
This is a valuable common functionality for implementing any system (e.g., dynamic-language runtimes) that compiles to bytecode with some level of compile-time type uncertainty.
Description
The code in the jdk.internal.dynalink.*
packages currently shipping as an internal dependency of Nashorn in JDK 8 contains a working implementation; we're looking to enhance and expose it as a set of packages named jdk.dynalink.*
, hosted in a new module named jdk.dynalink
.
We'll describe below the current design of it with the understanding that this section will evolve over time as the work progresses.