-*- coding: utf-8 -*- Project Name: Metaobject Sealing for CLOS ======== Synopsis Sealing is a technique whereby a programmer may assert that certain metaobjects — such as classes or generic functions — should not and will not be used or extended in certain ways. It is then the responsibility of the object system to verify that this promise is not broken. In addition to clarifying the programmer's intention with regard to a given protocol, sealing enables a variety of optimizations. Because of its highly dynamic nature (allowing redefinitions of classes and methods at runtime), the Common Lisp Object System (CLOS) is able to benefit greatly from a sealing promise. The goal of this project is to define appropriate semantics for sealing in CLOS and investigate how much can be achieved via the CLOS Metaobject Protocol¹ (MOP) alone and what hooks need to be implementation-provided for the sake of efficiency. Furthermore, we would like to implement said hooks for the SBCL² compiler. ¹ ² ========= Rationale The metaobject approach to programming language design seeks to provide elegance and extensibility while simultaneously providing opportunities for implementation efficiency through careful design. A sealing protocol fits this exact pattern. It should be possible to implement a significant part of said protocol through the CLOS MOP. More specifically, the MOP provides plenty of hooks for verifying that a sealing promise is being kept. However, because the MOP is a runtime protocol, this approach is likely to be limited to runtime optimizations which may or may not be straightforward. Hence, we anticipate the need for implementation-specific hooks, particularly in the area of compile-time optimizations. It is one of the goals of this project to identify this boundary between what can/should be implemented portably and what should be provided by specific implementations. The obvious metaobject candidates for sealing are classes and generic functions and it might be worthwhile to study the effects of sealing specializers, method combinations, and methods. Possible optimization avenues opened by sealing include: 1. compile-time method selection and combination; applicable methods can be computed and combined according to the generic function's method combination into an effective method function at compile-time. 2. slot-value cloning and inlining; slot accesses can be turned into direct memory accesses with an offset from the start of the object, possibly inlined, very much like structure slot access is optimized in some CL compilers. 3. method cloning and inlining; just as class slot access can approach that of structure slot access, so can generic function calls be identical to regular function calls. Effective methods can be cloned for specific types, opening way for optimization (4). 4. more precise type inferencing; optimizations (2) and (3) allow improvements in flow-based type inference, by putting barriers on where uncertain types can flow from/to. Not only the generic functions' bodies benefit from this but also the call sites. The same applies to slot-value being able to propagate declared slot types. In short, these optimizations have the potential to bring classes and generic functions up to pair with structures and regular functions, performance-wise, substituting the approach of rewriting the former in terms of the latter (for purposes of optimization) with sealing. One of the most important steps in this project will be figuring out the exact semantics of sealing for the various metaobjects. For instance, possible sealing alternatives for classes could be: * Shallow sealing: the class may not be further subclassed directly, but might be subclassed indirectly. * Deep sealing: the class may not be further subclassed in any way, directly or indirectly. * Redefinition sealing: the class (and perhaps its superclasses) may not be redefined. Each presents different optimization opportunities. It is one of the main purposes of this project to clearly define these semantics and associated optimization opportunities. Similarly, sealing a generic function would forbid adding new methods but it might be desirable to seal only particular intersections of methods and argument types. This would allow for optimization without eschewing extensibility altogether. Following Lisp's and CLOS' best traditions in dynamism, this protocol should be complete with unsealing operations. Naturally, this has serious implications regarding the way optimizations should be performed and this potentially turns sealing into a hint that optimizations that are potentially expensive to back out can and should be used. Moreover, more extreme, ‘irreversible’, optimizations such as full-fledged method selection and inlining (that would require recompilation of the call sites in order to be backed out or redone) could be applied when compiling with specific optimization levels, for instance. This might be particularly sensible in compilerless delivery scenarios.