Implementing "complex" native methods that are JVM intrinsics #902
Replies: 1 comment 1 reply
-
I don't know if I feel comfortable having static vs dynamic variants for operations like this. If at all possible I prefer to boil it down to a common case. For example, the semantics for array creation are somewhat different comparing primitive and reference — different enough that there are separate bytecodes for the two different cases. What if we try to reflect this difference instead? We could convert Then we can probably implement if (type == byte[].class) {
return new byte[len];
// ...
} else {
// it's a reference array
return intr_emit_new_ref_array(raw_type_id_of(clazz), dimensions_of(clazz) + 1);
}
I'll have to ponder this some more. Right now BBB implementations do a lot of lifting beyond just emitting or transforming nodes, and arguably this makes them brittle. A parallel abstraction of run time strategies might work, but I need to consider more how this would work in practice. |
Beta Was this translation helpful? Give feedback.
-
I've been thinking about this problem in the context of starting to work on #674. In particular, implementing
Array.newInstance(clazz, int)
, but I think it is a general question about how we should tackle implementing the kind of native methods that OpenJDK labels as a@HotSpotIntrinsicCandidate
. I've been dancing around a couple of alternate approaches, and none of them seems like an obvious winner. At some level, what this "native" method needs to do is fairly simple: Do some basic validation of its parameters, allocate the right amount of properly aligned memory, initialize some of it as an array object header, return the reference to it. Done.The thing that has been causing me to churn is that the "knowledge" of how to do this is spread through collaborating BasicBlockBuilders coming from multiple plugins. At a really broad level, I think we want to keep this knowledge in the compiler and in different plugins (so I tentatively discarded one possible approach based on mostly writing an intrinsic like this in Java as a runtime method with very low-level intrinsics that would piecemeal initialize individual header fields). And maybe we want to keep the knowledge mostly in the BasicBlockBuilders (BBB). The challenge is that the BBB is biased towards building IR based on compile time constructs (TypeType, ObjectType, etc).
I can imagine expanding the BBB API to support operations that operated on compile-time constructs that represented the runtime versions of these. I think this might be a plausible path, but I have some concerns...it could lead to an explosion of the BBB APIs and in some cases, the collaborating BBBs operate in different phases, so we also might need to either add new Nodes or "generalize" existing nodes in ways that are ultimately unproductive.
Concretely, we currently have
Value newArray(ArrayObjectType arrayType, Value size)
. There are BBBs that intercept this method on the ADD, ANALYZE, and LOWER phase (so we need a Node to propagate it between the phases). To supportArray.newInstance
, we would need to allowarrayType
to also be aValue
that contained ajava.lang.Class
instance. We probably would want to add a new node for this variant, since the kinds of things we can figure out at compile time vs. runtime for aArrayObjectType
vs. "Value
containing aClass
instance" are very different.Alternatively, I could imagine expanding the BBB API to add a set of more runtime-focused APIs. For example, allocate zeroed-storage of a given size and alignment, initialize an object header of various flavors, etc. This could be done by either really expanding the BBB APIs, or by creating a parallel delegating structure that allowed plugins to contribute bits and pieces of logic to this. (A
RuntimePrimitivesBuilder
)? The parallel delegating structure's methods would all take a BBB as a parameter and would use that BBB to actually build the graph. Some of the current functionality we put in BBBs (for example the object header initialization, storage allocation, memory copying) would end up being implemented by first converting their compile-time constructs to the correspondingValues
, then invoking the RuntimesPrimitiveBuilder to actually generate the graph that does the work.Any thoughts on how to proceed or alternatives I am missing?
Beta Was this translation helpful? Give feedback.
All reactions