If we want to cache accesses to some prototype that doesn't need repatching when new base structures come along, then we would emit this code:
- Materialize a pointer to the prototype's hashtable for this property.
- Mask or shift the structure ID to produce a hash code (on 64 bit: mask since it's a densely allocated integer ID; on 32-bit: downshift since it's a pointer)
- Load a structure ID from the hashtable.
- Check if it's the one we wanted. (Common case is that we stop here.)
- Bail if it's the deleted value sentinel.
- Increment and loop if it's not the empty value sentinel.
- If we find the structure ID in the hashtable, we produce the result value (either produce the constant or load from the prototype).
The fast path will thus involve one load-and-branch, plus some minor integer computation.
The way this will work is that it will be backed by a hashtable hanging off the prototype's property. Anytime we try to cache an access to that property by way of a prototype chain, we check if the prototype chain is watchable. If it is, we watch it and put the base structure into the hashtable.
Note that the code we generate inlines a pointer to the hashtable and the mask amount. Thus, if we rehash, we trigger watchpoints on those StructureStubInfo's so that they can be regenerated. Alternatively, we would let them regenerate if they ended up taking slow path.
Something that I still need to check is whether those websites that take slow path on these megamorphic loads ends up sharing the same base structures across different static accesses. If they do, then this optimization is going to be great because as soon as an IC is repatched to use the hashtable, it will likely not need to take slow path. But if there's just a huge set of diverse structures that end up in these accesses then we need some other strategy.