[jmm-dev] Optimizing external actions in the JMM

Sanjoy Das sanjoy at playingwithpointers.com
Tue Jul 12 07:35:47 UTC 2016

Hi Nitsan,

Thank you for replying!

Nitsan Wakart wrote:
 > Given:
 > "...
 > where f is some external action that the compiler understands.  If the
 > compiler knows `f` always returns 42 and has no other effect, can it
 > optimize ThreadA to
 > ...
 > thereby introducing a OOTA-like value of 42 into the system?"
 > Why is this OOTA?

It isn't OOTA intuitively, and I'm trying to justify its non-OOTA ness
by the JMM rules.

 > The thing is you define:
 > "external action that... always returns 42 and has no other effect"

I didn't mean to say that it "always returns 42 and has no other
effect" by the spec, but that the compiler knows it "always returns 42
and has no other effect" by some external knowledge it has about `f`
(and perhaps the environment).

For instance, say f(x) was "return Unix_open("/home/foo/" + x)", and
the JIT knew that since the process is running under user "bar", the
call to open would always return -1 and not have any other external
effect.  Would it be okay then to introduce the OOTA like value -1 by
replacing the call to Unix_fopen with -1?  I'd like to say yes, but I
can't justify -1 for the same reason as we couldn't justify 42 earlier
-- there isn't enough information in the trace to infer f(0) is -1 --
the trace will only state that f(-1) is -1.

 > Which according to:
 > "An external action is an action that may be observable outside of an execution,
 > and has a result based on an environment external to the execution."
 > (from https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.2)
 > is not an external action.
 > To make a function an "external action" we need to satisfy:
 > 1. "may be observable outside of an execution" AND
 > 2. "has a result based on an environment external to the execution"
 > The concerns you raise around off-heap memory handling boil down to:
 > - Unsafe.put(long address,*)/Unsafe.put(null, long address,*): don't fullfil 2
 > - Unsafe.get*(long address)/Unsafe.get*(null, long address): don't fullfil 1

Under this interpretation the Unsafe.get*() intrinsics have a corner
case -- if they're being called on a mmapped file (or uninitialized
memory, even) then the value returned by them is not specified by the
memory model (to be precise: whether a certain value returned by the
call is correct is not decidable in the JMM).  This hints that they
need to be modeled as external actions; moreover, I think that (1)
really means "*may* be observable" and not "*has to be* observable".

-- Sanjoy

 > The volatile accesses to offheap are not covered by JMM AFAIK, but are relied
 > upon by many to mean the same as their heap counter parts.

More information about the jmm-dev mailing list