JNI ReleasePrimitiveArrayCritical with mode JNI_COMMIT shouldn't end critical region
Ian Rogers
irogers at google.com
Thu Dec 7 04:55:04 UTC 2017
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.
Thanks,
Ian
On Wed, Dec 6, 2017 at 5:25 PM, David Holmes <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>> 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>
>>
>>
>> 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>
>>
>> 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>
>>
>> "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