Commit 92da5900 authored by Kunshan Wang's avatar Kunshan Wang

Remove the requirement of force unwinding native frames in exception

handling and OSR.
parent 7af24a8e
......@@ -233,17 +233,26 @@ Mu function "B", Mu sees one single native frame between the frames for "A" and
functions below, Mu consider the Mu function sitting on top of a native frame.
Stack introspection can skip native frames and introspect other Mu frames below.
OSR can pop native frames. Mu exceptions, when thrown to a native frame, will
remove the native frame and throw the exception to the Mu frame below it, or
have undefined behaviour if there is no such Mu frame below.
NOTE: The requirement to "see through" native frames is partially required
by exact garbage collection, in which case all references in the stack must
be identified.
Mu exceptions are oblivious of non-Mu exception handling (such as C++
exceptions). Destructors for C++ local variables will not be executed. It is
undefined how Mu frames are seen by native programs.
However, throwing Mu exceptions into native frames has implementation-defined
behaviour. Attempting to pop native frames via the API also has
implementation-defined behaviour.
NOTE: In general, it is not safe to force unwind native frames because
native programs may need to clean up their own resources. Existing
approaches, including JNI, models high-level (such as Java-level) exceptions
as a query-able state rather than actual stack unwinding through native
Native exceptions thrown into Mu frames also have implementation-defined
NOTE: Similar to native frames, Mu programs may have even more necessary
clean-up operations, such as GC barriers.
Changes in the Mu IR and the API
......@@ -20,6 +20,12 @@ if an optional feature is implemented, it must behave as specified.
Mu still needs to accept the Mu IR that contains such a type, but may always
refuse to allocate such a type in the memory.
The platform-independent part of the native interface is a required component of
the Mu spec, but the platform-dependent parts are not. There will be things
which are "required but has implementation-defined behaviours". In this case, Mu
must not reject IR programs that contain such constructs, but each
implementation may do different things.
Type System
......@@ -66,6 +72,10 @@ A function signature ``R (P0 P1 ...)`` is required if all of its parameter types
and its return type are implemented and there are at most 256 parameters.
Otherwise optional.
Pointer types ``ptr<T>`` and ``funcptr<sig>`` are required for required and
native-safe types ``T`` and signatures ``sig``. Both are represented as
integers, but their lengths are implementation-defined.
......@@ -82,6 +92,9 @@ implemented.
All NULL constants are required.
Pointer constants are required, but the implementation defines the length of
......@@ -121,6 +134,8 @@ Otherwise optional.
Calling a function whose value is ``NULL`` is undefined behaviour.
Throwing exceptions across native frames has implementation-defined behaviour.
Stack overflow when calling a function results in taking the exceptional control
flow and the ``LANDINGPAD`` instruction receives ``NULL``.
......@@ -144,7 +159,9 @@ its variable part.
All memory addressing instructions ``GETIREF``, ``GETFIELDIREF``,
undefined behaviour when applied to ``NULL`` references.
undefined behaviour when applied to ``NULL`` references. But when applied to
pointers, these instructions calculates the result by calculating the offset
according to the memory layout, which is implementation-defined.
All memory access instructions ``LOAD``, ``STORE``, ``CMPXCHG`` and
``ATOMICRMW`` that access the ``NULL`` references take the exceptional control
......@@ -156,17 +173,25 @@ behaviours.
Accessing a memory location which represents a type different from the type
expected by the instruction gives undefined behaviour.
Accessing the memory via a pointer behaves as if accessing via an ``iref`` if
the byte region represented by the pointer overlaps with the mapped (pinned)
memory region of the Mu memory location. It behaves as if updating the memory
byte-by-byte (not atomically) when all bytes in the byte region pointed by the
pointer are part of some Mu memory locations. Otherwise such memory access has
implementation-defined behaviours.
The following types are required for both non-atomic and atomic ``LOAD`` and
``STORE`` for all implemented ``T`` and ``Sig``: ``int<8>``, ``int<16>``,
``int<32>``, ``int<64>``, ``float``, ``double``, ``ref<T>``, ``iref<T>``,
``weakref<T>``, ``func<Sig>``, ``thread`` and ``stack``.
``weakref<T>``, ``func<Sig>``, ``thread``, ``stack``, ``ptr<T>`` and
The following types are required for non-atomic ``LOAD`` and ``STORE``:
``vector<int<32> 4>``, ``vector<float 4>`` and ``vector<double 2>``.
``int<32>``, ``int<64>``, ``ref``, ``iref``, ``weakref``, ``func``, ``stack``
and ``thread`` are required for ``CMPXCHG`` and the ``XCHG`` operation of the
``ATOMICRMW`` instruction.
``int<32>``, ``int<64>``, ``ref``, ``iref``, ``weakref``, ``func``, ``stack``,
``thread``, ``ptr`` and ``funcptr`` are required for ``CMPXCHG`` and the
``XCHG`` operation of the ``ATOMICRMW`` instruction.
``int<32>`` and ``int<64>`` are required for all ``ATOMICRMW`` operations.
......@@ -181,7 +206,8 @@ One atomic Mu instruction does not necessarily correspond to exactly one
machine instruction. So some atomic read-modify-write operations can be
implemented using ``CMPXCHG`` or load-link store-conditional constructs.
``CCALL`` is optional.
``CCALL`` is required, but the behaviour is implementation-defined. The
available calling conventions are implementation-defined.
``NEWSTACK`` is allowed to result in error, in which case the exceptional
control flow is taken.
......@@ -206,6 +232,11 @@ Required:
+ @uvm.thread_exit
+ @uvm.futex.wait for ``int<32>`` memory locations
+ @uvm.futex.wake for ``int<32>`` memory locations
+ @uvm.native.unpin
+ @uvm.native.expose
+ @uvm.native.unexpose
+ @uvm.native.get_cookie
Required when ``tagref64`` is implemented:
......@@ -1060,6 +1060,8 @@ The ``kill_stack`` message
The ``kill_stack`` message kills the stack.
If the stack contains native frames, the behaviour is implementation-defined.
For JVM users: The JVM does not distinguish stacks and threads. The closest
counterpart is the JVM TI function ``StopThread``, but the Mu ``kill_stack``
message does not unwind the stack. It simply marks the whole stack for
......@@ -1149,6 +1151,8 @@ current instruction in the selected frame. Returns a list of handles.
See ``current_func_ver`` about how the frame is selected.
This message cannot be used on native frames.
For JVM users: The closest JVM TI function is ``GetLocalVariable``. Mu will
not keep all local variables alive. It does not allow setting the value of
local variables, either. However, if an internal reference to a stack memory
......@@ -1172,10 +1176,11 @@ The ``pop_frame`` message
- return value: None
The ``pop_frame`` message pops the top frame of the stack. May pop native
The ``pop_frame`` message pops the top frame of the stack.
Popping native frames has implementation-defined behaviours.
For JVM users: This is the counterpart of the ``PopFrame`` frame.
For JVM users: This is the counterpart of the ``PopFrame`` JVM TI function.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment