JDK-8193222 : EnsureLocalCapacity() should maintain capacity requests through multiple calls
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 9,10
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2017-12-07
  • Updated: 2023-01-04
  • Resolved: 2017-12-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 10 JDK 11 JDK 8
10 b37Fixed 11Fixed 8u371Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
When multiple calls to EnsureLocalCapacity happen over the course of a java native method call (say, in the native method itself, as well as in a function called by the native method), an earlier request for a larger local capacity will be lost/overwritten by a later request for a smaller capacity.

One result is that EnsureLocalCapacity calls can be ineffective for preventing the local ref warning issued under -Xcheck:jni ("WARNING: JNI local refs: XX, exceeds capacity: YY") because the request is "forgotten" due to subsequent (sometimes tricky to spot) calls to EnsureLocalCapacity. 

The attached test case demonstrates the problem when run with  -Xcheck:jni.

Comments
URL: http://hg.openjdk.java.net/jdk/jdk10/rev/fe6fb69336b5 User: jwilhelm Date: 2017-12-20 21:12:15 +0000
20-12-2017

URL: http://hg.openjdk.java.net/jdk/hs/rev/fe6fb69336b5 User: dholmes Date: 2017-12-13 04:16:53 +0000
13-12-2017

Basic fix: --- a/src/hotspot/share/prims/jniCheck.cpp +++ b/src/hotspot/share/prims/jniCheck.cpp @@ -826,7 +826,10 @@ } jint result = UNCHECKED()->EnsureLocalCapacity(env, capacity); if (result == JNI_OK) { - add_planned_handle_capacity(thr->active_handles(), capacity); + // increase local ref capacity if needed + if ((size_t)capacity > thr->active_handles()->get_planned_capacity()) { + add_planned_handle_capacity(thr->active_handles(), capacity); + } } functionExit(thr); return result;
10-12-2017

Given the issue is only with the checked version of EnsureLocalCapacity we can do something fairly simple to fix it, I think - something much cruder than if this were a production issue.
08-12-2017

(from dholmes, in email): "The 'local capacities' are not nesting properly. Within a single native call stack if we set EnsureLocalCapacity in the entry frame then whenever we return to that frame after a call we should still have the same ensured capacity. A call to EnsureLocalCapacity further down the stack should not have any affect on a caller up the stack. A possible fix would be to never have EnsureLocalCapacity decrease the current allowed capacity. But when the top-level native frame returns the capacity should be reset."
07-12-2017