Folks,
Once we decided that we do not want to limit Harmony with only one VM/JIT/GC
instance I think it's time to start discussion how all these components will
work together effectively.
So the proposal is to discuss helper inlining interface.

Every component we have (VM, GC : )  can have helpers that must be called
from managed code.
While generating native code for Java method JIT inserts calls to these
helpers: "get_vtable", "allocate_new_object", "monitor_enter" e.t.c.

Some of these helpers have fast version: a "fast path", the algorithm that
worth to be inlined into generated method body to improve overall system
performance.

Here is an example of such helpers:
1)  new object allocation
2)  write barriers
3)  monitor enters/exits
4)  fast access to TLS data
...

The problem of inlining of a "fast-path" algorithm is that JIT must know the
details of the algorithm it inlines.
There are different ways to solve this problem and I will try to describe
some of them. Add more if you know better solution.
Which one to choose and details of the implementation is the subject of
discussion.


Solution 1.
Use "magic" methods (like MMTk does) and write fast path version of a helper
in Java.

"Magic" method is a method that is never compiled by JIT but replaced with a
native code.
In MMTk  (see link 1) there is a set of 'unboxed' types that allow to write
pointer arithmetic, pointer comparison, casts, and memory reads and writes
including atomic operations in Java language.
We can use MMTk-like 'unboxed' types with some new operations added  to
allow to write fast paths for helpers in Java. So JIT can access the
bytecode of the fast-path helper version and inline it as a usual Java
method.
What do we need to add to MMTk's like unboxed types (please correct if I've
missed something):
a)  Fast access to TLS.
Used to access thread local data in runtime: GC allocation, per-thread
profiling, monitors inlining e.t.c. :
b)  Develop an approach to call native methods using different calling
conventions.
Needed to call original and slow helper version if fast path version fails.


Solution 2.
Standardize algorithms by using custom interfaces for each of them.
GC, VM, JIT components interact with each other by using some intercomponent
interfaces, e.g. OPEN ones: (see link 2)
The proposal is to standardize interfaces for every algorithm or family of
algorithms we use in fast path helper versions, so if JIT supports one of
them it can ask VM or GC to provide a struct with functions pointers and
constants which describe the algorithm.
E.g. for a "monitor exit" fast path algorithm that checks some bit in header
in atomic operation it's enough to provide an offset of this bit to JIT.
Another example is a fast path of "bump pointer" allocation algorithm. Once
JIT is able generate a code to access to thread local data and knows the
offsets of 'current' and 'limit' pointers it can generate a code that
increments 'current' pointer or call to an original slow helper if check
with 'limit' failed.

Solution 3.
Develop and standardize a lightweight low-level language and parse it in JIT
to generate a helper's fast path.
In this case when JIT decides to inline a call of a helper it asks VM or GC
for a textual representation of the helper's fast path and parses it into
its internal representation. This solution looks exactly like Solution 1,
where Java bytecode serves as lightweight intercomponent language. So to
accept this solution we must get an answer why bytecode + "magic" methods
are not enough.


In my opinion all of these solutions will work, but the first one (Solution
1) is much more flexible.

Does anyone have other ideas how to design 'helper inlining' to make it easy
and reusable?
Is there any limitation with 'magic' approach that can prevent us to use
this way?


Links:
1)  http://cs.anu.edu.au/~Steve.Blackburn/pubs/papers/mmtk-icse-2004.pdf
2)  http://issues.apache.org/jira/browse/HARMONY-459.

--
Mikhail Fursov

Reply via email to