Determining what methods needs to be profiled - A global timestamp counter is kept and incremented every so often (perhaps once every few minutes). Each method contains an activation counter and a timestamp. Whenever a method is invoked, the activation counter is right-shifted by the timestamp delta between the global timestamp and the method's timestamp. The activation counter is then incremented by a constant amount. If the activation counter thus exceeds the threshold (a system-wide value) the method becomes activated for profiling and later optimization. This effects an exponential decay of the counters as used in Self. Instrumenting methods for profiling - Upon being activated for profiling, the method is instrumented to detect the maps of objects being stored in the variables as well as to detect the execution frequency of various paths in the code. An instrumented version of the method's default syntax tree (or optimized syntax tree, if available) is created with nodes linked to their relevant profiling entries and store in the optimized syntax tree field of the method. Variables profiles - Each profiled method contains an array of variable map profiles and an array of execution frequencies. A variable map profile is an array of fixed size (4-8 element pairs) with entries being a pair of the object map and a hit count (with a Nil hit count indicating an unused entry). When an object map is to be inserted into the profile, the profile is checked to see if an entry for it exists. If there is an entry already, the hit count is incremented. If an entry does not exist, an unused entry is then used and initialized with a hit count of 1. If no unused entry could be found, the profile is completely reset (and possibly profiling is disabled for this site by removing the profile from the method's variable map profile array, as it has become "megamorphic"). "variable profile" instruction - Placed immediately following "store variable" and "store free variable" instructions. Profiles object at the top of the stack (the value that was stored) for the corresponding variable (immediate index). Frequency profiles - An execution frequency is an integer entry in the method's execution frequencies array. All entries are initialized to 0. When the specific execution frequency instrumentation is passed, the corresponding entry is incremented. "frequency profile" instruction - Increments execution frequency entry (immediate index) in method's execution frequencies array. Placed at - * the beginning of a method * the beginning of branches of "ifTrue:ifFalse:" and variants * the beginning of body of "loop" * the beginning of the condition of "whileTrue:" and variants * the beginning of branches of "caseOf:" and variants Determining when to stop profiling and optimize - Each method contains a profile counter. Once a method is activated for profiling, it's profile counter is reset. When the method is subsequently invoked, it's profiler counter is incremented. Unlike the activation counter, the profile counter does not decay. Once the profile counter has indicated that the method has executed a requisite number of times (a system-wide value), the method is finally optimized with accumulated profiling information. Optimizing a method from profiling information - After optimized code is generated for a method, it's activation counter is reset, and the instrumentation is removed until it is activated again. Frequency profiles - Any code region where its frequency divided by the frequency of the code region containing it (i.e. the fraction of the time the code is executed from within its containing code) is less than the threshold (a system-wide value), the region of code is deemed unimportant and not optimized. Variable profiles - Variable map profiles that have overflowed are deemed megamorphic, and the type of the variable is subsequently treated as if it is unknown. Variable map profile entries where the hit count divided by the execution frequency of the code region is less than the threshold (a system-wide value) are deemed unimportant and are cleared. The remaining entries give a probability that variable will contain an object with the associated map. Inlining - A map profile type is generated for relevant variables reflecting the variable map profiles except if type information was already available for that variable. Inlining is performed as normal when type information is known about all arguments to a method. In the case where the types of some of the arguments are given by map profile types, various permutations of members of the map types are selected and inline versions of the message invocation are generated in an order with higher frequency permutations coming first, guarded by checks of the argument's maps, with a default message invocation occurring at end if the checks fail. When possible and expedient (i.e. a certain portion above a threshold of all message invocations in a region of code involve an argument whose type includes that map), map checks are factored out by splitting and cloning of parts of the source tree. Inlined methods depending on a map profile type must also be guarded by checks of the form "object delegateSlot == delegateValue" for any and every mutable delegation slot passed in dispatch before arriving at the method. Coarse dependencies are always registered for a method inlined with variable map profile information against every object passed in dispatch before arriving at the method. Registering dependencies - Every map points to its representative object (i.e. the object which caused the map to be created). A list of dependencies is associated with every map. Only dependencies against the representative object may be placed in the map. If dependencies are registered against a clone sharing the map, a new map is generated for the clone of which it is the representative. Any change that would result in a new map being assigned to the representative object of a map (i.e. adding slots, removing slots, changing immutable slots), will also invalidate any dependencies registered on that map. When a dependency for a method is invalidated, the optimized code for the method is completely discarded.