JNI ReleasePrimitiveArrayCritical with mode JNI_COMMIT shouldn't end critical region
Ian Rogers
irogers at google.com
Thu Dec 7 16:58:49 UTC 2017
On Wed, Dec 6, 2017 at 9:00 PM, David Holmes <david.holmes at oracle.com>
wrote:
> On 7/12/2017 2:55 PM, Ian Rogers wrote:
>
>> Thanks, fwiw Jikes RVM agrees that all critical releases end the critical
>> region:
>> https://github.com/JikesRVM/JikesRVM/blob/master/rvm/src/org
>> /jikesrvm/jni/JNIFunctions.java#L5936
>>
>> As does Cacao:
>> http://mips.complang.tuwien.ac.at/hg/cacao/file/2b4c9b6c245d
>> /src/native/jni.cpp#l3208
>>
>> Kaffe (with a non-moving GC) treats the release in the same way as
>> Release<Primitive>ArrayElements:
>> https://github.com/kaffe/kaffe/blob/master/kaffe/kaffevm/
>> jni/jni-arrays.c#L404
>> which is the same as how it is handled on Android.
>>
>> HotSpot has managed to put a foot in both camps, ending the critical
>> always (a la Jikes RVM and Cacao) but honoring commit behavior (and
>> leaking) when in -Xcheck:jni.
>>
>
> So ... I should file a bug for the leak in the checked version and apply
> your suggested patch to always pass mode 0?
>
> Thanks,
> David
>
Sounds good to me. I would have filed the bug rather than starting this
thread if I had a user/bug account :-)
Thanks,
Ian
> Thanks,
>> Ian
>>
>>
>> On Wed, Dec 6, 2017 at 5:25 PM, David Holmes <david.holmes at oracle.com
>> <mailto:david.holmes at oracle.com>> wrote:
>>
>> Hi Ian,
>>
>> On 7/12/2017 4:48 AM, Ian Rogers wrote:
>>
>> Thanks David, I think we may have differing opinions on clarity
>> :-) In the case of -Xcheck:jni and with HotSpot a copy is always
>> made, and so
>>
>>
>> Ah I see. I was considering only the "real" functionality.
>>
>> The fact the checked version of getPrimitiveArrayCritical creates a
>> copy seems to be treated as an internal detail as it does not AFAICS
>> report that a copy was in fact made - the passed in isCopy pointer
>> will be set false by the real getPrimitiveArrayCritical.
>>
>> perhaps the attached patch causes the implementation to match
>> the spec.
>>
>>
>> The whole logic surrounding the management of the copy seems
>> somewhat suspect to me. As you note with your patch
>> check_wrapped_array_release honours the mode, which in the checked
>> case allows, AFAICS, the internally made copy to "leak". So ignoring
>> the passed in mode and always passing 0 to
>> check_wrapped_array_release seems more correct.
>>
>> Given that commit doesn't free a copy, is it intended behavior
>> that in HotSpot it ends a critical region? ie In a VM that
>> allowed copies you could imagine, Get, Commit, Release and as
>> spec-ed the critical region ends at the commit if not a copy,
>> and at the release if it is. Perhaps the simplest thing is to
>> remove the notion of commit here.
>>
>>
>> I honestly do not know what this API is really trying to achieve in
>> that regard. I don't know the intended usage of "commit" mode. Why
>> would you not free the copied buffer? The spec unhelpfully only
>> states:
>>
>> "The other options give the programmer more control over memory
>> management and should be used with extreme care."
>>
>> And if you don't free it what can you do with it? For
>> Get*ArrayElements it clearly states
>>
>> "The result is valid until the corresponding
>> Release<PrimitiveType>ArrayElements() function is called."
>>
>> so once any Release* is done, regardless of mode, it would seem the
>> array (copy or not) is no longer valid and should not be accessed
>> again. So I don't see any expectation that you can call Release*
>> multiple times and so in terms of the critical variants I expect the
>> critical section to end when Release is called - regardless of mode.
>>
>> David
>>
>> Thanks,
>> Ian
>>
>>
>> On Tue, Dec 5, 2017 at 4:37 PM, David Holmes
>> <david.holmes at oracle.com <mailto:david.holmes at oracle.com>
>> <mailto:david.holmes at oracle.com
>>
>> <mailto:david.holmes at oracle.com>>> wrote:
>>
>> Hi Ian,
>>
>> On 6/12/2017 9:15 AM, Ian Rogers wrote:
>>
>> From:
>> https://docs.oracle.com/javase/8/docs/technotes/guides/jni/
>> spec/functions.html#GetPrimitiveArrayCritical_ReleasePrimiti
>> veArrayCritical
>> <https://docs.oracle.com/javase/8/docs/technotes/guides/jni/
>> spec/functions.html#GetPrimitiveArrayCritical_ReleasePrimiti
>> veArrayCritical>
>> <https://docs.oracle.com/javas
>> e/8/docs/technotes/guides/jni/spec/functions.html#GetPrimiti
>> veArrayCritical_ReleasePrimitiveArrayCritical
>> <https://docs.oracle.com/javase/8/docs/technotes/guides/jni/
>> spec/functions.html#GetPrimitiveArrayCritical_ReleasePrimiti
>> veArrayCritical>>
>>
>>
>> You need to see the updated spec:
>>
>> https://docs.oracle.com/javase/9/docs/specs/jni/functions.
>> html#getprimitivearraycritical-releaseprimitivearraycritical
>> <https://docs.oracle.com/javase/9/docs/specs/jni/functions.
>> html#getprimitivearraycritical-releaseprimitivearraycritical>
>> <https://docs.oracle.com/javas
>> e/9/docs/specs/jni/functions.html#getprimitivearraycritical
>> -releaseprimitivearraycritical
>> <https://docs.oracle.com/javase/9/docs/specs/jni/functions.
>> html#getprimitivearraycritical-releaseprimitivearraycritical>>
>>
>> That spec makes it clear:
>>
>> "mode: the release mode (see Primitive Array Release Modes):
>> 0,
>> JNI_COMMIT or JNI_ABORT. Ignored if carray was a not copy."
>>
>> In hotspot getCriticalArrayPrimitive never returns a copy
>> so the
>> mode is always ignored, as per the existing comment.
>>
>> David
>> -----
>>
>>
>> "The semantics of these two functions are very similar
>> to the
>> existing
>> Get/Release<primitivetype>ArrayElements functions. "
>>
>> https://docs.oracle.com/javase/8/docs/technotes/guides/jni/
>> spec/functions.html#Release_PrimitiveType_ArrayElements_routines
>> <https://docs.oracle.com/javase/8/docs/technotes/guides/jni/
>> spec/functions.html#Release_PrimitiveType_ArrayElements_routines>
>> <https://docs.oracle.com/javas
>> e/8/docs/technotes/guides/jni/spec/functions.html#Release_
>> PrimitiveType_ArrayElements_routines
>> <https://docs.oracle.com/javase/8/docs/technotes/guides/jni/
>> spec/functions.html#Release_PrimitiveType_ArrayElements_routines>>
>>
>> "JNI_COMMIT copy back the content but do not free the
>> elems buffer"
>>
>> Consider the pattern of:
>> GetPrimitiveArrayCritical(...)
>> ReleasePrimitiveArrayCritical(..., JNI_COMMIT)
>> ReleasePrimitiveArrayCritical(..., 0)
>>
>> where the first release is to just achieve a copy back.
>> For example,
>> jniCheck.cpp will copy back but not free a copy in the
>> case of
>> JNI_COMMIT
>> for a critical. The implementation of
>> ReleasePrimitiveArrayCritical ignores
>> all arguments and so it ends the critical region even
>> in the
>> event of a
>> commit.
>>
>> The attached patch makes ReleasePrimitiveArrayCritical
>> consider
>> the mode
>> argument when releasing the GCLocker.
>>
>> Thanks,
>> Ian
>>
>>
>>
>>
More information about the hotspot-dev
mailing list