JDK-8067139 : Finally blocks inlined incorrectly
  • Type: Bug
  • Component: core-libs
  • Sub-Component: jdk.nashorn
  • Affected Version: 9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2014-12-10
  • Updated: 2017-08-09
  • Resolved: 2015-01-28
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.
8u60Fixed 9 b49Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
function f(){ 
    try { 
    } catch(x) { 
        print("Caught " + x);
    } finally { 
        throw 0;
} f()

This program prints "Caught 0"; it should not. The issue here is that the "throw 0" is inlined in place of the "return" statement, but the catch block still guards the whole block (with the inline finally replacement). We should inline finallies as blocks, flag them as such, and handle flagged blocks when CodeGenerator processes try/catch/finally nodes to split the exception table ranges to exclude inlined finallies (that's the same strategy javac follows).
For the release note: I have talked with my team, and Sundar suggested that instead of a blog post, I add a page to the OpenJDK Nashorn Wiki ��� his reasoning, that I find convincing is that "blogs are more ephemeral". With that in mind, the page is here: <https://wiki.openjdk.java.net/pages/viewpage.action?pageId=22937606>. For the release notes, I'd just add a paragraph stating something to the effect of "Nashorn has known issues where it incorrectly compiles try/finally constructs" and the link to this page that provides the details. It'd be good to add this to both 8u45 release notes and all earlier 8 releases' notes.

Nashorn's compiler inlines finally blocks in front of a break and continue that transfer control outside of the try block, as well as in front of returns. That's all well, except that such inlining must not make the finally block guarded by the try block's catches, and it must not expose variables that are in the scope in the try block, but not in the finally block (see JDK-8048862 as an example of that). My first try to fix this was to emulate javac. Javac will define the regions in the exception table so that they don't contain the inlined finallies (e.g. if try/catch would guard region of bytecodes 50..100, but the inlined finally is between bytecodes 80..90, then javac emits two entries in the exception table, one for 50..90 and another for 90..100). Unfortunately, JS is different from Java in that we have reified scope objects, and they need to be carefully popped when we leave a block. That is, we also have runtime scope management. Now we would have a need to maybe pop a number of scopes in the inlined finally block, but then we also have another entry in the exception table that also pops the scope and then rethrows when an exception is thrown within a scoped block (making sure a block scope is popped even if we exit the block with an exception). Making sure that we split both ranges for try/catch and ranges for any number of scope-popping exception handlers quickly becomes unwieldy. For that reason I chose a different solution. What I decided on is to emit all inlined finally blocks after the try block (before the catch block, but it could've been after it too; doesn't matter much), and just emit a GOTO at the point where it was formerly inlined. That way, the finally block is definitely outside the bytecode range protected by both the scope-popping exception handler, and the try/catch's exception handler too. There's no need to split exception ranges.

Potentially a duplicate of JDK-8030198. For now let's keep both in mind.