|
Flexible Metalevel Architectures:
by Serge Shumilov
|
|
AbstractThis report presents a review of recent research into metalevel architectures. In this context, metalevel architectures are taken to be those whose designs have been motivated to some degree by the desire to allow the system to be tailored, either statically or dynamically, to the requirements of specific applications or application domains.
Common comparisonThe area of meta-level architectures, reflective computing and open implementations has received considerable attention of late. While most of the systems related to our work have differed either in focus or approach, they have all achieved their goals by opening or exposing the implementation of fundamental system components. Regardless of what behaviours they describe and how they are described, by accessing and manipulating the exposed interfaces, users modify and control the environment in which their objects live and execute. The net result of that is the ability to adapt objects to different and changing computational environments.Direct comparison between existing meta-level architectures is a tenuous proposition at best. Existing architectures typically focus on different aspects of object behaviour and so naturally have different capabilities. By abstracting out notions of capability we can at least try to position architectures relative to one another. Users can then match the capabilities of an architecture to their requirements. We also evaluate our system in terms of end-user performance in an effort to show that the system is usable as an environment for prototyping and experimentation.
The general goals of an architecture for open implementation are:
Based on the goals, we identify a number of properties which we use to informally relate systems to each other. We show that our architecture provides a reasonable level of support for these properties and so satisfies our overall goals for meta-level architecture design. Since most systems support a reasonable separation between the base- and meta-levels, we do not consider this aspect in the comparison. Support for the other aspects (i.e., expressiveness, extensibility and programmability) however varies widely. The properties used in the analysis are enumerated and described below, and related to existing architectures. There is one row in the table for each system and one column for each property. The meanings of the table's symbols are given bellow. We have not listed properties which we have found to be present or absent from all systems. Architecture 1 2 3 4 5 6 7 8 9 10 CodA . # . . . # . . # CLOS MOP . . W - W - # . W ABCL/R2 W W # - # W W W # AL-1/D . # . W # W # W . RbCl # # . W W - . . . Apertos . # # # . # . . . Symbol Meaning . Fully and explicitly supported. # Partially (in scope or depth) supported. W Not explicitly supported. - Not applicable. Depends on unsupported property. Table : The relationship between meta-level architectures.1. Is the programmer's interface clearly and well-defined? That is, does the architecture specifically set out a programmer's interface or is it left as an implementation detail? Such an interface is both in terms of objects and methods. Without a concrete structure, meta-level programmers are left on their own both to figure out how the system works and how to write their code so that it can be integrated with that of others. Of primary importance here is the granularity of the interface. Simply having a few high-level entry points may support meta-level use but does not support meta-level change. A meta-level object, like all objects, should present a rich, multi-level interface protocol. 2. Are the architecture's behaviour abstractions high-level? For the concepts that can be expressed, do the abstractions presented closely match the fundamental concepts of the system (e.g., message passing)? How many operations must a meta-level programmer invoke to effect some behaviour. Systems with good abstraction require relatively few since they have abstracted the details into a higher-level interface. 3. Does the architecture facilitate the description of object behaviour from more than one computational domain (e.g., sequential, concurrent, multi-threaded or distributed objects) or are all objects basically the same. This relates to the independence of the architecture from the object/language models it supports. Is the architecture a mechanism for reifying a particular language or computational structure, or is it more general. An open architecture will allow anything to be implemented but having a strong and clear separation between the architecture and the object models enables both the implementation of radically different computation styles and the inter-operation of objects using these styles. 4. Does the architecture have specific support for extension? The simple ability to add to the architecture is insufficient here. Without a framework for tracking and managing this change, user's will develop their own ad hoc styles which will clash when combined. Frameworks can range from simple structuring conventions to explicit mechanical support. 5. Does the architecture support the encapsulation of object models? This is closely related to the idea of abstraction but for structuring rather than interfaces and execution. Simple models are easily described by changes to, or the addition of, a few methods or objects in a restricted area of the meta-level. More complex behaviours affect many methods and objects from various parts of the meta-level. We must be able to manipulate entire behaviours as a small number of atomic concepts regardless of their complexity. 6. Does the architecture support object model combination and configuration? Architectures with frameworks and encapsulation implicitly support model combination. However, factors relating to granularity and complexity also come into play when configuring meta-levels. Combination and configuration support enables the merging of two or more models whose changes and additions range over diverse parts of the meta-level. This is essential if the meta-level architecture is to scale to support many different models. 7. Is object behaviour reified to a reasonably fine granularity? All object-oriented meta-level architectures reify behaviour as objects at the meta-level. The important questions are; how many and how were they derived? The granularity of the decomposition has a profound effect on the nature of the use of the meta-level. Finer objects allow more flexibility but require more maintenance. The objects in a coarser decomposition are more easily used (i.e., they have a higher-level interface) but the behaviour they describe is more difficult to reuse. 8. Does the architecture support the reuse of behaviour descriptions (e.g., meta-components)? If an architecture has a sound framework including model encapsulation then it has implicit support for reuse. This is enhanced by a consistent and fine-grained decomposition of the meta-level as well as any explicit reuse mechanisms which may be provided. Decomposition into methods does not form a sound basis for reuse as individual methods do not generally support reuse. 9. Does the architecture reify low-level system related behaviours such as garbage collection, process scheduling and object location? Some of the systems considered have no relation to such operating system level concepts while others deal mainly with these issues. 10. Performance. Our goals for performance fall into two categories; execution and design. On the one hand, to have an effective system, one which people can actually use, we must have reasonable execution performance. The amount of overhead introduced should correspond to the meta-level reification and modification done. That is, users should only pay for what they use. On the other hand, usability or design performance is related to how easy the system is to program, extend and apply. To improve performance in this area the system must support a wide range of behaviour descriptions and be extensible so as to facilitate completely new behaviours. It should also use and support typical software engineering practices such as encapsulation and reuse. Furthermore, when changes to the meta-level are applied, they must not require extensive changes to the base-level code. And so a tension arises --- A system which is very fast but horribly difficult to use is not very effective. The converse is also true. Beyond a certain point however, execution performance is largely an engineering issue. The architectural design issues fall away leaving just implementation and optimization details. Good developed meta-level system should have fine granularity, design inherently facilitates incremental, deep and narrow implementation optimization. Far-reaching changes should be made in very precise regions of the system without affecting other, unrelated areas. The following sections highlight particular points of the considered systems with respect to these properties and form an explanation of the values in table.
3-LispThe area of reflective computing and meta-level architectures really began with Brian Smith and Jim des Rivieres's work on 3-Lisp [RS84, Smi84]. 3-Lisp is a sequential Lisp which incorporates a meta-circular interpreter and the ability to level shift. Level shifting is typically done via a reflective procedure call and allows, for example, base-level programs to shift to the meta-level and carry out some reflective computation. The computation at the meta-level is carried out by an interpreter which is logically distinct from that of the base-level. Level shifting is a uniform operation appli- cable to any level (e.g., meta-level to meta-meta-level) giving rise to a logically infinite tower of levels or interpreters. 3-Lisp explicitly reifies code, the execution environment and the current continuation giving meta-level programmers access to all the vital elements of Lisp execution. New language or system constructs are added by modifying or reimplementing the interpreter for a given level (i.e., the level's meta-level). This model captures the fundamentals of reflective computing and meta-level architectures. It is however, closely tied to the Lisp model of computing. It does not address issues specific to object-oriented computing and the framework it provides for meta-level modification and extension is relatively unsophisticated.
3-KRSCarrying on from the 3-Lisp work, Patti Maes developed 3-KRS [Mae87]. The 3-KRS language is object-based and its meta-level was one of the first to be object-based. The 3-KRS meta-level, rather than being a meta-circular interpreter, is represented by a series of metaobjects. Level shifting is uniformly integrated into the language model using standard message sending operations. That is, a level shift is just a message send to, or invocation of, a metaobject. Other than open the possibility of using standard object-oriented software development techniques, 3-KRS does not provide any additional infrastructure for managing the meta-level. Nor does it prescribe a particular architecture for the meta-level.
ClassTalkClassTalk[BC89, Coi93] is somewhat like CLOS in that it is a reification of an existing object model. ClassTalk opens structural aspects of the Smalltalk language environment. In particular, the meta- class structure. This allows users to explicitly program metaclasses and thus modify the meta-level (i.e., the class) of an object.. It also opens a number of other system operations such as method lookup and execution. This is not a fully general system however. Like CLOS, ClassTalk is a useful system within its language environment but it does not open widely the world of objects. Behaviours having to do with individual object execution are not addressed nor are operational mechanisms such as message sending.
CodACodA [McA93, McA95a] is a framework for creating, controlling and understanding concurrent computing environments. Objects in CodA conceptually has several meta-objects, which are individually replaceable. Its implementation on Smalltalk seamlessly ties CodA objects and Smalltalk objects, so that existing Smalltalk libraries can be easily extended for different environments, such as distributed computing. (For more information.) 2 Since the basic architecture is independent of a particular language, the abstractions provided are not as high-level as those found in more language-specific architectures like CLOS. For example, the architecture has no explicit notion of class. However, implementations may `borrow' concepts like classes from their host language. In the Smalltalk implementation, normal classes can be extended to define additional or redefine existing meta-components for its instances. 6 Though CodA's general architecture of fine-grained objects encourages and supports combination and reuse, the object model's configuration management mechanisms are not sufficiently powerful to handle complex situations. 9 As shown with the ConcurrentObject and DistributedObject models, CodA reifies significant portions of an object's low-level behaviour. It does not however contain an explicit model of the underlying system (e.g., the memory or execution systems). These are left to the implementation platform. 10 The main focus of this work has been on design performance. The most convincing evidence of CodA's design performance is its integration with the underlying implementation environment and the degree to which meta-level changes are isolated from the base-level code. We have shown that real applications can be quite radically altered with negligible changes to the original code. In some cases the changes required have no impact on the application semantics of the objects. This is very high performance from the design and use point of view. CodA is intended as a platform for experimentation with object behaviour and object model design, and application implementation. Its main mode of use is that developers prototype their applications and object behaviours until they find those which meet their requirements. Then, if execution performance is found lacking, the implementation of individual or groups of objects and meta- components is optimized. In general, they have found that it is not appropriate to overly optimize the architecture itself as this would limit their expressiveness and ability to reuse prior work. We must however, recognize the need for eliminating the excessive costs of using a meta-level architecture in the first instance (i.e., the prototyping phase). CodA approaches this in a number of ways. First, the overall architecture is one of individual behaviour replacement. Meta-level users only pay for that which they use. All non-reified and unmodified meta-level operations are implemented by the underlying language environment's native mechanisms. Because of this, even without explicit optimizations, CodA and Tj perform well within accept- able bounds for experimental purposes. The worst case for full reification of a complete message send/receive cycle in the Smalltalk implementation is about an order of magnitude increase in runtime. While this may seem high at first, readers are reminded that not all message exchanges in a system need be reified and even those which are, need not be fully reified. In CodA you only pay for what you reify. As a result, the performance overhead seen in actual applications will vary substantially from this.
CLOS MOPThe CLOS Metaobject Protocol (MOP) [KRB91] came about as an attempt to unify several disparate object models implemented in Lisp. The basic approach was to identify and reify those parts of the various systems which were essential to defining their behaviour. By generalizing, abstracting and finally combining these behaviours at the meta-level, a unifying framework was produced. The architecture has six kinds of objects at the meta-level; classes, slots, generic functions, methods, specializers and method combinations. This model does an excellent job of reifying, in objects, the structural nature of CLOS language. That is, the metaobjects (e.g., classes, slots, etc.) are derived directly from structures that program- mers write or define when using the base-level language. It does not however, reify its operational concepts. Operations like message sending and method lookup are represented by methods on the appropriate metaobject. The CLOS MOP's provides a strong basis for the modification of existing language constructs but does not support a framework for the addition of new concepts which are not part of the existing model. Of course, since it is an open architecture, new concepts can be added but there is no generalized infrastructure for doing this. Similarly, the MOP, while implemented with objects, is not oriented towards objects. That is, it is difficult to modify the behaviour of individual objects. Consider a user wanting to count all invocations of method foo for some object O. A first cut at this is to implement a new kind of method metaobject which counts invocations and insert this into the generic method chain for the selector foo for objects of O's class. Unfortunately, this affects all instances of O's class and its subclasses (who do not redefine foo) --- the count will not be just for O. To get around this, the counting method metaobject must also maintain a list of objects for which it is counting and check the receiver against the list for every invocation. While this solution works, it introduces overhead in unrelated objects and does not scale to handle many different behaviours for many different objects. The CLOSMOP's domain is somewhat different from that of CodA in that its aim is to unify various CLOS object models. This is accomplished by reifying at the meta-level, those components which describe differing behaviours. The reified behaviours tend to be more structural than operational as in CodA. As a side-effect of the CLOS object model, the definition of behaviour on a per-object basis does not fit naturally into the CLOSMOP design. The CLOS meta-level architecture is neither general purpose nor particularly extensible but it is quite powerful within its intended domain. 3, 4 The CLOS MOP's basic execution model is that of CLOS (i.e., method-oriented). It does not support things like object-specific method invocation reification in a scalable way. The base-level system (e.g., CLOS) does not generally support the addition of concurrency or distribution so these concepts cannot be introduced at the meta-level. 5, 6 The MOP is a fragmented reification of behaviour with no mechanism for grouping behaviours to form coherent wholes. CLOS classes are an insufficient mechanism for this as they are not independent of the base-level. 7 CLOS MOP metaobjects reify, in objects, the structural nature of CLOS (e.g., classes, methods, slots, etc.) rather than its operational aspects (e.g., sends, lookups). Operational behaviour is described in methods on the structural metaobjects. The meta-level is medium-grained. 9 The domain of the CLOS MOP is the CLOS language, not its implementation. As a result, very few of the underlying details of real CLOS systems (e.g., garbage collectors) are reified in the MOP.
ABCL/RThe notion of reflection proposed by Brian Smith and Pattie Maes, is introduced into object-oriented concurrent computation [Yon90]. The reflective architecture, later called as Individual Based Reflective Architecture, is designed and its description language ABCL/R is implemented.
ABCL/R2To formulate reflective features provided in practical reflective systems (e.g., resource management), a hybrid group reflective architecture is proposed. This architecture has notion of group shared resources, which, for example, corresponds to processor elements of parallel computers [MWY91]. Its description language ABCL/R2 is designed, and efficient implementation technique is studied [MMWY92]. Currently, pseudo-parallel version of ABCL/R2 system is available via anonymous FTP, and used for several research projects as an extensible concurrent language platform. The ABCL/R2 was one of the first systems to introduce meta-level computing for concurrent objects. In doing this it reifies the concept of computing power and allows it to be manipulated by users. ABCL/R2 uses a group-wide approach to organizing and scheduling concurrent objects. Objects within a group share computing resources and can be manipulated as a whole by controlling the group itself. Groups are meta-level concepts. The ABCL/R2 meta-level takes the interpreter approach of traditional systems like 3-Lisp. That is, the meta-level is basically a meta-circular interpreter. Shifting to the meta-level causes (logically) another interpreter to be created and invoked to interpret the meta-level to which you just shifted. Inherent in this approach is the idea of complete meta-level reification. If we wish to change just one aspect of an object's behaviour, we must, at least logically, reimplement its entire interpreter. This is in contrast to the approach taken in RbCl and Apertos (and in fact our work) where only those portions of the meta-level actually changed are reified. Since every meta-level is a complete (logical) reimplementation of the interpreter, there is no need for a framework to organize the meta-level. The organization can be left up to the interpreter's implementor. This discourages object behaviour description reuse by making it difficult to integrate unrelated or third-party behaviours. The ABCL/R2 meta-level architecture is one of the few which deals with concurrency. It is quite open but does not explicitly abstract many object behaviours. Since the ABCL language is quite simple, this is not a too much of a problem. While it is in theory extendible, the architecture has no framework or infrastructure for extension. Creating new behaviour for an object implies writing code rather than changing parameters or plugging-in components as seen in other architectures. There are no facilities for configuring or structuring the meta-level itself. 1, 2 The ABCL/R2 meta-level is basically an interpreter whose design is left up to the implementor. The architecture itself says little about its structure or the abstractions it contains. 3, 4 ABCL/R2 objects are generally single threaded and concurrent. For implementation efficiency the system also provides lightweight objects which are essentially passive and stateless. There are no other facilities for extending this set of computational domains. 5, 6 Since the entire meta-level of an ABCL/R2 object is captured in its metaobject, the metaobject description implicitly encapsulates an object model. Metaobjects and thus object models are effectively interpreters, implemented as code and so do not readily support combination and configuration. 7, 8 The ABCL/R2 meta-level is made up of only a few objects. The internal structure of these objects is not explicitly set out by the architecture. Without this, the architecture cannot properly support scalability or reuse. 9 The group model of ABCL/R2 allows the description of some low-level execution behaviours such as scheduling.
ABCL/R3Computational reflection is a potential way to optimize high-performance applications especially for parallel computers. To realize this, we re-design a reflective concurrent object-oriented language ABCL/R3 so that various features of parallel computers can be managed via reflection MMY93, MMY94]. Also, the compilation framework for efficient execution is considered based on partial evaluation, which uses the ABCL/f compiler as a back-end compiler. [MMAY95].
AL-1/DAL-1/D [OIT92, OI94] is an application of AL-1's Multi-Model Reflection Framework (MMRF) [IO91, Ish92] to distributed systems. Within this architecture, an object's meta-level is partitioned into a fixed set of six models or views of base-level object behaviour. Below we summarize the parts of base-level object behaviour described within each of these models. Operation Describes the operational semantics related to the programming language. Concepts such as message sending, state storage and stack manipulation are detailed here. Resource Represents shared system resources such as CPU and memory. Statistics Maintains various statistics for various aspects of object behaviour (e.g., CPU time, memory usage, blocking, etc.). Distributed Environment (DE) Models the distributed system in terms of topology, networks, CPU and communications channel loadings, etc. Also maintains a global name server for object-to-location resolution. Migration Defines how an object moves from one host to another and what objects are moved with it. System Specifies the primitive system operations on which the entire system is built. Overall this partitioning appears to reflect implementation issues rather than design issues. This is useful but ultimately leads to problems and confusion. Behaviours one might expect to see together, are split over meta-models (e.g., object monitoring and migration behaviour). The partitioning is also relatively coarse-grained. One model, Operation, describes almost all of an object's execution behaviour. This is closely tied to the base-level language and does not serve as a sound basis for behaviour reuse or combination. The logical weight of the models is not balanced. While the Operation model defines a great deal of behaviour, the Statistics model is just a storage area for monitored values. These are grossly different in complexity, scope and significance. While it may be convenient to have system statistics grouped in one place, this would not seem to be sufficient motivation for an entire model. The details of moving an object from one place to another are split over several models (DE and Migration) rather than being one logical unit. The Migration model is billed as an OS abstraction but it includes specification of things like object attachment and slot inclusion which would seem to be higher level issues. The DE model, in addition to specifying argument passing strategies (e.g., call-by-move), deals with completely unrelated issues such as object name/location mapping and processor loading. AL-1/D is one of the few architectures which deals with distribution. It focuses on a set of meta-level concepts directly related to distribution requirements. Parts of the AL-1/D system can be mapped onto those of CodA and Tj as shown in Table. AL-1/D CodA/Tj Operation Standard CodA meta-components Migration Tj Marshaling and Migration System Smalltalk DE+Resource Tj infrastructure objects (topology, space, ...) Statistics Tj monitoring (largely meta-meta-level) Table : Mapping from AL-1/D to CodA.As noted early and show in Table, the meta-level is somewhat unbalanced. The Operation model is equivalent to most of the basic CodA meta-components but the architecture contains no facilities for intra-model structuring --- The behaviour defined and structured in CodA is unstructured in AL-1/D. Furthermore, the AL-1/D meta-model scheme does not extend to support the grouping of arbitrary metaobjects into manipulable wholes (i.e., object models). 3, 4 The portion of the meta-level which deals with object execution (i.e., the Operation model) is explicitly partitioned in AL-1/D. New computational domains are implemented by providing new Operation models. The models themselves however, contain no infrastructure to support this modification. 5, 6 The Operation model embodies entire and complete object model descriptions. The architecture does not support sub-models, model intersection, combination or other manipulation. Nor does it support the grouping of specific meta-models to form a coherent whole. 7, 8 The AL-1/D meta-level is decomposed into objects but the architecture says nothing in particular about their granularity or relation to one another. Reuse is provided via the meta-model concept but the models provided are of varying granularity and complexity. 10 AL-1/D's remote messaging is quite fast. It introduces just 30% overhead to standard Unix stream data transfer. CodA and Tj implemented in Smalltalk cannot match this performance because they use a very general object marshaling scheme which trades runtime efficiency for flexibility. As outlined above, programmers can easily modify the marshaling technique used for the system, instances of a class, a particular instance or a particular use of an instance to regain the efficiency but at the cost of flexibility. To date, our experiments with real applications have not indicated that this is necessary.
RbClRbCl is a reflective object-oriented concurrent language [IMY92]. It is designed so that any run-time routine of the language can be replaced with RbCl objects---what we call no kernel in the language. The RbCl system has system object tables, which registers run-time routines, which is written in C++ at the beginning. The table can be modified, and user defined RbCl objects can be executed as run-time routines via a novel feature linguistic symbiosis. RbCl [Ich93] is a reflective concurrent language system for distributed environments in which the meta-level is factored into objects. Metaobjects with different implementations (in different languages) can be plugged in and used as long as they understand the calling conventions. This is demonstrated with the free substitution of RbCl and C++ objects. Unfortunately, very little is said about what objects exist at the meta-level and how they interact. The authors claim that RbCl is kernel-less. The essence of this claim is that every function point in the description of object behaviour (i.e., the meta-level) can be reimplemented by the user. As such, there is no fixed kernel. This is a nice idea as it gives the user complete power over the system but with no framework or infrastructure organizing the meta-level, this power is hard to manage. RbCl is also set apart from other systems in that it reifies many of the low-level system operations like scheduling, interprocessor messaging device interfaces, etc. Though there could be more at the higher end, it has a reasonable span from system- to object-level behaviour descriptions. RbCl is another architecture with support for concurrent objects. The RbCl approach differs from ABCL/R2 and is similar to CodA in that it does not use the interpreter model of the meta-level. Rather, the meta-level is looked upon as a collection of objects which provide services to the base-level objects. Object behaviour is modified by replacing the objects at the meta-level on an individual basis. Since the meta-level objects are also objects having meta-levels, this can be seen as pushing the underlying machine further away from the base-level objects only in the areas of interest (i.e., those reified). CodA and RbCl differ in the level of infrastructure they support and their approach to meta-level decomposition. 1, 2 The programmer's interface for RbCl is well-defined in the sense that there are definitions for many (most) object behaviours. It is not well-defined in the sense that it is not clearly set out in the literature. Overall many of the interfaces are at quite a low-level and without higher-level abstractions to ease their use. 3, 4 The architecture is a reification of a specific object model, namely single threaded concurrent objects. Since the reification is at such a low level, there is some support for the implemen- tation of other computational domains. However, this support is not explicit. 5, 6 There is no notion of overall object model encapsulation or behaviour grouping. 10 In [Ich93] the runtime overhead introduced by modifying two system behaviours with RbCl code is discussed. It is shown that while the normal system takes 9.8ms to run a particular test, the modified version takes 600ms. A factor of 61 slower. While the nature of the changes is not given in detail, this is significantly more than we have seen in any of our experiments with remote messaging reification. Interestingly however, RbCl allows the user to replace the RbCl-based meta-level modifications with C++ based code and achieve a speed-up over the original unmodified meta- level. This same capability is available in Tj through specialization of an object's Marshaling component or the specification of optimized marshaling descriptors.
ApertosApertos [YTT89, Yok92] was the first object-oriented operating system developed using reflection, meta-objects and object/meta-object separation. It offers a scheme of ``extensible hooks'' through reflectors to cater for dynamic extension. This means that the set of possible extensions is limited by the number of hooks that the designers have included. The reflector class hierarchy only supports a single MOP which, though it is expandable through compile-time inheritance, only supports Actor-like, single-threaded, active objects as the system's executable entity. However, dynamic extensibility is not supported in the current release as neither alteration of reflector classes nor addition to the hierarchy of reflector classes is allowed at runtime. The Apertos meta-level is reified in to metaobjects which are grouped into metaspaces. Metaspaces are structural concepts which have no real meaning at runtime. They can be arranged in a hierarchy similar to classes and are used to describe relatively complete sets of behaviour. An Apertos object's behaviour is defined by the metaspace(s) in which it resides. To change its behaviour, we move if to a new metaspace. Any number of objects can reside in the same metaspace at the same time. Though Apertos does not reify many higher-level object behaviour concepts such as message handling (e.g., lookup) and state storage format (e.g., slot structure), in later chapters we will see that its fundamental architecture has much in common with our work. 1, 2 Though not explicitly set out in the current literature, Apertos' programmer's interface is reasonably well-defined. This is a consequence of its role as an operating system which is used by various client programs. Though its reified structures closely match those of its domain, they are not particularly high-level or abstract. 3, 4 Apertos is an object-oriented operating system, not an object operating system. As such, it is not particularly concerned with the description of object behaviours at a level higher than its execution and resource requirements. It does not define how object behaviour is described or structured. 5, 6 The Apertos architecture supports a hierarchy of metaspaces which are used to encapsulate groups of meta-level objects. Metaspaces are used only as structuring concepts and do not play any role at runtime. As such, they are somewhat limited in their support for behaviour combination and configuration. 7, 8 Though Apertos' domain (e.g, operating systems) is different from most of the other systems, its architecture does present a reasonably fine-grained reification of the behaviours it supports. The nature of the decomposition and meta-level framework explicitly supports reuse and combination. 9 Low-level execution details are the domain of Apertos and so are quite well treated.
OpenC++OpenC++ [Chi95, Chi96] is a static or compile-time meta-level architecture which allows users to modify the implementation of their objects. OpenC++ metaobjects represent C++ language elements and are produced when an OpenC++ program is parsed. Which metaobjects are created is controlled by meta-level directives or annotations made by the user. The language system has a small framework for annotating code to allow generalized annotations to be used. Once the code is parsed, the metaobjects, which essentially form a parse tree, are asked to produce code which implements the behaviour they describe. So, by using annotations to control metaobject creation, users can control the implementation of language constructs. This system is interesting but is not fundamentally different from current object-oriented compiler technology seen in languages like Smalltalk. Having said that, we find we would like a similar system for optimizing out many of the runtime meta-level operations in our system.
ActalkActalk [Bri89] is a meta-level architecture implemented in Smalltalk. It introduces actor-based concurrent objects to an otherwise passive object environment using meta-level manipulation. Its main goal is to provide a testbed for describing object behaviours in areas relating primarily to concurrent execution and message passing. The system itself has become more and more component-based at the meta-level, but the basic architecture has remained somewhat monolithic and code-based. There are however, many object behaviours implemented in Actalk (e.g., intra-object synchronization constraints) which we look forward to implementing in CodA.
RKL1RKL1 is a reflective version of KL1, which is a parallel logic programming language developed at ICOT. The notable feature of RKL1 is simplicity of its reflective architecture; programmers can modify only around the invocation of the body part of each clause. This simplicity helps us to easily develop a compiler that can generate programs that is embedded meta-level code, and runs efficiently. In fact, some example programs with meta-level descriptions exhibit good performance on multiple workstations connected via Ethernet. [TT94, TT95]
MPC++MPC++ is a metalevel-architecture-based C++ compiler system. Researchers in RWCP(Real World Computing Partnership), in cooperation with our group, is developing this system with the aim of providing practical parallel C++ systems using its meta-level architecture.[TIS+96]
Tiger, PigletTigger is an object-support operating system framework [ZC94, ZC96] which provides typical operating system services such as persistence and scheduling using objects as the basic units of computation. In addition to these general services Tiger provide real-time support by means of realtime scheduling of threads as well as real-time synchronization protocols. A general feature of this framework is its ability to be tailored to the specific needs of different target environments. Piglet, the metalevel architecture of Tigger, allows application-defined objects dynamically change the way in which they are executed. This allows applications to adapt operating system behaviour to even unanticipated requirements during run-time. Piglet uses a metalevel hierarchy of different metaobjects allowing different aspects of an object's run-time representation to be changed. The metalevel hierarchy consists of three layers. An object meta interface (OMI) on the first metalevel acts a link between the application and the underlying metaobjects which in turn use a generic core element to communicate with each other. Individual metaobjects residing on the second metalevel control the separate components of an underlying Tigger instantiation. These Tigger components make up the third metalevel. The basic unit of computation are objects. To control the way these objects are executed, a concept of called metaobjects [Mae87] was introduced. Since these metaobjects know about the internal organization and structure of application-defined objects, they are able to control certain aspects of the execution of those baselevel objects. The entirety of all metaobjects is called a metaspace. Piglet structures this metalevel into three groups of entities which represent the nature of the underlying instantiation of a Tigger.
1. MetanucleiTigger is a collection of subframeworks responsible for implementing various algorithms dealing with single aspects such as process management. Towards applications, the contents of each of these subframe- works are represented by metanuclei. Metanuclei are a means for grouping all the mechanisms and policies regarding a certain functionality that a particular instantiation of Tigger supports. The real-time metanucleus contains a metaregion responsible for scheduling the threads associated with the different active object models (different models for active objects can be identified depending on when a thread is associated with a particular method of the object). These schedulers implement different real-time scheduling algorithms such as priority-based scheduling (prio), Least Slack Time First (lstf), Rate-Monotonic (rm) and Earliest Deadline First (edf). The persistence metanucleus contains a metaregion providing pagers supporting different object sizes. These pagers are responsible for transferring object states to and from secondary storage and all employ different algorithms for doing so depending on the object size at which they are targeted. To be most efficient when dealing with small object sizes, the relevant meta- object groups small objects onto a memory page before storing this page on disk. In contrast to this, the metaobject aimed at supporting large object sizes may avail of certain features of the storage subsystem such as burst transfer.
2. MetaregionsEach metanucleus consists of a set of metaregions. A metaregion in turn consists of a (possibly empty) set of metaobjects implementing the same functionality and expose the same interface to application-defined objects. The difference between the individual metaobjects forming a metaregion is their behavior when providing this functionality. In addition to the individual metaobjects, each metaregion has a controller which allows metaobjects to be attached to objects and allows a metaregion to be queried about its contents and the capabilities of the individual metaobjects. This part of the interface is used by objects to control which metaobject of the metaregion is controlling a certain aspect of its behavior. Besides this controller interface, each metaregion defines a common interface for the metaobjects this metaregion contains. This common interface part of the metaobjects is then used by applications to change the way in which they are executed. Compared to traditional approaches to organizing metaobjects such as the multi-model reflection framework [OIT93] or Apertos [Yok93], metaregions have two distinct advantages. First of all, a metaregion can capture a common part of the metaobjects that it contains. The second advantage is that metaregions introduce a statically typed meta-level. One of the advantages of this static typing is that the source code can be compiled into machine code instead of being interpreted at run-time. Although not all binding decisions can be made at compile-time, more efficient mechanisms such as virtual function tables can be employed which result in a faster overall execution of the program compared to just interpreting it at run-time. A detailed discussion of metaregions can be found in [ZC95].
3. MetaobjectsMetaobjects implement the non-algorithmic behavior of objects, i.e. they control the way in which these objects are executed. The responsibilities of the metaobjects are twofold: on one side they are in charge of supplying the implementation of the MOP representing the metaregion as explained above; on the other side they intercept individual method calls to the baseobjects transparently. This allows the functionality associated with the metaobjects to actually take place. In comparation with traditional operating system frameworks such as Choices [ClJ+91, CIMR93] and reflective systems like Apertos [Yok93, LYI95], the architecture discussed above offer a rich choice of mechanisms to tailor the behavior of an operating system. By structuring the metalevel into metanuclei, metaregions and metaobjects, Piglet provides a means for the application programmer to select the functionality the current environment requires, thereby catering for the ability to change this functionality should this become necessary. For implementation of this architecture Open C++ preprocessor [Chi96] was used.
SummaryEach of these systems is a powerful tool within a particular domain. By in large, they were created as reifications of specific, pre-existing systems in an effort to open their implementation and facilitate user input. The way in which this has been done varies widely from system to system. The approaches used are typically not compatible with one another and the object descriptions from one architecture do not easily map onto a different architecture. In our work we strive to unify aspects of various existing systems and enable users to create and use object models from various domains within the same environment.
BibliographyThe need of customization[Kic92] G. Kiczales. Towards a New Model of Abstraction in Software Engineering. In Proceedings of the IMSA'92 Workshop on Reflection and Meta-level Architectures, 1992. Abstract, copyright and paper [KL93] G. Kiczales and J. Lamping. Operating Systems: Why Object-Oriented?. Proceedings of the Third International Workshop on Object-Orientation in Operating Systems, pages 25--30, Asheville, North Carolina, December 1993. IEEE Compuer Society Press. Abstract, copyright and paper [KAR+93] G. Kiczales, J.M. Ashley, L. Rodriguez, A. Vahdat, and D.G. Bobrow. Metaobject protocols: Why we want them and what else they can do. Object-Oriented Programming: The CLOS Perspective, pages 101--118. The MIT Press, Cambridge, MA, 1993. Abstract, copyright and paper [MKL94] A. Mendhekar, G. Kiczales and J. Lamping. Compilation Strategies as Objects. In Proceedings of the 1994 OOPSLA Workshop on Object-Oriented Compilation -- What are the Objects? 1994. Abstract, copyright and paper
Theory of reflection[MF93] A. Mendhekar and D.P. Friedman. Towards a Theory of Reflective Programming Languages. In Proceedings of the 1993 OOPSLA Workshop on Reflection and Meta-level Architectures, 1993. Abstract, copyright and paper
3-Lisp[RS84] J. des Rivieres and B.C. Smith. The implementation of procedurally reflective languages. In Conference Record of the 1984 ACM Symposium on Lisp and Functional Programming, 1984. [Smi84] B.C. Smith. Reflection and semantics in lisp. In Proceedings of ACM POPL '84, pages 23--35, 1984.
3-KRS[Mae87] P. Maes. Concepts and experiments in computational reflection. In Proceedings of OOPSLA'87, pages 147--155, October 1987. Orlando. http://www.informatik.uni-trier.de/~ley/db/conf/oopsla/oopsla87.html#Maes87
Choices[ClJ+91] R.H. Campbell, N. Islam, R. Johnson, P. Kougiouris, and P. Madany. Choices, Frameworks and Refinement. In Object-Orientation in Operating Systems, pages 9--15. IEEE Computer Society Press, 1991. [CIMR93] R. Campbell, N. Islam, P. Madany, and D. Raila. Designing and Implementing Choices: An Object-Oriented System in C++. Communications of the ACM, 36(9):117--125, 1993.
ClassTalk[BC89] J.P. Briot and P. Cointe. Programming with explicit metaclasses in Smalltalk-80. In Proceedings of OOPSLA '89, pages 419--431, October 1989. [Coi93] P. Cointe. CLOS and Smalltalk: A comparison. Object-oriented programming: The CLOS perspectives, pages 215--250. MIT Press, 1993.
Department of Information Science, The University of Tokyo, Yonezawa Lab.
|