filtering JAVAC.TRYWITH
This page discusses a not yet available feature!
Based on source code of javac and practical observations - it generates bytecode that is equivalent to the compilation of source code that is described in JLS 14.20.3. try-with-resources
Note that case of multiple resources looks like multiple nested try-with-resources statements.
javac from JDK 9 EA b160 does the same, but with some optimizations (see JDK-7020499):
-
null
check for resource is omitted when it is initialized asnew ...
- when number of copies of closing logic reaches threshold, this logic is extracted into synthetic method
$closeResource
containing calls to methodsaddSuppressed
andclose
,null
check for resource (if present - see above) is done before call of this method; when synthetic method not usednull
check ofprimaryExc
comes beforenull
check of resource
In general:
- body block
- closing resources (in reverse order of opening) on a non-exceptional path
-
finally
block on a non-exceptional path in case ofreturn
from body -
return
(note that this instruction belongs to a line of originalreturn
statement) orgoto
- handlers to close resources (in reverse order of opening) on exceptional path
-
finally
block on exceptional path and additional handlers forcatch
blocks -
finally
block on a non-exceptional path in case ofgoto
from body
Note that synthetic method either will be used for all resources, either for none of them. However this is not the case for null
check.
@Godin: in current implementation association between resource and slot of variable is done on exceptional path and is used to find close of resource on a non-exceptional. Possibility that null
check of resource comes after null
check of primaryException
implies that this order should be determined before doing association.
ECJ on the other hand generates "contiguous" block to close all resources that uses single variable primaryExc
.
Also note that in case of return
from body ECJ won't generate jump
s between blocks that close different resources.
Uncovered corner cases - https://github.com/jacoco/jacoco/pull/500#issuecomment-296285412
To close resource on exceptional path javac 7-8 generates
ASTORE t
ALOAD t
ASTORE primaryExc
ALOAD t
ATHROW
ASTORE t
ALOAD primaryExc
IFNULL L
ALOAD r
INVOKEINTERFACE close()V
GOTO L
ASTORE t
ALOAD primaryExc
ALOAD t
INVOKEVIRTUAL java/lang/Throwable#addSuppressed(Ljava/lang/Throwable;)V
GOTO L
ALOAD r
INVOKEINTERFACE close()V
ALOAD t
ATHROW
L:
ECJ for
try (r0 = ...; r1 = ...; r2 = ...) {
...
} finally {
...
}
generates
// body
r0.close:
ALOAD 5
IFNULL r1.close
ALOAD 5
INVOKEVIRTUAL close()V
GOTO r1.close
ASTORE 1
ALOAD 5
IFNULL L
ALOAD 5
INVOKEVIRTUAL close()V
L:
ALOAD 1
ATHROW
r1.close:
ALOAD 4
IFNULL r2.close
ALOAD 4
INVOKEVIRTUAL close()V
GOTO r2.close
ASTORE 2
ALOAD 1
IFNONNULL S
ALOAD 2
ASTORE 1
GOTO E
S:
ALOAD 1
ALOAD 2
IF_ACMPEQ E
ALOAD 1
ALOAD 2
INVOKEVIRTUAL java/lang/Throwable#addSuppressed(Ljava/lang/Throwable;)V;
E:
ALOAD 4
IFNULL L
ALOAD 4
INVOKEVIRTUAL close()V
L:
ALOAD 1
ATHROW
r2.close:
ALOAD 3
IFNULL end
ALOAD 3
INVOKEVIRTUAL close()V
GOTO end
ASTORE 2
ALOAD 1
IFNONNULL S
ALOAD 2
ASTORE 1
GOTO E
S:
ALOAD 1
ALOAD 2
IF_ACMPEQ E
ALOAD 1
ALOAD 2
INVOKEVIRTUAL java/lang/Throwable#addSuppressed(Ljava/lang/Throwable;)V
E:
ALOAD 3
IFNULL L
ALOAD 3
INVOKEVIRTUAL close()V
L:
ALOAD 1
ATHROW
ASTORE 2
ALOAD 1
IFNONNULL S
ALOAD 2
ASTORE 1
GOTO E
S:
ALOAD 1
ALOAD 2
IF_ACMPEQ E
ALOAD 1
ALOAD 2
INVOKEVIRTUAL java/lang/Throwable#addSuppressed(Ljava/lang/Throwable;)V
E:
// throw primaryExc
ALOAD 1
ATHROW
// additional handlers for `catch` blocks and finally on exceptional path
end:
// finally on normal path
ECJ for
try (r0 = ...; r1 = ...; r2 = ...) {
...
return ...
} finally {
...
}
generates
// body
// close r0 on a normal path
ALOAD 5
IFNULL L
ALOAD 5
INVOKEVIRTUAL close()V
L:
// close r1 on a normal path
ALOAD 4
IFNULL L
ALOAD 4
INVOKEVIRTUAL close()V
L:
// close r2 on a normal path
ALOAD 3
IFNULL L
ALOAD 3
INVOKEVIRTUAL close()V
L:
// finally on a normal path
ARETURN
// close r0 on exceptional path
ALOAD 5
IFNULL L
ALOAD 5
INVOKEVIRTUAL close()V
L:
ALOAD 1
ATHROW
ASTORE 2
ALOAD 1
IFNONNULL S
ALOAD 2
ASTORE 1
GOTO E
S:
ALOAD 1
ALOAD 2
IF_ACMPEQ E
ALOAD 1
ALOAD 2
INVOKEVIRTUAL java/lang/Throwable#addSuppressed(Ljava/lang/Throwable;)V
E:
// close r1 on exceptional path
ALOAD 4
IFNULL L
ALOAD 4
INVOKEVIRTUAL close()V
L:
ALOAD 1
ATHROW
ASTORE 2
ALOAD 1
IFNONNULL S
ALOAD 2
ASTORE 1
GOTO E
S:
ALOAD 1
ALOAD 2
IF_ACMPEQ E
ALOAD 1
ALOAD 2
INVOKEVIRTUAL java/lang/Throwable#addSuppressed(Ljava/lang/Throwable;)V
E:
// close r2 on exceptional path
ALOAD 3
IFNULL L
ALOAD 3
INVOKEVIRTUAL close()V
L:
ALOAD 1
ATHROW
ASTORE 2
ALOAD 1
IFNONNULL S
ALOAD 2
ASTORE 1
GOTO E
S:
ALOAD 1
ALOAD 2
IF_ACMPEQ E
ALOAD 1
ALOAD 2
INVOKEVIRTUAL java/lang/Throwable#addSuppressed(Ljava/lang/Throwable;)V
E:
// throw primaryExc
ALOAD 1
ATHROW
// additional handlers for `catch` blocks and finally on exceptional path