(M) RFR: 8081800: AbstractMethodError when evaluating a private method in an interface via debugger

Daniel D. Daugherty daniel.daugherty at oracle.com
Thu Sep 29 07:08:52 UTC 2016


On 9/28/16 5:50 AM, David Holmes wrote:
> Warning: long discussion, but in the end relatively simple code 
> change. :)
>
> Thanks to Karen for explaining vtables and itables and pointing out 
> various tests to be executed; Coleen for the discussions around 
> interface initialization and terminology, and pointing me to simple 
> redefinition tests; and Stas Lukyanov for indicating the right JCK 
> tests to run.
>
> Bug: https://bugs.openjdk.java.net/browse/JDK-8081800
>
> Background:
>
> In JDK 8 default and static interface methods were added to the Java 
> language. Private interface methods were also considered, and support 
> in the VM was added, but were dropped due to schedule pressure. In 
> Java 9 private interface methods have now been enabled at the 
> language-level and because the VM already supported invokespecial for 
> private interface methods, the direct language use, and core 
> reflection use, of these methods works fine. However, what was 
> overlooked (and which the test case in this bug report highlighted) 
> was that the other interfaces to the VM (JNI, JDWP, JDI, JVM TI) had 
> not been updated to account for private interface method, and such 
> usage did not work.
>
> The updates to the specifications, plus some small JDI/JDWP related 
> code changes are being handled under:
>
> JDK-8165827 Support private interface methods in JDI, JDWP and JDB
> https://bugs.openjdk.java.net/browse/JDK-8165827
>
> This bug, although originally discovered via JDI/JDB, is being used to 
> fix the underlying mechanics in the VM used by the JNI layer - after 
> which the test in the bug report will run fine.
>
> Problem:
>
> Because private interface methods are only invocable via invokespecial 
> (the JVMS goes to great lengths to explicitly prohibit all other 
> invocation forms on them) they are in essence always statically bound 
> and don't require lookup in either itables (for invokeinterface) or 
> vtables (for general lookup). However, JNI etc, uses itables/vtables 
> to perform their invocations, and what we got was behaviour where the 
> private interface methods did have an itable entry, which made them 
> appear to be regular abstract interface methods, and so they ended up 
> with initial vtable entries that were set to throw AbstractMethodError 
> on invocation (normally those vtable entries would be replaced by the 
> concrete methods in the implementing class) - and that is what was 
> observed via JDB. It turns out that depending on whether a class 
> method with the same signature existed in a class implementing the 
> interface, that you could also get IllegalAccessError (a path that 
> actually crashes the debug VM due to an assertion failure in jni.cpp!).
>
> Solution:
>
> Private interface methods do not need, and should not have, an itable 
> entry - they are never invoked via invokeinterface. (Thanks Karen)
>
> Private interface methods can always be statically bound - 
> Method::can_be_statically_bound() should return true, and their vtable 
> entry should be Method::nonvirtual_vtable_index.
>
> Private interface methods are not default methods and 
> Method::is_default_method() should return false. There is a 
> terminology confusion here that I address further down.
>
> See the bug report for a detailed analysis of all the places where 
> changing these Method properties may have had an affect.
>
> Main webrev:
>
> http://cr.openjdk.java.net/~dholmes/8081800/webrev.hotspot/
>
> The main changes are in:
> - klassVtable.cpp
> - method.cpp
>
> there are minor changes to comments and assertions in other files (the 
> jni.cpp change was due to the crash I encountered that I referred to 
> earlier). The change in linkResolver.cpp fixes an error in the tracing 
> code as the bytecode need not be "invokeinterface" and clarifies it is 
> an interface method (and adds a missing colon in the message) - there 
> is a corresponding tweak to the logging/ItablesTest.java test.
>
> I added new tests for JNI invocations of private, interface methods, 
> and also to test JVM TI retransformation of private and default 
> interface methods.
>
> ---
>
> Terminology problem:
>
> While working on this issue, and helping Coleen with:
>
> 8163969: Cyclic interface initialization causes JVM crash
>
> it became apparent that there was a terminology error in the VM code 
> with respect to default methods. A "default method" is very 
> specifically a public interface method, marked with the default 
> keyword, which has a method body defined. A static interface method 
> also has a body, but is not a default method. A private interface 
> method also has a body, but is not a default method. The JVMS refers 
> to non-static, non-abstract interface methods - which covers default 
> methods and private interface methods. But the code in the VM, 
> primilarly in instanceKlass.cpp and classFileParser.cpp used the term 
> "default methods" to mean "non-abstract and non-static" - which is 
> wrong and potentially very confusing. So a second part of this change 
> is to rename "has_default_methods" (and related variables) to 
> "has_nonstatic_concrete_methods". This is somewhat of a mouthful, 
> though less so than has_nonstatic_nonabstract_methods. Suggestions to 
> abbreviate this to has_nsna_methods, or has_nans_methods, were 
> rejected during pre-review.
>
> The renaming webrev is here:
>
> http://cr.openjdk.java.net/~dholmes/8081800/webrev.hotspot-rename/

src/share/vm/c1/c1_GraphBuilder.cpp
     No comments.

src/share/vm/ci/ciInstanceKlass.cpp
     No comments.

src/share/vm/ci/ciInstanceKlass.hpp
     No comments.

src/share/vm/classfile/classFileParser.cpp
     L5338:  if (_has_nonstatic_concrete_methods ) {
         nit: please delete space before ')'

src/share/vm/classfile/classFileParser.hpp
     No comments.

src/share/vm/oops/instanceKlass.cpp
     No comments.

src/share/vm/oops/instanceKlass.hpp
     No comments.

Thumbs up. I can't think of any good ways to verify that all
appropriate mentions of "default method" are changed without
visiting them all... sigh... these kinds of changes are hard.

Dan


>
> and is best viewed via the patch file, where the renaming is more 
> obvious. In classFileParser.cpp I also simplified the check for static 
> interface methods in pre-java8 classfiles.
>
> ---
>
> Testing:
>  - JPRT
>  - nsk.jdb/jdi/jdwp/jvmti
>  - jtreg: com/sun/jdi (including InterfaceMethodsTest)
>           runtime/SelectionResolution/
>  - internal: vm.defmeth
>  - JCK: subset of lang and vm tests that cover default/static/private 
> interface methods
>  - new tests
>
> Together these tests cover interface method invocation at the language 
> level, via core reflection, via MethodHandles, via JNI, via 
> JDI/JDWP/JDB, and via JVM TI.
>
> Thanks,
> David



More information about the hotspot-runtime-dev mailing list