Pedantic JNI question

  • Follow


I'm just trying to do the job properly and the correct answer is not obvious
to me in the documentation.

a-If I call GetByteArrayRegion I should later call ReleaseByteArrayRegion.
b-If an exception is thrown then the only functions that it is safe to call
are ExceptionCheck(I presume, but the docs don't say so), ExceptionClear,
ExceptionDescribe and ExceptionOccurred.

So does that mean in the event of an exception we can return safely without
bothering with the ReleaseByteArrayRegion calls (and the system will tidy
up).

-- 
Bill Medland
0
Reply billmedland (95) 10/19/2006 11:20:39 PM

On Thu, 19 Oct 2006 23:20:39 +0000, Bill Medland wrote:

> I'm just trying to do the job properly and the correct answer is not obvious
> to me in the documentation.
> 
> a-If I call GetByteArrayRegion I should later call ReleaseByteArrayRegion.
> b-If an exception is thrown then the only functions that it is safe to call
> are ExceptionCheck(I presume, but the docs don't say so), ExceptionClear,
> ExceptionDescribe and ExceptionOccurred.
> 
> So does that mean in the event of an exception we can return safely without
> bothering with the ReleaseByteArrayRegion calls (and the system will tidy
> up).

There is no ReleaseByteArrayRegion call in the JNI spec.  Did you mean
ReleaseByteArrayElements?

Anyway,  according to the way I read the spec, the statement that "When
there is a pending exception, the only JNI functions that are safe to call
are..." means just what it says.  In general the JVM cleans up dangling
references upon return from a native function.  It could be argued that
the native-type-array pointers returned by
Get<type>ArrayElements, GetStringChars and GetStringUTFChars are not local
references, so I always clean them up if possible;  but I'm not sure
exactly what different JVMs do.

If you want to do some cleanup that requires calls into the JVM,  you have
an alternative:  store the "jthrowable" returned by ExceptionOccurred
somewhere;  call ExceptionClear;  make your calls;  call Throw with the
"jthrowable" you stored before you return from the native function.  

-- 
PGP key posted on website ... http://www.lmert.com/people/davidl/

0
Reply dlamber45 (10) 10/20/2006 1:51:15 AM


David Lee Lambert wrote:

> On Thu, 19 Oct 2006 23:20:39 +0000, Bill Medland wrote:
> 
>> I'm just trying to do the job properly and the correct answer is not
>> obvious to me in the documentation.
>> 
>> a-If I call GetByteArrayRegion I should later call
>> ReleaseByteArrayRegion. b-If an exception is thrown then the only
>> functions that it is safe to call are ExceptionCheck(I presume, but the
>> docs don't say so), ExceptionClear, ExceptionDescribe and
>> ExceptionOccurred.
>> 
>> So does that mean in the event of an exception we can return safely
>> without bothering with the ReleaseByteArrayRegion calls (and the system
>> will tidy up).
> 
> There is no ReleaseByteArrayRegion call in the JNI spec.  Did you mean
> ReleaseByteArrayElements?

Woops, Yes - I meant Elements, not Region, of course.

> 
> Anyway,  according to the way I read the spec, the statement that "When
> there is a pending exception, the only JNI functions that are safe to call
> are..." means just what it says.  In general the JVM cleans up dangling
> references upon return from a native function.  It could be argued that
> the native-type-array pointers returned by
> Get<type>ArrayElements, GetStringChars and GetStringUTFChars are not local
> references, so I always clean them up if possible;  but I'm not sure
> exactly what different JVMs do.
> 
> If you want to do some cleanup that requires calls into the JVM,  you have
> an alternative:  store the "jthrowable" returned by ExceptionOccurred
> somewhere;  call ExceptionClear;  make your calls;  call Throw with the
> "jthrowable" you stored before you return from the native function.
> 

Thanks for your input, David.

I guess I'll just leave the "references" dangling around; I am not going to
start messing about putting exceptions away for a moment, unwinding,
reinstating  the exception, handling the possibility that reinstating the
exception fails, etc.
I'm sure they thought about it when they designed the system; I just wish
they'd documented their conclusions.
-- 
Bill Medland
0
Reply billmedland (95) 10/20/2006 7:31:32 PM

Bill Medland wrote:

> I guess I'll just leave the "references" dangling around; I am not going
> to start messing about putting exceptions away for a moment, unwinding,
> reinstating  the exception, handling the possibility that reinstating the
> exception fails, etc.
> I'm sure they thought about it when they designed the system; I just wish
> they'd documented their conclusions.

I think that's a very bad idea.  There is no reason at all (that I know of) to
suppose that it is intended to be safe to leave those "byte-array-regions"
unreleased.  The documentation, as you've noted, contains no hint that that is
allowed.  Also, I can see no sensible reason why the JNI people would put time
and effort into automatic reclaimation of byte-array-regions which only worked
in the error case -- I can just about imagine them wanting[*] to arrange for
automatic reclaimation (similar to reclaiming local references), but if so then
it would surely work in the main-line case, not just the exceptional one.

    -- chris

[*] I can imagine them wanting to arrange that, but I find it a lot harder to
imagine a practical implementation.


0
Reply chris.uppal (3970) 10/23/2006 8:43:38 AM

Chris Uppal wrote:

> Bill Medland wrote:
> 
>> I guess I'll just leave the "references" dangling around; I am not going
>> to start messing about putting exceptions away for a moment, unwinding,
>> reinstating  the exception, handling the possibility that reinstating the
>> exception fails, etc.
>> I'm sure they thought about it when they designed the system; I just wish
>> they'd documented their conclusions.
> 
> I think that's a very bad idea.  There is no reason at all (that I know
> of) to suppose that it is intended to be safe to leave those
> "byte-array-regions"
> unreleased.

"because we thought of that and it won't be a problem; we can define a good
api that won't make the programmer jump through hoops just to write robust
code; after all, we are professional programmers and we would want to write
robust code so lets assume the users of our api will too"

> The documentation, as you've noted, contains no hint that 
> that is
> allowed.  Also, I can see no sensible reason why the JNI people would put
> time and effort into automatic reclaimation of byte-array-regions which
> only worked in the error case -- I can just about imagine them wanting[*]
> to arrange for automatic reclaimation (similar to reclaiming local
> references), but if so then it would surely work in the main-line case,
> not just the exceptional one.

Ah well, whoever said life was easy.  I suppose I'll have to bite on the
bullet.  No wonder there is a tendency not to look at the return code and
simply do what seems to work often enough.

> 
>     -- chris
> 
> [*] I can imagine them wanting to arrange that, but I find it a lot harder
> [to
> imagine a practical implementation.

-- 
Bill Medland
0
Reply billmedland (95) 10/23/2006 2:17:22 PM

Bill Medland wrote:

[me:]
> >  There is no reason at all (that I know
> > of) to suppose that it is intended to be safe to leave those
> > "byte-array-regions"
> > unreleased.
>
> "because we thought of that and it won't be a problem; we can define a
> good api that won't make the programmer jump through hoops just to write
> robust code; after all, we are professional programmers and we would want
> to write robust code so lets assume the users of our api will too"

<grin/>

I think Sun's position is that if you want that kind of thing then you should
be using Java, not C ;-)

    -- chris


0
Reply chris.uppal (3970) 10/23/2006 3:06:42 PM

Chris Uppal wrote:

> Bill Medland wrote:
> 
> [me:]
>> >  There is no reason at all (that I know
>> > of) to suppose that it is intended to be safe to leave those
>> > "byte-array-regions"
>> > unreleased.
>>
>> "because we thought of that and it won't be a problem; we can define a
>> good api that won't make the programmer jump through hoops just to write
>> robust code; after all, we are professional programmers and we would want
>> to write robust code so lets assume the users of our api will too"
> 
> <grin/>
> 
> I think Sun's position is that if you want that kind of thing then you
> should be using Java, not C ;-)
> 
>     -- chris
Yeh.  Anyway, thanks for the reality check, Chris.
-- 
Bill Medland
0
Reply billmedland (95) 10/23/2006 3:57:27 PM

Bill Medland wrote:

> David Lee Lambert wrote:
> 
>> On Thu, 19 Oct 2006 23:20:39 +0000, Bill Medland wrote:
>> 
>>> I'm just trying to do the job properly and the correct answer is not
>>> obvious to me in the documentation.
>>> 
>>> a-If I call GetByteArrayRegion I should later call
>>> ReleaseByteArrayRegion. b-If an exception is thrown then the only
>>> functions that it is safe to call are ExceptionCheck(I presume, but the
>>> docs don't say so), ExceptionClear, ExceptionDescribe and
>>> ExceptionOccurred.
>>> 
>>> So does that mean in the event of an exception we can return safely
>>> without bothering with the ReleaseByteArrayRegion calls (and the system
>>> will tidy up).
>> 
>> There is no ReleaseByteArrayRegion call in the JNI spec.  Did you mean
>> ReleaseByteArrayElements?
> 
> Woops, Yes - I meant Elements, not Region, of course.
> 
>> 
>> Anyway,  according to the way I read the spec, the statement that "When
>> there is a pending exception, the only JNI functions that are safe to
>> call
>> are..." means just what it says.  In general the JVM cleans up dangling
>> references upon return from a native function.  It could be argued that
>> the native-type-array pointers returned by
>> Get<type>ArrayElements, GetStringChars and GetStringUTFChars are not
>> local
>> references, so I always clean them up if possible;  but I'm not sure
>> exactly what different JVMs do.
>> 
>> If you want to do some cleanup that requires calls into the JVM,  you
>> have
>> an alternative:  store the "jthrowable" returned by ExceptionOccurred
>> somewhere;  call ExceptionClear;  make your calls;  call Throw with the
>> "jthrowable" you stored before you return from the native function.
>> 
> 
> Thanks for your input, David.
> 
> I guess I'll just leave the "references" dangling around; I am not going
> to start messing about putting exceptions away for a moment, unwinding,
> reinstating  the exception, handling the possibility that reinstating the
> exception fails, etc.
> I'm sure they thought about it when they designed the system; I just wish
> they'd documented their conclusions.

Latest news.  They(/he) did.  So that just muddies the water even further.
In Sheng Liang's "Programmer's Guide and Specification" his section 11.8.2
lists a much larger selection of functions that are safe to call while
there is an exception pending, including Release<Type>ArrayElements.

So who do you believe?  The author of the design or the documentation that
comes with the product.

Seeing as Sheng Liang actually includes ExceptionCheck in his list, which
the documentation doesn't, and seeing as how I am less than impressed with
Sun's quality on some other things I think it is actually more reasonable
to go with his specification than the one that comes with the Sun Java
product (what a thing to have to say!).

So I am going to assume that it is safe to call
Release<Type>ArrayElements(...JNI_ABORT) with there being an exception
current and that it will not overwrite the exception.
-- 
Bill Medland
0
Reply billmedland (95) 10/23/2006 6:32:36 PM

Bill Medland wrote:

> Latest news.  They(/he) did.  So that just muddies the water even further.
> In Sheng Liang's "Programmer's Guide and Specification" his section 11.8.2
> lists a much larger selection of functions that are safe to call while
> there is an exception pending, including Release<Type>ArrayElements.

Ah! Good.


> So who do you believe?  The author of the design or the documentation that
> comes with the product.

I would believe whichever seemed most plausible ;-)

I'd prefer to believe the spec, and certainly I would take the spec over Liang
if there was a chance that Liang was simplifying (or even being mildly
inaccurate) for the sake of exposition.  But in a case like this where they
flat-out contradict each other, and where the spec is obviously
wrong/incomplete anyway (missing ExceptionCheck(), as you say), I would take
Liang.  After all Liang's stuff was written after, and presumably in full
knowledge of, the spec.

BTW, I found the thing about it being improper to DeleteLocalRef() with the
wrong JNIEnv.  It wasn't quite what or where I remembered it (though it has the
same effect on my code).  In /Liang's/ version of the spec, the second
paragraph of the text for that function states

    Deleting a local reference that does not belong to the topmost
    local reference frame is a no-op. Each native method invocation
    creates a new local reference frame. The PushLocalFrame
    function (added in Java 2 SDK release 1.2) also creates a new
    local reference frame.

So it isn't actually an /error/ as such, although it doesn't do what one might
expect.  There is (irritatingly) no equivalent to that paragraph in the version
of the JNI spec which comes with JDK 1.4 or 1.5...

    -- chris


0
Reply chris.uppal (3970) 10/24/2006 11:23:38 AM

Chris Uppal wrote:

> 
> BTW, I found the thing about it being improper to DeleteLocalRef() with
> the
> wrong JNIEnv.  It wasn't quite what or where I remembered it (though it
> has the
> same effect on my code).  In /Liang's/ version of the spec, the second
> paragraph of the text for that function states
> 
>     Deleting a local reference that does not belong to the topmost
>     local reference frame is a no-op. Each native method invocation
>     creates a new local reference frame. The PushLocalFrame
>     function (added in Java 2 SDK release 1.2) also creates a new
>     local reference frame.
> 
> So it isn't actually an /error/ as such, although it doesn't do what one
> might
> expect.  There is (irritatingly) no equivalent to that paragraph in the
> version of the JNI spec which comes with JDK 1.4 or 1.5...
> 
>     -- chris
Well that was a little brain-dead, wasn't it :-)
So that means if I have a library function that carefully deletes all the
local references it creates I still have to keep track of how many
references there were because if Push/PopLocalFrame is called it needs to
allow for all those references that won't actually be deleted after all.
(What's the smiley for "shakes head in total resignation?")

-- 
Bill Medland
0
Reply billmedland (95) 10/24/2006 5:28:22 PM

Bill Medland wrote:

> Well that was a little brain-dead, wasn't it :-)
> So that means if I have a library function that carefully deletes all the
> local references it creates I still have to keep track of how many
> references there were because if Push/PopLocalFrame is called it needs to
> allow for all those references that won't actually be deleted after all.

That is why my stuff (if run in a mode where there can possibly be more than
one JNIEnv/local frame active) now converts /all/ local references to globals
as soon as it sees them, and at the lowest level of the housekeeping code.  I
tried a few more "clever" approaches (stacks of JNIEnvs and so on) before
deciding they were all too difficult to make right, and fell back to good old
brute force.

Not very nice, really...

    -- chris


0
Reply chris.uppal (3970) 10/26/2006 10:28:34 AM

10 Replies
32 Views

(page loaded in 0.208 seconds)


Reply: