• Keine Ergebnisse gefunden

Chapter 1 Overview

2.2 Binding of Join Points

Binding of Join Points

In addition to the control flow instructions, other parts of Java bytecode refer to instructions by their offset. Most importantly, this is the exception handler map. Similar to the try-catch structure in the source code, this map specifies the range of bytecode instructions—in terms of a start and an end offset—which may cause an exception and the offset of the instruction where to continue execution in the case of an exception—i.e., thecatch block.

Binding of Join Points

12 //...

13 if(<cflow−test>)

14 QueryInjectionChecker.before 0(sql);

15 connection.execQuery(sql);

16 }

17

18 voidservice2(String sql){

19 //...

20 if(<cflow−test>)

21 QueryInjectionChecker.before 0(sql);

22 connection.execQuery(sql);

23 }

24 }

Listing 2.6: Compilation and weaving result of AspectJ.

All AO languages investigated in this thesis (presented in detail in Sec-tion 3.1) allow to write advice in terms of statements from the base language.

These advice are compiled into methods—henceforth calledadvice methods—

in the bytecode. For each aspect, the compiler generates a class—calledaspect class from now on—that holds all its advice methods. For instance, the as-pect in Listing 2.2, is compiled to the class in lines 1–6 in Listing 2.6; the advice in lines 6–9, Listing 2.2, is compiled to the method before 0 in lines 2–5 in Listing 2.6.

Examples of residual dispatch are shown in lines 13–14 and 20–21 in Listing 2.6. For advice execution, the weaver generates a call to the advice method in the residual dispatch; if context values have to be reified for use by the advice, these values are passed to the advice method as arguments (lines 14 and 21).

In [KM05] pointcuts are presented as the natural successors of method calls and declarations which are well-known mechanisms for binding meaning to points in the execution of a program. In fact, they bear a conceptual resemblance to virtual methods in object-oriented languages in the sense that both are late-bound to meaning.

Whenever a virtual method is called, some predicate is evaluated. The expressiveness ranges from a predicate on the dynamic type of the receiver in

“traditional” method dispatch [ES90] to a predicate on the types of receiver and arguments in multi-dispatch [CLCM00], or, more radically, to an arbi-trary predicate on dynamic values in predicate dispatch [Mil04]. Similarly, when a join point occurs, pointcuts are, at least conceptually, evaluated to determine which meaning to bind to the join point: the advice of matching pointcuts are executed; if no pointcut matches, the join point is executed

un-Binding of Join Points

advised. This conceptual view is reflected in formalisms for object-oriented and aspect-oriented languages [CLW03, KHH+01, MKD03] and often is called the “direct semantics” of AOP in informal discussions.

The dispatch is preserved as first-class concept in the intermediate code of object-oriented languages such as Java [GJSB00], Smalltalk [Sma], and Self [US87]. In these languages, the compiler does not statically undertake any dispatching steps for method calls, it merely determines the dispatch strat-egy. In Java, e.g., this may be a dispatch using a virtual method dispatch table [ES90] (represented by the invokevirtual bytecode instruction) or, for interface methods, searching the method in the complete super type hierar-chy [ACF+01] (represented by invokeinterface). However, all method calls remain virtual after compilation, i.e., their binding is per default determined by evaluating run-time predicate functions. It is the virtual machine that dynamically applies optimizations and decides to treat some of the method calls as non-virtual ones.

In contrast, despite the conceptual similarity to virtual methods, the “di-rect semantics” of AOP is not reflected in most current AO language imple-mentations which share the conceptual work flow of first performing partial evaluation and second weaving residual dispatch [HH04, DKM02, MKD02].

During the weaving phase, aspect-oriented concepts, which are expressed by special language constructs in the source code, drive code generation and transformations in the compiler. An implication of this approach is that code originally modularized in aspects is merged with modules of the base pro-gram. Furthermore, there is no explicit representation of residual dispatch.

There are several problems with this approach.

• It may be desirable to add an aspect to an application which is currently running. Consider the example of a client-server-application from the previous section. If the vulnerability to SQL command injections is discovered when the application is already in productive use, it is ad-vantageous if the aspect can be added to the running system without the need to stop the application, re-compile it and start the new version.

In an approach that binds join points early do advice, dynamic aspect deployment is expensive since the manipulation of application byte-code and its subsequent re-installation into the execution environment are time-consuming. Approaches exhibiting fast dynamic deployment behavior by preparing join point shadows with hooks and wrappers usually suffer from the footprint of the required infrastructure [Hau06]

which degrades performance of other operations.

Virtual Join Points

• The continuity property of incremental compilation is weakened: modi-fyingone aspect potentially requires re-weaving inmultiple other mod-ules [RDHN06].

• The fact that aspect-oriented concepts become implicit instead of stay-ing first-class in the generated bytecode hinders optimizations by the virtual machine.

• Dynamic class loading is poorly supported. It is, for example, possi-ble to statically optimize a cflow pointcut to the best possible degree using sophisticated analyses [ACH+05b]. However, when classes are dynamically loaded which have not been available during static analy-sis the optimizations fail and the aspect may not be executed correctly anymore.

• The weaving approach followed by common AO language implementa-tions is rather complex and slow: when weaving residual dispatch at a join point shadow, care must be taken of the control flow of the method containing the join point shadow, i.e., the weaver must update the method’s instructions. Furthermore, join point shadows for pointcuts that match field accesses or method calls are generally spread all over the program and multiple join point shadows exist for the same accessed member. Hence, the same weaving action must be executed repeatedly at each of these shadows. As reported in [HH04] and shown in the evaluation in Section 2.5.2, even when no aspect is present in the code, the time spent for compiling an application with the AspectJ compiler increases considerably, compared to the time spent by a conventional compiler. For a simple aspect that logs the application’s method calls the compile-time increases to more than 400% [HH04]. Poor compile time performance impacts the efficiency of the development process since it slows-down the “compile-test-debug” cycle [SDR08].