To differentiate aspects from the program they act upon, the latter is called the base program. An aspect is composed of two parts. The first, the pointcut, defines when execution of the aspect should be triggered. A pointcut acts as a join point designators. A join point is a point in the execution flow where an aspect can be executed. The second part, the advice, specifies the behavior of the aspect when it is executed. Pointcut and advice in Arachne are provided as extensions of the C programming language. Finally, a tool, a weaver, ties a set of aspects to a base program. Arachne aspect language syntax is summarized below in BNF:

 

aspect-library

::=

aspect | aspect aspect-library+ | C-compound-instruction aspect-library+ | require-directive aspect-library+

aspect

::=

aspect-name "[:" pointcut-advice":]"

pointcut-advice

::=

function-call "[:" pointcut-advice ":]" | function-call "[:" advice":]" | global-var-access "[:" advice ":]"

function-call

::=

type identifier-or-star "("params ")" | type identifier-or-star "()" params ::= type identifier | params "," params

global-var-access

::=

global-var-read | global-var-write

global-var-read

::=

type identifier-or-star

global-var-write

::=

type identifier-or-star "=" identifier

advice

::=

C-compound-instruction

identifier-or-star

::=

identifier | "*"

aspect-name

::=

identifier

require-directive

::=

"require" identifier "as" type

 

The definition of each aspect consists of its name and a nested sequence composing the pointcut that identifies the affected join point. Each element in the pointcut sequence but the last must describe a function call (function-call). Thus together, these elements describe a sequence of direct nested function calls. Execution of the advice will be triggered if this sequence of function calls occurs in the execution of the base program and if the last element in the sequence composing the pointcut can be matched. This element can either be a function call or a global variable access (global-var-access). In the latter case, the last element will be considered as matching the base program execution program if the base program tries to access that particular global variable. The sequence of pointcut predicates ends with an advice, which is implemented as an ordinary C statement.

 

The advice associated with an aspect is executed when the current execution context matches that described by the pointcut. The execution of the advice replaces execution of the join point represented by the last element in the sequence composing the pointcut. Advice runs in the global address space of the base program and thus can refer its global variables.

 

When the pointcut implies that the advice replaces a function call, the advice can also refer to the arguments of this call, via the parameter names declared in the last element of the sequence composing the pointcut. The advice can furthermore invoke the original body of the function using the implicitly generated function pointer continue. The returned value of the advice is returned to the base program as the return value of the function call.

 

When the pointcut implies that the advice replaces a write access to a global variable, the last element in the sequence composing the pointcut represents an assignment (global-var-write). This last element includes both the name of the affected variable and a new variable representing the value of the righthand-side expression. This new variable can also be referred to by the advice, which is responsible for performing the assignment, if desired. The advice has no return value. If necessary, the aspect system will automatically use the value contained in the written global variable as the value returned by the replaced assignment.

 

When the pointcut implies that the advice replaces a read access to a global variable, the last element in the sequence composing the pointcut represents the name of that global variable (global-var-read). This advice can use this name to read the value of the variable. The advice is responsible for returning a value that the aspect system will give to the base program as the value contained in the global variable it expected to access.

 

In addition the aspect language contains two features to ease interoperation with the C language. First, standard C code (C-compound-instruction) can be interleaved between aspect declarations. Second, an advice can use the functions and global variables contained in the base program. Such dependencies must be explicitly declared before the advice code using the keyword: require. A require declaration has the form require as require <symbol> as <type>, where symbol is the name of the imported function or global variable and type indicates to its type. require frees aspect programmers from the obligation of explicitly retrieving symbol addresses at weaving time.

 

 

Below is a simple example we developed for squid. The first line uses the keyword require to make the function httpHeaderGetByName provided by the cache available to the advice. Next, a C helper function miss is defined. Finally an aspect MissTrigger is declared. The poincut associated with this aspect indicates that MissTrigger’s advice will replace the execution of any invocation of the function clientProcessMiss within the cache. The advice of the aspect calls the C function miss before using the continue keyword to execute the clientProcessMiss function defined by the cache.

 

require httpHeaderGetByName as char * (*)(Headers headers, char* name);

 

void miss(char * uri, HttpHeader header) {

/* Do many useful things here using httpHeaderGetByName */

return ;

}

 

MissTrigger [:

void clientProcessMiss(clientHttpRequest * http) [:

{

miss(http->uri,http->request->header); continue(http);

}

:]

:]