OrenIshShalom
OrenIshShalom

Reputation: 7162

How to view the virtual function table of an inherited Java class

I have the following java code:

class Father  {
    public void walk(int x) { System.out.format("Fwalk %d", x); }
    public void run (int x) { System.out.format("Frun  %d", x); }
    public void swim(int x) { System.out.format("Fswim %d", x); }
}
class Son extends Father {
    public void swim(int x) { System.out.format("Fswim %d", x); }
    public void cook(int x) { System.out.format("Scook %d", x); }
    public void run (int x) { System.out.format("Frun  %d", x); }
}
class main {
    public static void main(String[] args) {
        Father f = new Father();
        f.run(1);
        f.swim(2);
        Son s = new Son();
        s.run(3);
        s.swim(4);
    }
}

I'm looking for the actual offsets of swim and run in the virtual function tables. When I use an equivalent C++ code, I am able to do that easily with objdump:

 663     f->run(1);
 664  8c3:   48 8b 45 e0             mov    -0x20(%rbp),%rax
 665  8c7:   48 8b 00                mov    (%rax),%rax
 666  8ca:   48 83 c0 08             add    $0x8,%rax <------ offset 8 for father::run

And the same offset for inherited class:

 689     s->run(3);
 690  914:   48 8b 45 e8             mov    -0x18(%rbp),%rax
 691  918:   48 8b 00                mov    (%rax),%rax
 692  91b:   48 83 c0 08             add    $0x8,%rax <------ offset 8 for son::run

When I use Apache's class utility, I get something close (the pool constants)

1)CONSTANT_Methodref[10](class_index = 11, name_and_type_index = 20)
2)CONSTANT_Class[7](name_index = 21)
3)CONSTANT_Methodref[10](class_index = 2, name_and_type_index = 20)
4)CONSTANT_Methodref[10](class_index = 2, name_and_type_index = 22)
5)CONSTANT_Methodref[10](class_index = 2, name_and_type_index = 23)
6)CONSTANT_Class[7](name_index = 24)
7)CONSTANT_Methodref[10](class_index = 6, name_and_type_index = 20)
8)CONSTANT_Methodref[10](class_index = 6, name_and_type_index = 22)
9)CONSTANT_Methodref[10](class_index = 6, name_and_type_index = 23)
10)CONSTANT_Class[7](name_index = 16)
11)CONSTANT_Class[7](name_index = 25)
12)CONSTANT_Utf8[1]("<init>")
13)CONSTANT_Utf8[1]("()V")
14)CONSTANT_Utf8[1]("Code")
15)CONSTANT_Utf8[1]("LineNumberTable")
16)CONSTANT_Utf8[1]("main")
17)CONSTANT_Utf8[1]("([Ljava/lang/String;)V")
18)CONSTANT_Utf8[1]("SourceFile")
19)CONSTANT_Utf8[1]("main.java")
20)CONSTANT_NameAndType[12](name_index = 12, signature_index = 13)
21)CONSTANT_Utf8[1]("Father")
22)CONSTANT_NameAndType[12](name_index = 26, signature_index = 27)
23)CONSTANT_NameAndType[12](name_index = 28, signature_index = 27)
24)CONSTANT_Utf8[1]("Son")
25)CONSTANT_Utf8[1]("java/lang/Object")
26)CONSTANT_Utf8[1]("run")
27)CONSTANT_Utf8[1]("(I)V")
28)CONSTANT_Utf8[1]("swim")

It seems like the entries to the virtual function table are name-based ("run", "swim"). Is this really so? For completion, here is the Java script to extract the constants pool.

import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.ConstantPool;

class test
{
    public static void main(String[] args)
    {
        try
        {
            ClassParser c = new ClassParser(args[0]);
            JavaClass j = c.parse();
            ConstantPool cp = j.getConstantPool();
            System.out.format(cp.toString());
        }
        catch (Exception e) { return; }
    }
}

Upvotes: 2

Views: 361

Answers (1)

Denis Rodin
Denis Rodin

Reputation: 319

Post from Lalith Suresh [3]

At the bytecode level, the invokevirtual operation is what triggers the Java equivalent of a C++ virtual method call [1]. As per the specification, the operation accepts an index (two actually, but it is combined to get a single value) which is used to get a reference to a method and a reference to the class in which the method is to be found. In HotSpot [2], this corresponds to a vtable index within the target class, resolving which the intended target method can be invoked. Depending on the class hierarchy, each class may have a differently sized vtable, and child classes that override methods of a parent can re-use vtable.

However, in the JIT compiled code, the vtable calling sequence is typically not used. HotSpot performs inline caching, wherein the code optimistically assumes that the target of a virtual method always points to the same implementation (meaning the call site is monomorphic). In this case, a check is inserted into the code to verify whether the assumption actually holds (that is, the target hasn't changed), and then control is passed directly to the target method without involving any vtable lookups, akin to how a so-called 'unlinked' call site works. Loosely put, if this assumptions fails enough times, the code falls back to the long-winded vtable lookup approach.

[1] https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokevirtual

[2] https://wikis.oracle.com/display/HotSpotInternals/VirtualCalls

[3] https://www.quora.com/How-is-the-virtual-method-table-implemented-in-Java

Upvotes: 3

Related Questions