Our optimization replaces each dynamic function call with a switch statement and a set of static function calls. Since existing compilers can analyze static functions calls, the compiler is in a better position to perform other optimizations after our optimization is applied. The replacement has the following steps:
It is possible that, after applying these rules, only a single case remains. If so, we replace the switch statement with a single static call.
Example. Figure 2 shows the transformed functions Base::bar(), Sub1::bar(), and process() from Figure 1. Using Rule 2, the cases for Base and Sub2 in function process() are consolidated because Sub2 does not implement its own version of bar(). Also, since Sub1 has no subclasses, Rule 1 leaves a case statement with only one arm. After further optimization, this becomes the static call sub1::foo().
Like many interprocedural optimizations, ours is most effective when the entire source is analyzed at one time. Complete source allows the optimization to obtain complete information about class hierarchies and the use of virtual functions. It is possible to optimize procedures compiled separately, with some loss in the effectiveness. It is also possible to perform the optimization at link time; however, some local optimizations, such as constant propagation, that we hope to enable would be missed. An alternative is the use of a programming environment that incrementally computes summary information for large systems (often as a background task); thus, reducing the need to examine the entire program on each compile without sacrificing the effectiveness of the optimization. Such an environment for SELF programs is described in [8].
Copyright © 1995, 1996 Bradley M. Kuhn, David W. Binkley.
Verbatim copying and distribution of this entire paper is permitted in any medium, provided this notice is preserved.