A generic approach to handle generic methods, aka polymorphic calls, aka dynamic binding.
First, we can conceptually divide this operation into three primitive operations:
Computing the value
Lookup: signature->word
Executing the word
1. Computing the signature
This a simple way to generalize single dispatch, subjective dispatch, multiple dispatch and predicate dispatch.
Examples:
Single dispatch signature: [ drop drop class ]
Multiple dispatch signature: [ [ class ] tri@ ]
Subjective dispatch signature: [ access get ]
Predicate dispatch signature: [ 0 > ]
2. Lookup: signature->word
optimization:
Executing the word
This is trivial. A few important things, though:
At this point, we assume the signature has been fully checked (there is no need for further checks)
optimization: We have the opportunity to do customization, that is, the produce a version of the word that is optimized for the signature
optimization: The next step is speculative inlining. This is what gives it's runtime performance to adaptive recompilation (prime example: Self '93). However, speculative inlining can be done heuristically (like Self '92) or based on runtime profiling information, as we can expect many optimizations to be stable. In these cases, it's possible to compile ahead of time. Using heuristics can achieve impressive performance (the 'within 2x the speed of C' benchmarks were with Self '92, not Self '93), but will very easily break down (trivial changes in the code can result in drastic runtime difference) and might require delayed code generation in order to produce an acceptable amount of code (hence requiring online compilation, thus defeating the purpose of compiling ahead of time).
This revision created on Wed, 22 Oct 2008 02:41:27 by prunedtree