Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy does Java's invokevirtual need to resolve the called method's compile-time class?
    text
    copied!<p>Consider this simple Java class:</p> <pre><code>class MyClass { public void bar(MyClass c) { c.foo(); } } </code></pre> <p>I want to discuss what happens on the line c.foo().</p> <p><strong>Original, Misleading Question</strong></p> <p><em>Note: Not all of this actually happens with each individual invokevirtual opcode. Hint: If you want to understand Java method invocation, don't read just the documentation for invokevirtual!</em></p> <p>At the bytecode level, the meat of c.foo() will be the invokevirtual opcode, and, according to <a href="http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc6.html" rel="nofollow noreferrer">the documentation for invokevirtual</a>, more or less the following will happen:</p> <ol> <li>Look up the foo method defined in <em>compile-time</em> class MyClass. (This involves first resolving MyClass.)</li> <li>Do some checks, including: Verify that c is not an initialization method, and verify that calling MyClass.foo wouldn't violate any protected modifiers.</li> <li>Figure out which method to actually call. In particular, look up c's <em>runtime</em> type. If that type has foo(), call that method and return. If not, look up c's runtime type's superclass; if that type has foo, call that method and return. If not, look up c's runtime type's superclass's superclass; if that type has foo, call that method and return. Etc.. If no suitable method can be found, then error.</li> </ol> <p>Step #3 alone seems adequate for figuring out which method to call and verifying that said method has the correct argument/return types. So my question is why step #1 gets performed in the first place. Possible answers seem to be:</p> <ul> <li>You don't have enough information to perform step #3 until step #1 is complete. (This seems implausible at first glance, so please explain.)</li> <li>The linking or access modifier checks done in #1 and #2 are essential to prevent certain bad things from happening, <em>and</em> those checks must be performed based on the compile-time type, rather than the run-time type hierarchy. (Please explain.)</li> </ul> <p><strong>Revised Question</strong></p> <p>The core of the javac compiler output for the line c.foo() will be an instruction like this:</p> <pre><code>invokevirtual i </code></pre> <p>where i is an index to MyClass' runtime constant pool. That constant pool entry will be of type CONSTANT_Methodref_info, and will indicate (maybe indirectly) A) the name of the method called (i.e. foo), B) the method signature, and C) the name of compile time class that the method is called on (i.e. MyClass).</p> <p>The question is, why is the reference to the compile-time type (MyClass) needed? Since invokevirtual is going to do dynamic dispatch on the runtime type of c, isn't it redundant to store the reference to the compile-time class?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload