• Keine Ergebnisse gefunden

Chapter 1 Overview

3.5 Execution Environments

To evaluate the appropriateness of FIAL to act as a framework for imple-menting execution environments for AO languages, different instantiations of FIAL applying different weaving techniques have been developed.

FIAL requires that each entity’s semantics is implemented in a method of the entity’s class, which facilitates a default code generation strategy for each kind of meta-entity from LIAM. This default code executes the entity’s semantics by invoking the method. This way, the concept represented by an entity is implemented in isolation from other concepts.

Treating each concept separately, makes it easy to add new concepts and precisely define their semantics, namely by providing a programmatic speci-fication that can be executed and tested. This strategy furthermore supports the generation of optimized code for those entities specifically supported by an execution environment as discussed further in Chapter 4.

The default implementation of the LIAM entities is based on implement-ing their meanimplement-ings as pure Java methods. AContextentity, for example, has a

Execution Environments

method which returns the corresponding context value and aDynamicProperty has a method that returns eithertrueorfalse. Below, these methods are gen-erally referred to as “perform”, however, they are called differently for each kinds of entity, e.g., isSatisfiedfor DynamicPropertys or getValue for Contexts.

FIAL employs a factory for the creation of LIAM entities. Hence, the execution environments presented here can provide an appropriate imple-mentation of the entities whereby the “perform” is implemented specially for those entities that have to interact with the execution environment.

For entities which require context values to perform their semantics, those values have to be passed as arguments to the “perform” method. Since the entities are objects and the above described methods are virtual, each LIAM entity has a numerical ID and FIAL provides a registry that facilitates to retrieve an entity by its ID. Thus, the code generated for executing an entity, is as follows:

1. Push the ID on the operand stack as a constant.

2. This constant is passed to FIAL’s registry which returns the LIAM entity object.

3. For eachContextrequired by this entity, generate code according to this enumeration.

4. Call the entity’s “perform” method.

3.5.1 Envelope-Based Reference Implementation

The so-called Envelope-based Reference ImplementatioN (ERIN) has been implemented as an instantiation of FIAL. It supports all features of FIAL and performs, as the name suggests, envelope-based weaving. It is an ad-vanced version of the prototype performing runtime weaving with envelopes, presented in Section 2.5.2, realized as a Java 6 agent.

A Java agent contains a class with a method named premain. This class is invoked by the virtual machine after it has finished its own initialization.

When this method is invoked on the ERIN agent, it starts the initialization of FIAL and installs a class loading interceptor. The last action of thepremain method is to notify FIAL that the application is about to start.

The agent uses the bytecode instrumentation package to intercept class loading: When a class is loaded by the virtual machine, the agent pro-cesses the class data, brings the bytecode in the envelope-style, generates JoinPointShadow objects and stores meta-information about the class to be

Execution Environments

used for weaving. FIAL is notified of these JoinPointShadows. In ERIN the JoinPointShadow objects correspond to envelope methods.

When the call-back for join point shadow code re-generation is invoked by FIAL ERIN re-generates the code of the envelope methods related to the affected join point shadows. Subsequently, the JVM’s Class Redefinition facility is used to replace the bytecode of those classes containing envelope methods that have been changed.

Most of the default LIAM entity implementations are independent from the concrete FIAL instance. However, the primitive context values like the receiver or thethisobject depend on the specific weaving strategy. As already discussed in Section 2.4, in envelope-based weaving the this object is not in the local context of the join point shadow. Thus, ERIN provides theContext implementations representing these primitive values which are implemented by means of the JVMTI as presented in Section 2.4.

Code is generated for envelopes according to the weaving directives pro-vided by the corresponding JoinPointShadow object. ERIN, first, generates code that evaluates the dispatch function and stores the evaluation’s result in a local variable. Second, code for each bound action is generated sepa-rately according to the default code generation strategy. In front of each code block for executing a bound action, a branch is placed which tests the result of the dispatch function and skips the bound action if it is not applicable.

The dispatch function’s result is encoded as a bit vector where the bit at index i determines whether theith bound action is to be executed (bit is 1) or not (bit is 0).

The applicable BoundActions and their execution order are provided for a JoinPointShadow in terms of a structure of ActionOrderElements. Figure 3.14 shows (a) an action order structure and (b) how it is mapped onto a sequence of bytecode instructions. The dashed arrows in sub figure (b) represent the control flow of the branch that test for the bound action’s applicability in the dispatch function’s result.

The solid arrows illustrate the control flow that has to happen when an around adviceproceeds. In order to support that, the code for bound actions representingaround actions is inlined into the envelope instead of generating code for invoking the advice method; i.e., the method’s implementation is copied into the envelope. ERIN requires that the proceed special form is compiled into a method call which can be identified by naming conventions.

Such instructions are replaced by a “jump to subroutine” instruction (jsr) that jumps to the first bound action from the next advice order element. When the last of its bound actions has been executed, the execution is continued just behind the jsrinstruction representing proceed.

Execution Environments

before1 before2 around

<leave shadow>

after1 after2 method

branch if not applicable

jump whenaroundadvice finished control flow ofproceed

control flow enter / exit of join point shadow

Figure 3.14: Instruction sequence generated for ordered BoundActions.

The inlined code is further modified in two ways. First, local variables are re-numbered to avoid interference with local variables of the envelope method or other inlined around advice. Second, return instructions are replaced by instructions that jump behind the inlined advice method’s code to ensure that the execution continues with the code of the next bound action after the inlined advice method; this is shown as dotted arrows in Figure 3.14.

Inlining of around advice cannot be performed when the proceed occurs in an anonymous nested type in thearoundadvice as observed in [ACH+05b, HH04]. They also describe an implementation based on closures that can be used in all situations. A similar solution is currently not implemented in ERIN.

3.5.2 Static Weaver

Another instantiation of FIAL has been developed in this thesis to show its appropriateness also in settings of static weaving. The weaving strategy pursued here is similar to that of the standard AspectJ compilers: join point shadows occur in the application code and are not relocated to envelopes.

However, still the code generated for the different entities follows the default code generation strategy.

A main class beginning from which all referenced classes are determined recursively is passed to this static weaver. All determined classes are pro-cessed and JoinPointShadow objects are generated which are passed to FIAL.

After all classes have been processed,the importer call-back is triggered, thus aspects may get defined and deployed. Thereby, FIAL attachesBoundActions to the JoinPointShadows. After the importer call-back has been executed, all affected join point shadows are modified. Then all classes that have been

AO Language Design and Implementation with FIAL

loaded and processed in the first place are written out again. Those instruc-tions that make-up join point shadows are not written unchanged, but code is generated for them according to their JoinPointShadow object, everything else is copied verbatim.

This execution environment does not support dynamic aspect deploy-ment. Thus the call-back for code re-generation is to be implemented.

3.6 AO Language Design and Implementation