Go

What is an itab, when is it built, and what does a method call through an interface cost?

Question 78HardGo 1.22 to 1.25

An itab pairs one (interface type, concrete type) combination with the method pointers the concrete type provides for that interface. When the compiler can see a conversion statically (var r io.Reader = f where f is *os.File), it emits the itab into the binary as read-only data. When the pairing is only known at runtime (a type assertion or switch to an interface, such as x.(io.Writer)), the runtime calls getitab. That function builds the itab by matching the sorted method lists (roughly O(m+n)) and caches it in a global hash table, so the next lookup is cheap. Since Go 1.22, type switches and assertions to interfaces also get per-call-site caches.

A method call through an interface loads tab.fun[i] and makes an indirect call with data as the receiver. The indirection itself costs little. The real cost is that the compiler usually cannot inline the callee, and escape analysis often gives up, so arguments move to the heap.

// Assertion to a concrete type: one pointer comparison (tab._type == &type.T)
f, ok := r.(*os.File)

// Assertion to an interface: itab lookup (cached)
w, ok := r.(io.Writer)

Profile-guided optimization (PGO, Go 1.21+) can devirtualize hot interface calls: it adds a guarded direct call to the most common concrete type, which can then be inlined.

More on Interfaces, Methods & Embedding

All 35 Interfaces, Methods & Embedding questions