Since the type of the object is not specified and because of potential method overloading, it is impossible to decide ahead of time which concrete implementation of the toString-method is going to be invoked.
To achieve better performance, many language runtimes employ some form of non-inline caching where the results of a limited number of method lookups are stored in an associative data structure.
This can greatly increase performance, provided that the programs executed are "cache friendly" (i.e., there is a limited set of methods that are invoked frequently).
In those cases, performance can be increased greatly by storing the result of a method lookup "inline"; i.e., directly at the call site.
If the language runtime reaches the same call site again, it retrieves the callee from it and invokes it directly without performing any more lookups.
To account for the possibility that objects of different types may occur at the same call site, the language runtime also has to insert guard conditions into the code.
The following example constitutes a worst-case scenario for monomorphic inline caching: Again, the method toString is invoked on an object whose type is not known in advance.
A "polymorphic" call site decides which of a limited set of known methods to invoke based on the type that it is currently presented with.
In other words, with polymorphic inline caching, multiple method lookup results can be recorded at the same call site.
A megamorphic inline cache can be implemented by creating code to perform a first-level method lookup for a particular call-site.