Think v4 (a.k.a. Nuptse) Programmer`s Manual

Think v4 (a.k.a. Nuptse) Programmer`s Manual
Think v4 (a.k.a. Nuptse)
Programmer’s Manual
July 1, 2008
Revision History
revison
1.0
date
XXX
description
initial version
author
Olivier Lobry (Orange Labs)
1
Contents
1
Introduction
4
2
Basic programming
2.1 Basic concepts . . . . . . . . . . . . . . . . .
2.2 The Interface Description Language (IDL) . . .
2.3 The Architecture Description Language (ADL)
2.3.1 Introduction . . . . . . . . . . . . . . .
2.3.2 Keywords . . . . . . . . . . . . . . . .
2.3.2.1 component . . . . . . . . . .
2.3.2.2 provides . . . . . . . . . . .
2.3.2.3 requires . . . . . . . . . . .
2.3.2.4 attribute . . . . . . . . . . .
2.3.2.5 assigns . . . . . . . . . . . .
2.3.2.6 contains . . . . . . . . . . .
2.3.2.7 singleton . . . . . . . . . . .
2.3.2.8 content . . . . . . . . . . . .
2.3.3 Deprecated Keywords and constructions
2.4 The NuptC Component Programming Language
2.4.1 Introduction . . . . . . . . . . . . . . .
2.4.2 NuptC annotations . . . . . . . . . . .
2.4.2.1 ServerMethod . . . . . . . .
2.4.2.2 DefaultServerMethods . . . .
2.4.2.3 ServerInterfacePrefix . . . .
2.4.2.4 ClientMethod . . . . . . . .
2.4.2.5 DefaultClientMethods . . . .
2.4.2.6 ClientInterfacePrefix . . . . .
2.4.2.7 Attribute . . . . . . . . . . .
2.4.2.8 DefaultAttributes . . . . . .
2.4.2.9 AttributesPrefix . . . . . . .
2.4.2.10 PrivateData . . . . . . . . .
2.4.2.11 PrivateMethod . . . . . . . .
2.4.2.12 KeepName . . . . . . . . . .
2.4.2.13 IgnoreDeclarations . . . . .
2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6
6
7
9
9
9
9
10
10
11
11
12
13
13
15
15
15
16
16
17
18
19
20
20
21
22
22
23
24
25
25
3
Advanced Programming
3.1 Implementation Parts . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Programming controllers . . . . . . . . . . . . . . . . . . . . . . .
3.2.1 Client Interfaces Meta-Data . . . . . . . . . . . . . . . . .
3.2.2 Server Interfaces Meta-Data . . . . . . . . . . . . . . . . .
3.2.3 Attributes Meta-Data . . . . . . . . . . . . . . . . . . . . .
3.2.4 Components Meta-Data . . . . . . . . . . . . . . . . . . .
3.3 Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3.1 Existing properties . . . . . . . . . . . . . . . . . . . . . .
3.4 Aspect Oriented Programming using Global Extensions Mechanism
3.5 ADL predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.6 Compilation control and optimizations . . . . . . . . . . . . . . . .
3.7 Meta-Programming using builder specification . . . . . . . . . . . .
3.8 Entering component world . . . . . . . . . . . . . . . . . . . . . .
3
.
.
.
.
.
.
.
.
.
.
.
.
.
27
27
28
28
29
30
30
31
32
33
33
34
35
35
Chapter 1
Introduction
This document aims to give sufficient information to help developers design and program Think components ar applications made of existing Think components. It does
not intend to detail how to use the Think compiler in order to build a component-based
software from existing component definitions. Such information can be found in the
Think User’s Manual.
Think is a native implementation of the Fractal component model[?]. It can be
used to develop OS kernels though it is not resticted to this application domain: the
framework can be used to develop any component-based system or application written in C. Thanks to the Fractal Component Model, Think adopts a clear separation
between architecture and components. As a consequence Think accelerates native
software de-velopment by allowing intensive re-use of pre-defined software component and rapid porting of infrastructure on new hardware targets. The Think project
(http://think.objectweb.org) provides a compiler and several languages and mechanisms to design and program components.
Since its first design, Think has known several transformations through several
versions. The latest version, Think v4, is known as Nuptse and focuses on simplcity
and efficiency:
• it simplifies the burden of the developers of think-based software by providing
simplified languages, especially for developers of functional code. It enables
enhancement and simplification;
• it makes possible the generation of very efficient software by providing the possibility to better master the flexibility power and implementation (and so the
associated cost) of generated software.
The goal of this new version is to make Think useable to design and program components for embedded applications and systems by taking into account the resource
constraints specific to this application domain. In particular we are targeting embedded application like Wireless Network Sensors (WSN). This document focuses on the
4
Nuptse version of Think.
A component library named Kortex is also hosted in the repository of the project1 .
Kortex includes many components, some of them being devoted to execution infrastructure and OS development (memory manager, interrupt handler, semaphores, runtime schedulers...). Functional code can be written in C extended with reserved names
representing architectural artifacts.
This document is split into two chapters. The first one details basic programming
concepts and languages to design and implement basic components, that is, that should
cover the requirements to design and implement, say, 90 % of components. The second
chapter gives additional information on advanced concepts and languages to program
control interfaces, develop and specify non-architectural aspect through properties and
global extensions, understand optimizations, etc.
1 For historical reason, this library is hosted by the Think project in the svn repository but may be extracted
from it in a near future.
5
Chapter 2
Basic programming
2.1
Basic concepts
A component, in the Fractal sense, is a runtime entity, often called a component instance. A component has a type, called a component type, that defines the type of
interactions the component can make. An interface is an interaction point, either an
entry point, called a server interface or a provided interface, or an exit point, called a
client interface or a required interface. In Fractal a component type is defined by the
types of the interfaces that the component provides and requires. A component has a
content and a membrane, the membrane having control over the content. The content
may consist of sub-components or implementation code1 . A component may also have
attributes that reify non-functional properties of the component (like the speed of a
serial port on the size of a buffer). The provided interfaces implemented by the content
are called functional interfaces whereas the interfaces implemented by the membrane
are called control interfaces. The idea here is that the content implements functional aspects of the component, whereas the membrane implements the non-functional aspects
and provides control over this non-functional aspects. One particular non-functional
aspect is the architectural one. The Fractal model defines a set of interface types that
may be implemented to control the architecture of a system at runtime, namely:
• the Component interface that gives access to the interfaces provided by te component;
• the BindingController interface, that gives access to the interfaces required by the component and allows to change bindings;
• the ContentController that gives access to sub-components, if any, and allows to change the content of the component (i.e. add remove sub-components);
• the AttributeController that allows to get and set the value of an attribute.
1 Or
both in the case of Think, see section 3.1 for more details.
6
Remember that Fractal is a runtime component model. This precision is important since many other component models are design-time models. Fractal doesn’t care
about the design phase. When taking about Fractal implementations like Julia or Think
we are taking about frameworks that are able to generate components that, once loaded,
will be Fractal-compliant components. However, frameworks like these, do care about
the design phase and provide languages to design components and program, typically
an Interface Description Language (IDL) and an Architecture Description Language
(ADL). They also provide one or more compilers or tools to generate data that will
help to create components (i.e. component instances) at runtime. In this design phase,
we are out of the scope of the Fractal model, though there are similarities.
One particular concept that does not exist at runtime is the concept of component
definition. A component definition is a component type (it defines the set of client
and server interfaces) with additional information about how this component is implemented. In other component models this is often referred to as a component implementation of a component (or component type). In Think the concept of implementation
rather refers to the code that implements server interfaces.
Think provides an IDL to express the types of interfaces, and an ADL to express
component definitions. In the sense of programming languages what is defined in an
IDL or an ADL file (respectively interface types and component definitions) is a type.
This is very similar to Java classes and interfaces that are defined in Java files: they are
types. But beware: a component definition which is a type in the ADL sense, should
not be confused with a component type in the Fractal sense, since it also expresses how
a component type is implemented.
Also, we may sometimes say that a component definition contains sub-components,
but actually only components (that is component instances) can contain sub-components.
To be precise, a component definition may contains declarations of references to subcomponents. At runtime, instances of this component definition will contain references
to (sub-)components. This is very similar to a Java class that contains a declaration of a
typed reference: at runtime, objects (i.e. instances) of this class will contain references
to other objects.
2.2
The Interface Description Language (IDL)
Think provides a language, called an Interface Description Language (IDL), to declare interface types. In the Nuptse version, this language extends the C grammar with
few keywords. In brief, an interface type is defined by a set of methods and a set of
constants. Methods are declared as C functions and constants are declared as typed
variable with an initial value.
An interface is declared as follows:
package <packageName : DotName> ;
( t y p e d e f s < f i l e P a t h : DotName> ; ) ∗
i n t e r f a c e <i n t e r f a c e T y p e N a m e : Name> {
7
(< m e t h o d D e c l a r a t i o n > ; |
<c o n s t a n t D e c l a r a t i o n > ; ) ∗
}
packageName is the name of the package that contains this interface type. Like in
Java, it must corresponds to the path of the directory that contains the file into which
this interface type is defined. methodDeclaration must be a valid C function
prototype declaration and constantDeclaration must be a valid initialized C
variable declaration. The C types used in the declaration of methods and constants can
be primitive C types (ex: int, unsigned int, short, struct, ...) but also types defined in
external files : either a global file containing types which scope is the whole system
which can be specified using the global-typedefs-file option passed to the
compiler, or using the typedefs keyword. This keyword specifies that a file must
be parsed before parsing the content of the interface definition and search for type
definitions. These types can then be used in method or constant declaration and also
in code that implements server interface or that uses client interfaces of this interface
type. Note that if the -prefix-IDL-typedefs compiler option is set to true, uses
of this types in the implementation code must be prefixed with the path of the interface
type, with dots replaced with underscores.
Example In the following example, the interface type foo.api.Foo is defined as
a method bar and a constant string CONST_STRING which value is "hi". Method
bar takes a parameter a of type aType which is defined in file foo/api/aFile.h.
package f o o . a p i ;
typedefs aFile ;
i n t e r f a c e Foo {
char ∗ CONST STRING = ” h i ” ;
u n s i g n e d i n t b a r ( aType a ) ;
}
The content of file foo/api/aFile.h is given bellow:
typedef struct {
int x ;
} aType ;
8
2.3
The Architecture Description Language (ADL)
2.3.1
Introduction
2.3.2
Keywords
2.3.2.1
component
Usage Declares a component definition.
[ a b s t r a c t ] component <compDefName : DotName>
[ e x t e n d s <extCompDefName : DotName> ] {
...
}
Description Declares a component definition named compDefName. This definition may extend another definition named extCompDefName. Extending a component definition is like inlining the whole content of the extended definition into the
extending one. Abstract component definition are component definition that are not
sufficiently defined or that are not fully functional to exist at runtime. That is, they
can only be used to declare an abstract sub-component in a component definition (see
2.3.2.6 for more details). Also, an component that contains an abstract sub-component
must be declared abstract.
Example The following code declares an abstract component definition named here.is.bar,
and another (concrete) component definition named here.is.foo as an extension
of here.is.bar.
a b s t r a c t component h e r e . i s . b a r {
provides itfTypeA as i t f a
c o n t a i n s subCompX = subCompDefX
b i n d s t h i s . i t f a t o subCompX . i t f a
}
component h e r e . i s . f o o e x t e n d s h e r e . i s . b a r {
provides itfTypeB as i t f b
r e q u i r e s itfTypeC as i t f c
c o n t a i n s subCompY = subCompDefY
b i n d s t h i s . i t f b t o subCompY . i t f b
b i n d s subCompY . i t f c t o t h i s . i t f c
b i n d s subCompY . i t f a t o subCompX . i t f a
}
The definition above of here.is.foo is equivalent to:
component h e r e . i s . f o o {
provides itfTypeA as i t f a
9
provides itfTypeB as i t f b
r e q u i r e s itfTypeC as i t f c
c o n t a i n s subCompX = sumCompX
c o n t a i n s subCompY = subCompDefY
b i n d s t h i s . i t f a t o subCompX . i t f a
b i n d s t h i s . i t f b t o subCompY . i t f b
b i n d s subCompY . i t f c t o t h i s . i t f c
b i n d s subCompY . i t f a t o subCompX . i t f a
}
2.3.2.2
provides
Usage Declares a provided (a.k.a server) interface in a component definition.
p r o v i d e s <i t f T y p e : DotName> a s <i t f N a m e : Name>
Description Declares a provided (a.k.a server) interface named itfName of interface type itfType.
Example The following code declares, in a component definition here.is.bar, a
provided interface named foo of interface type here.is.Foo.
i n t e r f a c e h e r e . i s . Foo {
void foo1 ( i n t a , i n t b ) ;
i n t foo2 ( char x ) ;
}
component h e r e . i s . b a r {
p r o v i d e s f o o a s h e r e . i s . Foo
}
2.3.2.3
requires
Usage Declares a required (a.k.a client) interface in a component definition.
r e q u i r e s <i t f T y p e : DotName> a s <i t f N a m e : Name>
[ ( mandatory | o p t i o n a l ) ]
Description Declares a required (a.k.a client) interface named itfName of interface
type itfType. A client interface may be declared as optional or mandatory (default
is mandatory). Any mandatory interface of a component instance must be bound to a
server interface. The build chain will complain about unbound mandatory interfaces
and will consequently fail.
10
Example The following code declares, in a component definition here.is.bar, a
required interface named foo of interface type here.is.Foo.
i n t e r f a c e h e r e . i s . Foo {
void foo1 ( i n t a , i n t b ) ;
i n t foo2 ( char x ) ;
}
component h e r e . i s . b a r {
r e q u i r e s f o o a s h e r e . i s . Foo
}
2.3.2.4
attribute
Usage Declares an attribute.
a t t r i b u t e <a t t T y p e : Type> <a t t N a m e : Name>
[ ”=” <v a l u e : E x p r e s s i o n > [ c o n s t ] ]
Description Declares an attribute named attName of type attType in a component definition. An initial value may be specified. This will be the value of the attribute
once the system initialized. If const is specified the attribute will be constant, that is,
will keep its initial value ant will not be modifiable at runtime. Usage in the functional
code may be replaced by the specified value, so that trying to assign it in the functional
code will possibly lead to a compile-time error.
Example The following code declares three attributes in a component definition
here.is.bar. foo1 is an int and has no initial value, foo2 is of type short and will
be instanciated with 3 as initial value, foo3 is a constant char attribute which value is
10 and foo4 is a constant string attribute which value is ”hello world”.
component h e r e . i s . b a r {
a t t r i b u t e i n t foo1
a t t r i b u t e s h o r t foo2 = 3
a t t r i b u t e c h a r f o o 3 = 10 c o n s t
a t t r i b u t e s t r i n g foo4 = ” h e l l o world ” const
}
2.3.2.5
assigns
Usage Assigns a value to an attribute of a sub-component.
a s s i g n s <subCompName : Name>.< a t t N a m e : Name>
”=” <v a l u e : E x p r e s s i o n >
11
Description Assigns value value to attribure attName of sub-component subCompName.
subCompName must be the name of a sub-component declared in the component definition (see 2.3.2.6). If the attribute was already declared with a value, the latter is
overwritten with the new value.
Example The following code declares a component definition here.is.foo that
contains a sub-component subComp of type here.is.bar and assigns a new value
to its attribute att.
component h e r e . i s . b a r {
attribute int att = 1
}
component h e r e . i s . f o o {
c o n t a i n s subComp = h e r e . i s . b a r
a s s i g n s subComp . a t t = 2
}
2.3.2.6
contains
Usage Declares a sub-component in a component definition.
c o n t a i n s <subCompName : Name> ( : | = ) <compDef : DotName>
Description Declares a sub-component subCompName of component type compDef
in a component definition. The ”:” notation declares an abstract sub-component and
must be used if and only if compDef is an abstract component definition. In that
case, the enclosing component definition must also be declare as abstract. Note however that an abstract component definition must not necessarily contains abstract subcomponents.
Example The following example declares an abstract component definition here.is.bar1
containing an abstract sub-component c which definition is the abstract component
definition here.is.foo1, and a (concrete) component definition here.is.bar1
that extends here.is.bar1 and overloading the abstract sub-component c with a
concrete sub-component which definition is here.is.foo1.
a b s t r a c t component h e r e . i s . f o o 1 {
...
}
component h e r e . i s . f o o 2 e x t e n d s h e r e . i s . f o o 1 {
...
}
12
a b s t r a c t component h e r e . i s . b a r 1 {
...
contains c : here . i s . foo
}
component h e r e . i s . b a r 2 e x t e n d s h e r e . i s . b a r 1 {
contains c = here . i s . foo2
}
2.3.2.7
singleton
Usage Forces a component definition to be instanciated only once in a architecture.
singleton
Description Forces a component definition to be instanciated only once in a architecture. Two component instances of two different component definitions that contain
a declaration of a sub-component which definition is declared as singleton will share
the same sub-component instance at runtime.
Example The following code declares a singleton component definition here.is.foo,
a component definition here.is.bar1 that contains a sub-component c1 of component type here.is.foo and a component definition here.is.bar2 that contains
a sub-component c2 of component type here.is.foo, and a sub-component c3
of component type here.is.bar1. In a instance x of the component definition
here.is.bar2, x:c2 and x:c3:c1 refer to the same shared component instance.
component h e r e . i s . f o o {
...
singleton
}
component h e r e . i s . b a r 1 {
c o n t a i n s c1 = h e r e . i s . f o o
}
component h e r e . i s . b a r 2 {
c o n t a i n s c2 = h e r e . i s . f o o
c o n t a i n s c3 = h e r e . i s . b a r 1
}
2.3.2.8
content
Usage Specifies a file that contains implementation code.
13
c o n t e n t <f i l e N a m e : DotName> [ raw ] )
Description Specifies that file which base name (i.e. without extension) is fileName
with dot replaced with file separator, contains implementation code. The extension of
the file name must be one of the following: ”.c”, ”.s”, ”.S”. If multiple files exist with
the same base name, the first file that fits the mentioned extensions will be used, in the
mentioned order. Note multiple files may be specified for implementing the component, so that implementation code can be split across several files.
If raw is specified, then the file contains code that does not directly implement server
interfaces but usual C or assembly code instead and cannot make use of the model artifacts (access attributes, call client interfaces, ...).
Files will be searched in the component repository path list specified in the command
(see ??).
Example In the following example, if we suppose that rep1 and rep2 are in the
repository path list in that order, file rep1/a/b/f1.c contains code for the default
implementation part, files rep1/a/b/c/f2.c and rep2/a/b/f3.c contain code
for the implementation part imp1, file rep2/a/b/c/f4.c contains code for the
implementation part imp2, and file rep1/a/b/d/f4.c is to be added as is2 . Note
that rep2/a/b/c/f2.c will be ignored.
component h e r e .
...
content
content
content
content
content
}
i s . foo {
a . b . f1
a . b . c . f 2 f o r imp1
a . b . f 3 f o r imp1
a . b . c . f 4 f o r imp2
a . b . d . f 5 raw
File structure:
rep1
+− a
+− b
+− f 1 . c
+− c
+− f 2 . c
rep2
+− a
+− b
+− f 3 . c
+− c
2 See
section 3.1 for explainations on multiple implementation parts.
14
+− f 2 . c
+− d
+− f 5 . c
2.3.3
Deprecated Keywords and constructions
The following keywords and constructions are still supported by the compiler but are
deprecated and may not be supported in future releases of the compiler. Programmers
are strongly invited to use the corresponding keyword or construction.
deprecated
new expression
composite
componenta
primitive
component2
abstract component
type
attribute
attributes
attribute
attribute
<attType> <attName>
<attName> : <attType>
skeleton
content
! nolccb
provides
fractal.api.LifeCycleController
implements
extends
a There is no more dinstcintion between primitive and composite components. Components are hybrid
components in the sense that they can contain implementation code and sub-components
b ! nolcc means the absence of the keyword
2.4
2.4.1
The NuptC Component Programming Language
Introduction
Nuptse provides a Component Programming Language (CPL) called NuptC to write
the functional code implementing the provided interfaces of a component definition.
The CPL provides a way to the programmer to express the mapping between symbols
defined in the ADL and IDL files corresponding to the component definition and the
symbols in the C code that implements this component definition.
Contrary to previous CPLs of Think, NuptC has been designed in order to:
• minimize the burden of the programers and clarify functional code by providing
clear keywords representing the component concepts;
• allows optimizations by providing keywords that do not reflect particular implementation of the meta-data.
Functional code is parsed by the compiler and is translated into an Abstract Semantic Graph using the CodeGen library3 . Because NuptC does not extend the C
grammar, files can be parsed with the C parser provided by CodeGen and the compiler
3 CodeGen
is currently hosted by the Think project.
15
implements a listener to handle the specific keywords. This ASG is then analyzed and
transformed by the build chain and the resulting C files are then produced before being
compiled by a C compiler (along with files containing the glue code).
Historically, NuptC was extending the C language with architectural-oriented reserved identifiers having well defined naming conventions. The grammar was the same
but some identifiers were recognized as C mapping of architectural concepts. For example, to implement a method foo of a server interface bar, one had to declare a C
function named SRV_foo__bar with appropriate parameters. While this approach
simplified a lot the burden of programming component compared to the previous versions, and did allow arbitrary optimizations and implementations of architectural concepts, we went one step further: annotations.
CodeGen is now able to parse annotations in C comments, delimited by two ”@@”
tokens, like /* @@ ServerMethod(foo, bar, bar) @@ */. It does not define a particular syntax of the annotations. It just detects them and notifies them through
a Java ParsingListener interface. The Nuptse compiler implements this Java interface
to allow programmers to specify the mapping by annotating their C code. The main
benefit of this new approach is that it is way less intrusive. First, programmers can
decide to organize their mapping information as they want, either by annotating each
C function, or by gathering all these information in the header or even in another file.
But a greater benefit is encapsulation of legacy code. Indeed, it is very important, when
transforming a legacy code to encapsulate it into a component, to modify the less possible the original code. Why there a many reasons for that, in is particularly important
that subsequent evolutions of the original code can be applied to the transformed encapsulated code. Typically, if there a patch correcting a bug, it would be very interesting
that the same patch can be applied to the encapsulated code. NuptC annotations allow
to specify the names of the C symbols that represent architectural concept. Hence, it
is possible, for example, to specify that the original name of a C function is used to
represent a server method, so that there is no need to touch the original code to encapsulate it in a component definition. The legacy example in the example directory of the
compiler gives a simple example of a C code that has been encapsulated in components
without touching a single line of the original code.
Note that the previous approach using naming conventions is still supported. When
programming components from scratch, some developers prefer this old approach because it makes mapping symbol more explicit, more ”visible”. To do this, NuptC
defines implicit annotations that make available these old-style symbols4 . These predefined annotations are detailed in the following sections.
2.4.2
NuptC annotations
2.4.2.1
ServerMethod
Usage Declares a server method.
/ ∗ @@ ServerMethod (< s e r v e r I n t e r f a c e N a m e >, <methodName>
[ , <f u n c t i o n N a m e > ] ) @@ ∗ /
4 This
behavior will be controllable in future releases through a compiler option
16
Description Specifies that the C function functionName implements the method
methodName of the server interface serverInterfaceName. If the parameter
functionName is omitted then the representing function is the following C function
declaration (or definition). Note that the methodName parameter refers to the IDL
definition of the type of the interface whereas the serverInterfaceName refers
to the name of the interface provided by the implemented component, found in the
corresponding ADL file.
Examples In the following example the programmer specifies that the C function
myBar implements the method bar of the server interface foo.
/ / @@ ServerMethod ( f o o , bar , myBar ) @@
[...]
i n t myBar ( i n t x ) {
...
}
It the second following example the programmer specifies that the C function bar
following the annotation implements the server method.
/ / @@ ServerMethod ( f o o , b a r ) @@
int bar ( int x ) {
...
}
Predefined annotations For each method methodName of each interface itfName
provided by the component, Nuptse predefines the following annotation:
/ ∗ @@ ServerMethod (< i t f N a m e >, <methodName >,
SRV <i t f N a m e > <methodName >) @@ ∗ /
2.4.2.2
DefaultServerMethods
Usage Specifies that default symbol names will be used for representing server methods.
/ ∗ @@ D e f a u l t S e r v e r M e t h o d s
[ (< i t f N a m e 1 >, <i t f N a m e 2 >, . . . <itfNameN >) ] @@ ∗ /
Description Specifies that the methods of server interfaces itfName1 ... itfNameN
are implemented by C function having the same names than the methods of the interface. If no interface is given, then this applies to all server interfaces of the component.
Note that if two provided interfaces have methods with the same name, an error will
17
be thrown if this annotation is used for both interfaces. In that case, the standard annotation ServerMethod must be used for at least one of the conflicting interfaces.
This is a shortcut to writing the following annotation, for each method methodName
of each interface itfName provided by the component:
/ ∗ @@ ServerMethod (< i t f N a m e >, <methodName >,
<methodName >) @@ ∗ /
Example In the following example the programmer specifies that methods bar and
gnu of interface foo are implemented by C functions with identical names.
/ / @@ D e f a u l t S e r v e r M e t h o d s ( f o o ) @@
[...]
int bar ( int x ) {
...
}
[...]
v o i d gnu ( s h o r t x ) {
...
}
2.4.2.3
ServerInterfacePrefix
Usage Specifies the prefix of functions that implement the methods of a server interface.
/ ∗ @@ S e r v e r I n t e r f a c e P r e f i x (< s e r v e r I n t e r f a c e N a m e >,
<p r e f i x >) @@ ∗ /
Description Specifies that the methods of a provided interface serverInterfaceName
will be implemented by C functions having the same name than the methods prefixed
with prefix. This is a shortcut to writing the following annotation, for each method
methodName of each interface itfName provided by the component:
/ ∗ @@ ServerMethod (< i t f N a m e >, <methodName >,
<p r e f i x ><methodName >) @@ ∗ /
Examples In the following example the programmer specifies that the method bar
and gnu of server interface foo are implemented respectively by C functions my_bar
and my_gnu.
/ / @@ S e r v e r I n t e r f a c e P r e f i x ( f o o , my ) @@
[...]
i n t my bar ( i n t x ) {
18
...
}
[...]
v o i d my gnu ( s h o r t x ) {
...
}
2.4.2.4
ClientMethod
Usage Specifies the symbol representing a client method.
/ ∗ @@ ClientMethod (< c l i e n t I n t e r f a c e N a m e >, <methodName>
<f u n c t i o n N a m e > ) @@
∗/
Description Specifies that the C function symbol functionName represents the
method methodName of the client interface clientInterfaceName. Calls to
the client method can then be made by a C call using this symbol. Note that the
methodName parameter refers to the IDL definition of the type of the interface whereas
the serverInterfaceName refers to the name of the interface required by the implemented component, found in the corresponding ADL file. Also note that client
methods can only be called from server or private methods. Trying to call the method
in a normal C function will raise an error.
Example In the following example the programmer specifies that the C function symbol myBar represents the method bar of the client interface foo. This method is
called in function aMethod.
/ / @@ ClientMethod ( f o o , bar , myBar ) @@
i n t aMethod ( i n t x ) {
myBar ( x ) ;
}
Predefined annotations For each method methodName of each interface itfName
required by the component, Nuptse predefines the following annotation:
/ ∗ @@ ClientMethod (< i t f N a m e >, <methodName >,
CLT <i t f N a m e > <methodName >) @@ ∗ /
19
2.4.2.5
DefaultClientMethods
Usage Specifies that default symbol names will be used for representing client methods.
/ ∗ @@ D e f a u l t C l i e n t M e t h o d s [ (< i t f N a m e 1 >, <i t f N a m e 2 >,
. . . , <itfNameN >) ] @@ ∗ /
Description Specifies that the methods of client interfaces itfName1 ... itfNameN
are represented by C function having the same names than the methods of the interface.
If no interface is given, then this applies to all client interfaces of the component. Note
that if two required interfaces have methods with the same name, an error will be
thrown if this annotation is used for both interfaces. In that case, the standard annotation ClientMethod must be used for at least one of the conflicting interfaces. This
is a shortcut to writing the following annotation, for each method methodName of
each interface itfName required by the component:
/ ∗ @@ ClientMethod (< i t f N a m e >, <methodName >,
<methodName >) @@ ∗ /
Example In the following example the programmer specifies that methods bar and
gnu of interface foo are represented by C function symbols with identical names.
These methods are called in function aMethod.
/ / @@ D e f a u l t C l i e n t M e t h o d s ( f o o ) @@
i n t aMethod ( i n t x ) {
foo ( x ) ;
bar ( x +1);
}
2.4.2.6
ClientInterfacePrefix
Usage Specifies the prefix of functions that represents the methods of a client interface.
/ ∗ @@ C l i e n t I n t e r f a c e P r e f i x (< c l i e n t I n t e r f a c e N a m e >,
<p r e f i x >) @@ ∗ /
Description Specifies that the methods of a required interface serverInterfaceName
are represented by C functions having the same name than the methods, prefixed with
prefix. This is a shortcut to writing the following annotation, for each method
methodName of each interface itfName required by the component:
20
/ ∗ @@ ClientMethod (< i t f N a m e >, <methodName >,
<p r e f i x ><methodName >) @@ ∗ /
Examples In the following example the programmer specifies that the method bar
and gnu of client interface foo are represented respectively by C functions ext_bar
and ext_gnu.
/ / @@ C l i e n t I n t e r f a c e P r e f i x ( f o o , e x t ) @@
[...]
i n t aMethod ( i n t x ) {
ext foo (x );
ext bar (x +1);
}
2.4.2.7
Attribute
Usage Specifies the symbol representing an attribute.
/ / @@ A t t r i b u t e (< a t t r i b u t e N a m e >, <varName >) @@
Description Specifies that the C variable symbol varName represents the attribute
attributeName. Calls to the client method can then be made by a C call using
this symbol. Note that the methodName parameter refers to the IDL definition of the
type of the interface whereas the serverInterfaceName refers to the name of the
interface required by the implemented component, found in the corresponding ADL
file. Note that attributes can only be accessed from server or private methods. Trying
to access the attribute in a normal C function will raise an error.
Example In the following example the programmer specifies that the C variable
symbol myVar represents the attribute att. This attribute is accessed in function
aMethod.
/ / @@ A t t r i b u t e ( a t t , aVar ) @@
[...]
i n t aMethod ( i n t x ) {
aVar = aVar + x ;
r e t u r n aVar ;
}
21
Predefined annotations
ing annotation:
For each attribute attName, Nuptse predefines the follow-
/ / @@ A t t r i b u t e (< attName >, ATT <attName >) @@
2.4.2.8
DefaultAttributes
Usage Specifies that default symbol names will be used for representing attributes.
/ / @@ D e f a u l t A t t r i b u t e s @@
Description Specifies that the attributes of the components are represented by C variable having the same names than the attributes. This is a shortcut to writing the following annotation, for each attribute attributeName:
/ / @@ A t t r i b u t e (< a t t r i b u t e N a m e >, <a t t r i b u t e N a m e > @@
Example In the following example the programmer specifies that attributes att1
and att2 are represented by C variable symbols with identical names. These attributes
are accessed in function aMethod.
/ / @@ D e f a u l t A t t r i b u t e s @@
i n t aMethod ( i n t x ) {
att1 = att1 + x;
a t t 2 −= x ;
return a t t 1 + a t t 2 ;
}
2.4.2.9
AttributesPrefix
Usage Specifies the prefix of variables that represent the attributes of a component.
/ / @@ A t t r i b u t e s P r e f i x (< p r e f i x >) @@
Description Specifies that the attributes of the component are represented by C variables having the same name than the attributes, prefixed with prefix. This is a shortcut to writing the following annotation, for each attribute attributeName of the
component:
/ ∗ @@ A t t r i b u t e (< a t t r i b u t e N a m e >,
<p r e f i x ><a t t r i b u t e N a m e >) @@ ∗ /
22
Examples In the following example the programmer specifies that the attribute att1
and att2 are represented respectively by C variables att_att1 and att_att2.
/ / @@ A t t r i b u t e s P r e f i x ( a t t ) @@
i n t aMethod ( i n t x ) {
att att1 = att att1 + x;
a t t a t t 2 −= x ;
return a t t a t t 1 + a t t a t t 2 ;
}
2.4.2.10
PrivateData
Usage Specifies a C global variable as a private data.
/ / @@ P r i v a t e D a t a [( < v a r i a b l e N a m e >)] @@
Description Specifies that the C variable variableName will be a private variable.
Private variables are component variables, that is, each component instance of a component definition will have its own instantiation of the declared private variables. If
parameter variableName is omitted then the annotation indicates that the variable
declaration that follows is a private data.
Examples In the following example the programmer specifies that variable aVar is
a private data which is accessed (as a normal C variable) in server method bar.
/ / @@ P r i v a t e D a t a ( aVar ) @@
[...]
i n t aVar ;
[...]
/ / @@ ServerMethod ( f o o , b a r ) @@
int bar ( int x ) {
aVar = aVar ∗ x ;
}
The following example illustrates the use of the annotation where the name of the
variable is omitted.
/ / @@ P r i v a t e D a t a @@
i n t aVar ;
[...]
/ / @@ ServerMethod ( f o o , b a r ) @@
int bar ( int x ) {
aVar = aVar ∗ x ;
}
23
Predefined annotation Variable names PRIVATE is considered as a private variable.
That is, Nuptse predefines the following annotation:
/ / @@ P r i v a t e D a t a ( PRIVATE ) @@
2.4.2.11
PrivateMethod
Usage Specifies a C function as a private method.
/ / @@ PrivateMethod [( < f u n c t i o n N a m e >)] @@
Description Specifies that the C function functionName is a private method. A
private method is a function that can access data of the component instance (access
attributes, call client methods, ...), like a server method, but does not implement any
method of a server interface. If parameter functionName is omitted then the annotation indicates that the function declaration that follows is a private method.
Examples In the following example the programmer specifies that function prvMeth
is a private method which makes a call to a client method gnat.
/ / @@ ClientMethod ( g n u t , g n a t , g n a t ) @@
/ / @@ PrivateMethod ( p r v M e t h ) @@
[...]
i n t prvMethod ( i n t x ) {
gnat ( x ∗ x ) ;
}
[...]
/ / @@ ServerMethod ( f o o , b a r ) @@
int bar ( int x ) {
prvMethod ( x + 2 ) ;
}
The following example illustrates the use of the annotation where the name of the
function is omitted.
/ / @@ ClientMethod ( g n u t , g n a t , g n a t ) @@
[...]
/ / @@ PrivateMethod @@
i n t prvMethod ( i n t x ) {
gnat ( x ∗ x ) ;
}
[...]
/ / @@ ServerMethod ( f o o , b a r ) @@
int bar ( int x ) {
prvMethod ( x + 2 ) ;
}
24
Predefined annotation Functions that begin with PRV_ are considered as a private
method. That is, for such a function named PRV_foo, Nuptse predefines the following
annotation:
/ / @@ PrivateMethod ( PRV foo ) @@
2.4.2.12
KeepName
Usage Indicates to keep unchanged a C function.
/ / @@ KeepName @@
Description Specifies that the name of the following C function should not be changed
by the Nuptse compiler. This annotation can typically be used in case the function is to
be called from assembly code that cannot be transformed by the compiler.
Examples In the following example the programmer specifies that the name of the
C function bar representing the server method bar, should not be changed by the
compiler.
/ / @@ KeepName @@
/ / @@ ServerMethod ( f o o , b a r ) @@
int bar ( int x ) {
[...]
}
2.4.2.13
IgnoreDeclarations
Usage Indicates to eliminate declaration of global variables from the C source code.
/ / @@ I g n o r e D e c l a r a t i o n s ( <varName1 >, . . . , <varNameN> ) @@
Description Specifies that the variables named varName1, ..., varNameN should
be eliminated by the compiler when transforming the source code. This is typically
used when turning a C global variable into an attribute when encapsulating legacy
code. Note: IgnoreDeclarations annotations may be implicitly deduced in the
future from the Attributes or AttributePrefix annotations.
Examples In the following example the programmer specifies that the attribute att
is represented by symbol aVar and that the declaration of the C global variable is to
be ignored, because the variable has be turned into the attribute att.
25
/ / @@ A t t r i b u t e ( a t t , aVar ) @@
/ / @@ I g n o r e D e c l a r a t i o n s ( aVar ) @@
[...]
i n t aVar ;
int bar ( int x ) {
aVar = x ;
}
26
Chapter 3
Advanced Programming
3.1
Implementation Parts
In the Fractalmodel, a component may contain sub-component or code (that compose
its the content), and a primitive component is defined as follows: ”A component that
does not expose its content, but has at least one control interface, is called a primitive
component”. To our understanding, this definition does not prevent from having components made of sub-components and implementation code. The approach taken in
Think is to actually make no distinction between primitive and composite components,
since the property of being a primitive component is derived by other properties: the
fact that the component provides or not a ContentController interface. A server
interface can be either implemented by a sub-component or directly by implementation
code. Another particularity of Think, is that the implementation code of a component
may be made of multiple implementation parts. That is, the set of services provided
by a component may be split between multiple parts, each responsible of a subset of
the provided interfaces. One important outcome of this choice is that different properties may be associated to different implementation parts. For example, it is possible to
specify that the code implementing a control interface is shared between components,
while the code that implements a functional interface (or another control interface) is
not, or by specifying different builders for different implementation parts (see section
3.7).
When programming a component the basic way, programmers do not have to care
about implementation parts. For this reason, the Nuptse compilers defines a hidden
implementation part named default with the following rules:
• any provided interface that is not bound to a sub-component or is not implemented by another implementation is implemented by the default implementation;
• any client interface can be called by the default implementation part;
• any content file which is not specified for a particular implementation part contains code for the default implementation.
27
The ADL provides the following keywords to specify required interfaces, provided
interfaces and content files for a particular implementation part. Note that the current
notation is subject to change in the future. In the following example, the programmer
specifies that the provided interface foo is implemented by the implementation part
anImplementationPart that is made of the content file aFile and may call the
required interface bar. here.is.Foo.
component h e r e . i s . b a r {
[...]
p r o v i d e s f o o a s h e r e . i s . Foo i n a n I m p l e m e n t a t i o n P a r t
r e q u i r e s b a r a s h e r e . i s . Bar i n a n I m p l e m e n t a t i o n P a r t
content aFile for anImplementation
}
3.2
Programming controllers
Think provides a way to specify and implement control interfaces. The approach taken
in the Nuptse version is to make almost no distinction, in the specification, implementation and compilation, of control and functional interfaces. The only difference is that
programmers of implementations of control interfaces can use ”privileged” keyword to
get access to meta-data generated by the compiler. (This is very similar to the fact that,
in operating systems, kernel code has accessed to privileged machine instruction that
user code do not.) In addition, the compiler distribution comes with a set of implementations of the standard Fractal interfaces. This approach has the following benefits:
• it provides an uniform way to the programmers to specify and implement interfaces, whatever they are control or functional interfaces;
• it makes possible to specify, implement and use new control interfaces, or program new implementation of the Fractal interfaces;
• all optimizations that can be applied to functional interfaces can be applied the
same way to control interfaces. Also, it is possible to control the implementation
of meta-data corresponding to control interfaces as it is possible for functional
interfaces.
As mentioned above, NuptC provides ”privileges” symbols for programming implementation of control interfaces. This keywords give a way to initialize implementation code with values concerning the architecture known at compile time and access
and modify meta-data at runtime. All these keywords start with the META_ prefix.
3.2.1
Client Interfaces Meta-Data
META_NB_CLT_ITFS Compile-time value representing the number of client interfaces of the component.
28
META_CLTITF_TABLE Variable name that declares a table containing the name and
the id of each required interface. This table must be declared as an array of any
type, which size must be at least the number of client interfaces. The type if the
table is transformed into a array of struct with two fields:
• itfName the name if the interface
• itfId the id of the interface
The table is initialized with values known at compile time. For example if a
component requires two interfaces foo and bar, then the following declared
variable:
any META CLTITF TABLE[ META NB CLT ITFS ] ;
is transformed into the following code:
struct {
char ∗ i t f N a m e ;
any i t f I d ;
} META CLTITF TABLE[ META NB CLT ITFS ] = {
{ ” f o o ” , <f o o I d > } ,
{ ” b a r ” , <b a r I d > }
}
where fooId and barId are the identifiers of respectively the foo and bar
client interfaces.
META_CLT_ITF_SET Runtime function to set the server interface identifier corresponding to a given client interface identifier.
v o i d META CLT ITF SET ( any c l t I t f I d , any s r v I t f I d ) ;
META_CLT_ITF_GET Runtime function to get the server interface identifier corresponding to a given client interface identifier.
any META CLT ITF GET ( any c l t I t f I d ) ;
3.2.2
Server Interfaces Meta-Data
META_NB_SRV_ITFS Compile-time value representing the number of server interfaces of the component.
META_SRVITF_TABLE Variable name that declares a table containing the name and
the id of each provided interface. This table must be declared as an array of any
type, which size must be at least the number of server interfaces. The type if the
table is transformed into a array of struct with two fields:
29
• itfName the name if the interface
• itfId the id of the interface
The table is initialized with values known at compile time. For example if a
component provides two interfaces foo and bar, then the following declared
variable:
any META SRVITF TABLE [ META NB SRV ITFS ] ;
is transformed into the following code:
struct {
char ∗ i t f N a m e ;
any i t f I d ;
} META SRVITF TABLE [ META NB SRV ITFS ] = {
{ ” f o o ” , <f o o I d > } ,
{ ” b a r ” , <b a r I d > }
}
where fooId and barId are the identifiers of respectively the foo and bar
server interfaces.
3.2.3
Attributes Meta-Data
META_NB_ATTS Compile-time value representing the number of client interfaces of
the component.
META_ATT_SET Runtime function to set the value of an attribute given its identifier.
v o i d META ATT SET( any a t t I d , any a t t V a l u e ) ;
META_ATT_GET Runtime function to get the value of an attribute given its identifier.
any META ATT GET( any a t t I d ) ;
3.2.4
Components Meta-Data
META_NB_SUB_COMPS Compile-time value representing the number of sub-components
of the component.
META_SUBCOMP_TABLE Variable name that declares a table containing the name
and the id of each sub component. This table must be declared as an array of any
type, which size must be at least the number of sub components. The type if the
table is transformed into a array of struct with two fields:
• compName the name of the sub component
30
• compId the id of the sub component
The table is initialized with values known at compile time. For example if a component contains two sub components foo and bar, then the following declared
variable:
any META SUBCOMP TABLE[META NB SUB COMPS ] ;
is transformed into the following code:
struct {
char ∗ compName ;
any compId ;
} META SUBCOMP TABLE[META NB SUB COMPS] = {
{ ” f o o ” , <f o o I d > } ,
{ ” b a r ” , <b a r I d > }
}
where fooId and barId are the identifiers of respectively the foo and bar
sub components.
3.3
Properties
The Think ADL gives the possibility to attach properties to declarations of the different
artifacts of the architecture model: components, client interfaces, server interfaces,
attributes, implementation and content files. The syntax is:
[<propName>=<p r o p V a l u e >]
where propName and propValue are strings. Properties give a way to pass information to the different parts of the compiler.
For example, the property binds foo.i to bar.i [static=true] specifies that the binding between foo.i and bar.i will not change at runtime. The
builder of the client interfaces of foo (that is responsible of the generation of code that
makes the mapping between the identifier of a client interface and the identifier of the
server interface it is bound to), can take this property into account and generate direct
calls for invocations of the methods of foo.i.
/ / a t t a c h e d t o a component
component . . . [<propName>=<p r o p V a l u e >] {
/ / attached to a server i n t e r f a c e
r e q u i r e s . . . [<propName>=<p r o p V a l u e >]
/ / attached to a c l i e n t i n t e r f a c e
p r o v i d e s . . . [<propName>=<p r o p V a l u e >]
/ / a t t a c h e d t o an a t t r i b u t e
a t t r i b u t e . . . [<propName>=<p r o p V a l u e >]
/ / attached to a binding
31
b i n d s . . . [<propName>=<p r o p V a l u e >]
/ / attached to a content f i l e
c o n t e n t . . . [<propName>=<p r o p V a l u e >]
/ / a t t a c h e d t o an i m p l e m e n t a t i o n p a r t
i m p l e m e n t a t i o n . . . [<propName>=<p r o p V a l u e >]
}
3.3.1
Existing properties
Some properties are already defined and taken into account by the default builders of
the Think compiler. These properties are listed bellow, with the default value.
binds ... [static=true|false]
at runtime. Default value is false.
Specifies that the binding will not change
binds ... [inline=true|false] Specifies that, in case the binding is static,
the compiler should try to inline the code that implement the server interface into the
code of the caller of the client interface, or generate inline directives so as to inform
the C compiler to inline the code.
attribute ... [const=true|false]
change at runtime. Default value is false.
Specifies that the attribute will not
provides ... [single=true|false] Specifies that, in the scope of the interface, this entry point will be the only one for the corresponding interface type. Default value is false.
implementation ... [shared=true|false] Specifies that the code of
the implementation part should be shared between component instances, if possible1 .
Default value is true.
[attribute=<value>] Can be attached to component, attribute, provides,
requires or implementation to add __attribute__(<value>) to glue
descriptors of respectively components, attributes, server interfaces, client interfaces
and implementation. This can typically be used to control the placement of glue descriptors in memory sections (rom, ram, flash, ...).
[embedded-desc=true|false]
TO BE COMPLETED...
1 There are cases where such a directive cannot be satisfied. For example, if the component definition as
constant attributes and there is multiple instances of such component definition with different values, the if
the attribute are implemented as constants then the code cannot be shared. In this case [shared=false]
cannot be satisfied.
32
3.4
Aspect Oriented Programming using Global Extensions Mechanism
The Architecture Description Language introduced in section 2.3 allows to define a
component by extending another definition. Starting from a initial definition it is possible to add new interfaces, new attributes or new subcomponents. It is also possible to
specify new properties to existing interfaces, attributes, components, ... In the following, the component definition staticComp extends the definition comp by making
static the declared interfaces.
component s t a t i c C o m p e x t e n d s comp {
binds x . i to y . i [ s t a t i c = t r u e ]
binds x . j to z . j [ s t a t i c = t r u e ]
}
Nuptse introduces the notion of global extension as a way to extend multiple component definitions in a AOP-like manner using pattern matching. An extension specification is a standard ADL file but where names can have ”jokers” that will be matched
against names found in an architecture description. For example applying the following
extension definition make all bindings static of any component definition.
component ∗ ∗ . ∗ {
binds ∗.∗ to ∗.∗ [ s t a t i c = t r u e ]
}
Th list of global extensions is specified with the ext-files. Users can also specify
the option ext-path to specify directories where to find extension files. The compiler will first look in the ext-path then in the src-path when looking for global
extensions. Each global extension is matched against each component definition found
in the architecture given as input to the build chain, and it matches the original definition is extended accordingly.
Note that currently pattern expression is very limited: only ”**.*” or exact names
are supported at the moment. More possibility (based on Java pattern matching) will be
available in the future. Also note that this not possible to specify a path to a component
instance (only names of component definition is supported at the moment). This will
be implemented in a near future. These two limitations do not however invalidate the
principles of the described approach.
3.5
ADL predicates
The ADL defines some predicates to condition some declarations.This predicate are
particularly useful in case of global extensions because they can be applied to different
component definition having different structure. For example, it should be useful to
add a BindingController interface to a component only if it has client interfaces.
This is expressed using the hasCltItf attribute as in the following example:
33
component ∗ ∗ . ∗ {
provides f r a c t a l . api . BindingController
as binding −c o n t r o l l e r in B i n d i n g C o n t r o l l e r
if hasCltItf
}
3.6
Compilation control and optimizations
Programmers can control the generation of meta data using properties and use global
extensions to apply the same properties to a set of components, interfaces, ... and
separate this specification from the description of the architecture. Using the default
builders, what can be currently controlled is:
• the placement of data using the attribute property (see section 3.3.1);
• the organization of descriptors using the embedded-desc property (see section 3.3.1);
Additionally the following optimizations are done:
• direct call are generated for static bindings and no meta-data is generated for the
client interface in the META_CLTITF_TABLE table.
• for code that is proper to a single component instance, the addresses of metadata are known at compile-time, so the ”this” parameter that may be generated
for implementations of server methods is not used;
• for single implementation of server interfaces, the ”this” parameter is not generated for implementations of server methods and the ”this” argument is not calculated when calling such a method. Combined with the previous optimization,
the ”this” parameter disappear completely;
• the organization of descriptors using the embedded-desc property (see section 3.3.1);
Note that not using the ”this” parameter in not-shared implementations is distinguished
to the not generation of the ”this” parameter of single interfaces. This is necessary because a client interface bound to a server interface which implementation is not shared
may possibly be re-bound to another server interface which implementation is not single and that expects a valid ”this” parameter to function properly. Only if the server
interface is single, the ”this” parameter need not to be passed because this means that
there is (and will be) no other server that implements the same interface type and so
client interfaces that are bound to it cannot be bound to another server interface (provided type correctness of bound interfaces is satisfied).
34
3.7
Meta-Programming using builder specification
The Think compiler provides a way to specify, for each component, which builders
should be invoked. This is done using the builder property. TO BE COMPLETED...
3.8
Entering component world
35
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF

advertisement