-
Notifications
You must be signed in to change notification settings - Fork 0
IMT
Method dispatch table for interface calls, optimized over vtable.
The IMT (Interface Method Table) is a fixed-size hash table embedded in the TIB (Type Information Block) that enables efficient interface method dispatch. Unlike the vtable which provides O(1) lookup for class inheritance calls, interface dispatch must find the correct implementation among all interfaces implemented by a class. The IMT solves this by using a precomputed hash of method name and signature (the "selector") to index into a fixed 64-element table (ObjectLayout.IMT_LENGTH).
Interface dispatch is fundamentally harder than virtual method dispatch because:
- A class can implement multiple interfaces, each with potentially overlapping method sets
- The set of interfaces is determined at compile time but resolved at runtime
- Finding the right method without a table would require walking the interface hierarchy
The IMT addresses this by computing index = selector % 64 at class preparation time. Each slot either holds a single method (no collision) or a collision list (chained linear search). The CompiledIMT layer further optimizes this into architecture-specific machine code for fast runtime dispatch.
| Class / File | Role |
|---|---|
core/src/core/org/jnode/vm/classmgr/IMTBuilder.java |
Builds the IMT with hash-based insertion and collision chaining |
core/src/core/org/jnode/vm/classmgr/VmClassType.java |
Implements prepareIMT() constructing IMT from all implemented interfaces |
core/src/core/org/jnode/vm/classmgr/VmType.java |
Coordinates IMT creation during class preparation, stores in TIB |
core/src/core/org/jnode/vm/classmgr/ObjectLayout.java |
Defines IMT_LENGTH = 64 as the hash table size |
core/src/core/org/jnode/vm/classmgr/VmConstIMethodRef.java |
Holds selector for interface method references |
core/src/core/org/jnode/vm/compiler/IMTCompiler.java |
Abstract base for architecture-specific IMT compilation |
core/src/core/org/jnode/vm/compiler/CompiledIMT.java |
Abstract result of IMT compilation, provides getIMTAddress()
|
core/src/core/org/jnode/vm/x86/compiler/X86CompiledIMT.java |
x86-specific CompiledIMT holding bytecode array |
The IMT lives in the TIB at fixed indices alongside the vtable:
TIB[index] Layout:
[0] VmType reference
[1] IMT (Interface Method Table) — Object[]
[2] IMT collision flags — boolean[]
[3] CompiledIMT — compiled dispatch code
[4] Superclasses array
[5..N] vtable (VmInstanceMethod references)
See Object-Layout for full TIB structure and Virtual-Methods for the complete picture.
The IMT is a fixed 64-element array (ObjectLayout.IMT_LENGTH). Method lookup uses:
index = selector % IMT_LENGTH // selector = hash(name + signature)This gives a constant-time first probe. If the slot is occupied by a different method, a collision list is searched.
IMTBuilder constructs the IMT by iterating over all interface methods and inserting them:
public IMTBuilder() {
final int length = ObjectLayout.IMT_LENGTH; // 64
this.imt = new Object[length];
this.imtCollisions = new boolean[length];
}
public void add(VmInstanceMethod method) {
final int index = method.getSelector() % getLength();
if (imt[index] == null) {
// Empty slot — direct insert
imt[index] = method;
} else if (imtCollisions[index]) {
// Already a collision list — extend it
final Object[] oldList = (Object[]) imt[index];
final Object[] newList = new Object[oldList.length + 1];
System.arraycopy(oldList, 0, newList, 0, oldList.length);
newList[oldList.length] = method;
imt[index] = newList;
} else {
// First collision at this slot — create a list
final Object[] collisionList = new Object[2];
collisionList[0] = imt[index]; // Existing method
collisionList[1] = method; // New method
imt[index] = collisionList;
imtCollisions[index] = true;
collectionCount++;
}
}The IMT is built during class preparation by VmClassType.prepareIMT():
IMTBuilder imtBuilder = new IMTBuilder();
for (VmInterfaceClass intf : allInterfaces) {
for (VmMethod intfMethod : intf.getType().getMethods()) {
if (intfMethod.isPublic() && !intfMethod.isStatic()) {
final VmInstanceMethod clsMethod = resolveInterfaceMethod(intfMethod);
imtBuilder.add(clsMethod);
}
}
}
// Result stored in TIB at IMT_INDEX, collisions at IMTCOLLISIONS_INDEX
tib[TIBLayout.IMT_INDEX] = imtBuilder.getImt();
tib[TIBLayout.IMTCOLLISIONS_INDEX] = imtBuilder.getImtCollisions();For faster runtime dispatch, the IMT is compiled into architecture-specific machine code:
final CompiledIMT cimt = loader.compileIMT(imtBuilder);
tib[TIBLayout.COMPILED_IMT_INDEX] = cimt.getIMTAddress();IMTCompiler is the abstract base; X86CompiledIMT holds the resulting bytecode array. The compiled form is a jump table that maps a selector hash directly to the method code entry, avoiding collision list traversal in the common (no-collision) case.
When an interface method is invoked on an object, the runtime resolves it via:
- Load TIB reference from object header (offset -1)
- Load IMT array from TIB[1]
- Compute
index = methodRef.getSelector() % 64 - Lookup
imt[index] - If single method, use it; if collision list, linear search by selector
- Fixed hash table size: The 64-element IMT is shared across all classes. As more interface methods are added to a class, the probability of collisions increases. The collision list mechanism handles this, but lookup is no longer pure O(1).
- Selector hashing: The selector is a precomputed hash of method name + signature, not a sequential index. Selector values are stable per method reference across the entire VM.
- Class-specific collision patterns: Two classes implementing the same interfaces may have different collision lists because method insertion order varies. The JIT cannot assume IMT slot contents are identical across classes.
- CompiledIMT as optimization: If CompiledIMT is null, the runtime falls back to Java-side IMT lookup with collision list traversal. The compiled form is preferred because it inlines the dispatch logic.
-
JIT must understand IMT structure: Interface call compilation (
visit_invokeinterface) cannot use simple indexed load like virtual calls (visit_invokevirtual). The JIT must emit the hash computation and conditional branch for collision handling, or use the CompiledIMT if available. - Multiple interfaces with same method: If two interfaces declare the same method (name + signature), the IMT handles this correctly because both resolve to the same selector and thus the same IMT slot.
- Virtual-Methods — Overview of method dispatch including vtable and IMT relationship
- vtable — Virtual method table for class inheritance dispatch
- Object-Layout — TIB structure and object header layout
- Type-System-Internals — VmType hierarchy, class preparation, and TIB construction
- JIT-Compilers — How compilers use IMT for interface call compilation
- CompiledIMT — Architecture-specific compiled IMT (referenced from this page)