A Formal Denition for the Description of
Distributed Concurrent Components
Extended Version
Informatik-Bericht Nr. 2012-04
1
1
1
2
Stefan Kolatzki , Matthias Hagner , Ursula Goltz , and Andreas Rausch
Institute for Programming and Reactive Systems, TU Braunschweig
Muehlenpfordtstr. 23, 38106 Braunschweig, Germany
http://www.ips.cs.tu-bs.de/
{kolatzki, hagner, goltz}@ips.cs.tu-bs.de
2
Department of Informatics Software Systems Engineering, TU Clausthal
Albrecht-von-Groddeck-Str. 7, 38678 Clausthal-Zellerfeld, Germany
http://www.in.tu-clausthal.de/abteilungen/software-systems-engineering/
[email protected]
1
The component-based approach is well established to manage the complexity of large-scale software systems, by adding structure
and modularity to the development process and the resulting system. For
the formal analysis of such systems, a clear denition has to be provided
for the component description. In this paper, we describe an operational
semantics for the component description language DisCComp and its
execution environment. The formalisation is done in two steps: First an
abstract machine is dened and implemented which allows the execution
of systems build from DisCComp components. The second step is the
mapping of the DisCComp component descriptions to the instruction
set of the abstract machine. The resulting formal semantics can be used
as foundation for the verication of system properties, as for instance
semantic interface compatibility.
Abstract.
Keywords:
semantics
components, operationally described interfaces, operational
1 Introduction
The complexity of software systems has grown steadily in recent years. Thus,
under many aspects, it is not possible to handle these systems as a whole. However, especially for long living systems, it is important to have possibilities for
maintenance and adaptation. Therefore, the software architecture of a system is
usually decomposed into components. The component-based software engineering [19] enables the possibility to divide a complex system in smaller, manageable
parts. In the best case, these components can be maintained or even replaced
independently.
2
Kolatzki, Hagner, Goltz, Rausch
To connect the components, it is necessary to dene interfaces. In addition
to the syntactic level, also semantic aspects have to be considered to ensure the
intended behaviour of a system composed from components. The information if
the syntax matches is provided by the signature of the interfaces. The semantic
compatibility can only be veried if there is more information available, e.g., an
abstract representation of the implementation.
We propose to use the component description language DisCComp [15] as it
provides an operational way to dene the interfaces of the components and is
realistic enough to provide a foundation for component technologies actually in
use, e.g., CORBA [12] or .NET [20]. However, there was until now no formally
dened semantics for DisCComp and, consequently, a verication of interface
compatibility in composed systems based on a DisCComp description was not
possible.
In this paper, we develop and formalise an operational semantic for DisCComp by dening and implementing an abstract machine for the execution of
DisCComp based systems. Then we dene a mapping of the DisCComp component descriptions to the instruction set of the abstract machine.
The paper is structured as follows: Section 2 gives an overview of semantics for
other component systems. In Section 3 the used component description technique
DisCComp is explained using an example. The semantics of the abstract machine
for the DisCComp execution environment is given in Section 4 and Section 5
describes the translation of the DisCComp language into the instruction set of
the dened abstract machine. Section 6 concludes the paper.
As the entire description of the formal semantics is very extensive, only
cutouts can be described here. The complete denition of all elements can be
found in the appendix.
2 Related Work
A large number of dierent meta-models for component-based systems have
been developed. However, most of them have substantial dierences in their
approaches and purposes.
Commercial approaches, e.g., COM+ [8], CORBA [12], .NET [20], or, EJB
[17], are usually close to operating systems or programming languages. They
rely on the semantics of the underlying programming language. The purpose
of these approaches is to give a stable run-time environment. Therefore, they
leave out concepts like hierarchical structures, dierent types of communication,
and abstract behavioural description. SOFA 2.0 [6] tries to close this gap by
adding these concepts. It uses a Component Description Language (CDL) that
is translated into C++ or Java.
Fractal [5] is an open and general component model, that can be tailored to
t a large variety of dierent applications or domains. It can be used with a large
number of programming languages. Palladio [16] has an operational semantics
dened within the meta-model, but the purpose of Palladio is to predict the
performance of a system.
A Formal Denition for the Description of Components
3
KobrA [3] is an approach to make the component concept an integral part of
the complete software life cycle. Here, for every operation an operation schema
is dened, which shows the eects of the operation concerning input parameters,
changed variables, output values, and pre- and postconditions. The behaviour
is dened using UML state-charts. Crnkovic et al. [7] published a framework
for the classication of component models. In [9], they used the framework for
comparing the dierent approaches.
DisCComp oers a possibility to describe the behaviour of the component
interfaces at an abstract level. This feature is not common for component metamodels as they often focus on the syntactic description or dene protocols for
the order of calls on interfaces.
3 The Component Model DisCComp
DisCComp is a formal model based on set-theoretic formalisations of distributed
concurrent components. It allows modelling of dynamically changing structures,
a shared global state and asynchronous message communication, as well as synchronous method calls. In this section, we give an introduction to the concepts of
DisCComp and illustrate them by means of an example. A denition for the syntax used here will be presented in Section 5. DisCComp provides an UML-based
description technique for structural and behavioural aspects of component-based
systems. In the DisCComp approach, a software system consists of a set of disjoint instances, that can be of the types system, component, interface, attribute,
connection, message, thread, and value. A component can be connected to other
components by interfaces, which encapsulate the behaviour of the components.
Using this connection network, asynchronous messages can be send, and it is
also possible to access attributes of interfaces.
UserInterface
+sumSalary: Integer
+addPerson(String,Integer)
r_SalaryManager
DashBoard
SalaryManager
+getSalarySum():Integer
+addPerson(Person)
r_Person
r_Person
r_PersonManager
FinancialControl
Person
+name: String
+salary: Integer
PersonManager
+addPerson(String, Integer)
PersonOrganizer
Fig. 1.
DisCComp Example
4
Kolatzki, Hagner, Goltz, Rausch
A system may change its structure dynamically: instances may be created or
deleted, attributes may be assigned to interfaces, interfaces may be assigned to
components, or connections between interfaces can be created or deleted. The
description of a state of a system consists of the structure of the system, a state
of the communication, and the values of the attributes. This state is denoted as
a snapshot.
The DisCComp approach focuses on execution streams instead of timed
streams. Whenever a thread's call stack changes (e.g., a method returns or a
new method is called) a new observation point is reached. As it is done in techniques like CORBA or J2EE, there is a global order of all method calls and
returns. Consequently, there is an order of all observation points, and at every
observation point a snapshot is created, capturing the state of the system. A
transition between two states of the system is between a certain part of the
system-wide snapshot and a certain part of the threads' wished system-wide
successor snapshot after performing a method call or return.
Thus, DisCComp needs a specialised runtime system that schedules all threads
at each new method call or return from a method call. Whenever a thread wants
to perform a new method call or return, the run-time system composes a new
well-dened system-wide successor snapshot based on the thread's requested
changes and the current system-wide snapshot.
COMPONENT DashBoard
PROVIDED
INTERFACE UserInterface [1 ,1]
CONNECTION personManagerOfDB END thePersonManager : r_PersonManager [1 ,1]
METHOD addPerson ( name : String , salary : Integer )
thePersonManager . r_addPerson ( name , salary );
REQUIRED
INTERFACE r_PersonManager [1 ,1]
CONNECTION r_personsOfPM END r_persons : Person [0 ,*]
MESSAGE r_addPerson ( r_newName : String , r_newSalary : Integer )
POST correctPersonStorage ()
self@PRE . r_persons . size () + 1 == self . r_persons . size () ;
IF ( self . r_persons . exists (p: r_Person | NOT self@PRE . r_persons . exists ( p2 :
r_Person | p == p2 )) )
THEN (p . r_name == r_newName ) AND (p. r_salary == r_newSalary );
ELSE false ; ENDIF ;
INTERFACE r_Person [0 ,*]
ATTRIBUTE r_name : String
ATTRIBUTE r_salary : Integer
Fig. 2.
Component DashBoard
Figure 1 gives an excerpt from a Human Resource Management System, containing components for handling persons, salaries, and an external entry point.
DashBoard, SalaryManager, and PersonOrganizer. The components Dashboard and PersonOrganizer share two
interfaces (PersonManager with the method addPerson() and Person with
Three components are represented:
the possibility to access the stored persons). One requirement is that an object
A Formal Denition for the Description of Components
of type Person being passed as parameter of the function
5
addPerson() is really
added to the system with the correct name and salary. The code in Figure 2, 3,
and 4 is the partial textual illustration of the example in Figure 1.
DashBoard in Figure 2 denes the followDashBoard has a provided interface UserInterface and the required interfaces r_PersonManager and r_Person. UserInterface has a connection, accessible by the name thePersonManager, to the interface r_PersonManager
and a method addPerson(). r_PersonManager requires a set of connections to
The component description of
ing properties:
r_Person interfaces.
COMPONENT PersonOrganizer
PROVIDED
INTERFACE PersonManager [1 ,1]
CONNECTION personsOfPM END persons : Person [0 ,*]
MESSAGE addPerson ( name : String , salary : Integer )
newPerson : Person := NEW Person ;
newPerson . name := name ;
newPerson . salary := salary ;
newPersonsOfPM : personsOfPM := NEW personsOfPM BETWEEN newPerson AND self ;
INTERFACE Person [0 ,*]
ATTRIBUTE name : String
ATTRIBUTE salary : Integer
Fig. 3.
Component PersonManager
r_addPerson(). r_Person
r_name and r_salary. At method invocation addPerson()
message r_addPerson() is sent to thePersonManager. The
Additionally, it requires a message handling of
requires the attributes
of UserInterface a
description of r_PersonManager assigns the following post condition to the
r_addPerson() : One r_Person has to be added to the
r_addPerson() is processed. Furthermore,
r_name and r_salary of the added r_Person has to be equal to r_newName
and r_newSalary received by the message r_addPerson().
message processing of
set of r_Person connections after
SYSTEM SystemToVerify
USED COMPONENTS DashBoard , PersonOrganizer
INITIALIZATION
theDB : DashBoard := NEW DashBoard ;
thePO : PersonOrganizer := NEW PersonOrganizer ;
theUI : UserInterface := NEW UserInterface ASSIGNED TO theDB ;
thePM : PersonManager := NEW PersonManager ASSIGNED TO thePO ;
connUsPm : personManagerOfDB := NEW personManagerOfDB BETWEEN theUI AND thePM ;
theUI . addPerson ( " Richard Paulson " ,1200) ;
MAPPING OF DashBoard :: r_PersonManager TO PersonOrganizer :: PersonManager
MAP r_personsOfPM TO personsOfPM ; MAP r_addPerson TO addPerson ;
MAPPING OF DashBoard :: r_Person TO PersonOrganizer :: Person
MAP r_name TO name ; MAP r_salary TO salary ;
Fig. 4.
System Description
6
Kolatzki, Hagner, Goltz, Rausch
PersonOrganizer in Figure 3 denes the
PersonOrganizer has the provided interfaces PersonManager and Person. PersonManager has a set persons of connections to
Person interfaces and can receive the message addPerson(). Person has the
attributes name and salary. At reception of the message addPerson(), a new
The component description of
following properties:
interface Person is created with the name and salary received by the message.
The new Person interface is added to the set of connections
persons.
The description of the system, depicted in Figure 4, contains an initialisation
of the components and the interfaces as dened in Figure 1. Here, the interfaces
are assigned to components. Furthermore, the system description contains a
mapping from the required to the provided interfaces.
4 An Abstract Machine for DisCComp
The architecture of the DisCComp abstract machine, depicted in Figure 5, is
based on the Java Virtual Machine [10], resulting in a stack-based design. The
DisCComp abstract machine consists of two main elements: An execution engine
that manages the running threads and executes the component description, and
the memory. Static information, as the component descriptions, are hold in the
method area, which is a part of the memory. The dynamic part of the memory
consists of the shared memory, organised as a heap, and the thread exclusive
stacks. As described in Section 3, DisCComp uses snapshots to organise the
shared data. This behaviour is implemented as
m + 1 separated areas within the
heap.
The techniques used to describe the DisCComp abstract machine and its
semantic are based on [2, 1, 11, 4].
Heap
Stacks
Global Snapshot
Method Area
Snapshot
1
...
Snapshot
m
Threadstack
1
...
Threadstack
n
Memory
Execution Engine
Fig. 5.
Thread
1
...
Thread
n
Architecture of the DisCComp Abstract Machine
Figure 6 shows the instruction set of the DisCComp abstract machine. These
instructions can be categorised as follows:
A Formal Denition for the Description of Components
7
arithmetic, logic, and comparing operations,
variable and array access operations,
interface creation and access operations,
function calls and returns,
an conditional jump, and
DisCComp specic operations as creation and deletion of connections.
F ktInstr :=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
load index
| store index
add
| sub
mul
| div
neg
| or
and
| implies
xor
| not
cmpeq
| cmpneq
cmplt
| cmple
cmpgt
| cmpge
load
| store
aload
| astore
anew
| asize
return
| vreturn
pop
| dup
swap
| const wert
atpre
| atpast
getattribute atrN ame | setattribute atrN ame
invokesync mthN ame | invokeasync mthN ame
new type
| iftruegoto index
newconnection type
| deleteconnection type
violation
Fig. 6.
Instruction Set
Most of the instructions do not require parameters, as they are implicitly expecting the required information to be found on the operand stack. For example,
the arithmetic operator
add
expects two arguments of matching numeric type
to be placed on the operand stack, before it is executed. Unlike the Java Virtual
Machine, the DisCComp abstract machine does not have a mechanism to check
the validity of input les. The correctness is expected to be ensured during the
compilation process into the instruction set of the DisCComp abstract machine,
described in Section 5.
To store static and dynamic data for the conguration of the DisCComp
abstract machine an environment is dened, providing
mappings between names and element descriptors,
information of running threads, and
the shared memory with its snapshots.
8
Kolatzki, Hagner, Goltz, Rausch
Environment := < /* static part */
components:
interf aces:
methods:
nameM ap:
String → Component,
String → Interf ace,
String → M ethod,
String → String,
...
/* dynamic part */
threads:
T hread∗ ,
activeT hread:
T hread,
nextSnapshotId: N0 ,
snapshots:
Location × N → Object ∪ Array >
Fig. 7.
Environment
A cutout of the formal environment denition is depicted in Figure 7.
On start-up the environment of the DisCComp abstract machine has to be
initialised. For this, a set of special instructions is used that creates the component structure with its interfaces, loads required component descriptions, and
sets up the dened name mapping for the system. After the initialisation, those
instructions have no eect on the conguration of the DisCComp abstract machine.
An excerpt of these special instructions is depicted in Figure 8.
DecInstr :=
|
|
|
|
map sourceN ame targetN ame
include componentN ame
ccomponent name
cinterface name lowerBound upperBound
cmethod name returnT ype paramCount varCount startP os
...
Fig. 8.
Initialising instructions
The following denitions describe a DisCComp abstract machine conguration. This notation is used to describe the state transition for the instructions.
Denition 1. A conguration of the DisCComp abstract machine is a tuple
s := hE, Sn, t :: Θi
, where
E - is the global environment Environment,
Sn - the global snapshot-management Environment.snapshots, and
t :: Θ - a list of all available threads Environment.threads, where t
active thread Environment.activeT hread.
is the
To get direct access to the activated frame in the running thread, we introduce
the following expanded notation:
A Formal Denition for the Description of Components
9
Denition 2. An expanded conguration of the DisCComp abstract machine is
a tuple
s := hE, Sn, t = {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi
The active thread
t = Environment.activeT hread is disaggregated and rep-
resented by its sub elements, where
m - is the method t.activeF rame.method, running in the active frame,
preSn - the snapshot-id t.activeF rame.preSnapshot, the method was started
with,
pc - the program counter t.activeF rame.programCounter,
preP aram - the list of arguments t.activeF rame.preP arameters,
given to
the method instance,
l - the local variables t.activeF rame.localV ariables,
o - the operand-stack t.activeF rame.operandStack ,
Σ - the inactive frames t.f rameStack \ t.activeF rame,
pastSn - the id of the last created snapshott.pastSnapshot,
currentSn - the id of the current snapshot t.currentSnapshot,
Θ - the inactive threads Environment.threads \ t.
and
m.code(pc) = load i
v = getLocalV ariable(l, i)
o0 = v :: o
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
Fig. 9.
(1)
Inference Rule for load
On the basis of the previous denitions, the semantics of the instructions
can be dened with inference rules. The assumption in these rules consists of
two parts. In the rst part, conditions on the conguration of the DisCComp
abstract machine are dened, under which the rule can be applied. In Figure
9 the interference rule for the
load i -instruction is depicted. This instruction
i and puts it on the top of the operand
reads the local variable at position
stack. In the rst line of the assumption of this rule, it is checked whether the
instruction at the position of the program counter in the active method matches
load i.
In the second part, declarations and calculations for the successor state
are processed, using the variables of the active conguration. For loading the
local variable in
helper function
load i, rst the list of local variables has to be accessed via the
getLocalV ariable(l, i), which returns the value of the variable.
10
Kolatzki, Hagner, Goltz, Rausch
The next step is to put the determined value on top of the operand-stack, and
to store the manipulated stack. Finally the program counter is increased by one.
In the conclusion of the inference rule, the state transition is described using
the calculated values from the assumption. In case of the
load i
instruction,
the operand stack and the program counter are changed. This is represented by
o
exchanging the variables
and
pc
with the calculated values
o0
and
pc0
in the
new conguration.
m.code(pc) = add
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = V [arg1] + V [arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
Fig. 10.
(2)
Inference Rule for add
Figure 10 shows the interference rule for the arithmetic addition operation
of two numbers. As the architecture of the DisCComp abstract machine is designed as a stack-based machine, the instruction expects two numeric values
at the top of the operand stack. The values are read with the helper function
getStackElement(o, n), which returns the nth value from the top of the stack
o. To use the mathematical +-operation, an interpretation of the values read
has to be processed. This is done with the interpretation function V [arg ], which
N : IN T → Z
R : REAL → R
B : BOOL → B
S : ST RIN G → String
V : IN T ∪ REAL ∪ BOOL ∪ ST RIN G → Z ∪ R ∪ B ∪ String
Fig. 11.
Interpretation Functions
translates the stored value into a mathematical object, as for instance a natural
number. Figure 11 depicts the signature of the interpretation functions used. For
A Formal Denition for the Description of Components
simplication we assume a pre-dened mathematical object
11
String representing
the domain of character lists, with a concatenation operation and an equality
check.
m.code(pc) = invokeasync n
method = E.methods(n)
argLen = method.parameterCount
args = getStackElementList(o, argLen)
loc = getStackElement(o, argLen + 1)
newSn = E.nextSnapshotId
Sn0 = createSnapshot(Sn0 , newSn)
o0 = popStack(o, argLen + 1)
pc0 = pc + 1
f = newF rame(method, args, newSn, currentSn)
t0 = newT hread(f, newSn)
t00 :: Θ0 = chooseT hread(t0 :: t :: Θ)
E0 = E
0
E .nextSnapshotId = E.nextSnapshotId + 1
E 0 .activeT hread = t00
hE, Sn, t = {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
0
E , Sn0 , t00 :: Θ0
Fig. 12.
(3)
Inference Rule for invokeasync
DisCComp provides synchronous and asynchronous function calls, which are
invokesync and
invokeasync. As described in Section 3, a function call is a synchronisation point
for the snapshots of the calling method. The inference rule for the invokeasync
represented by the DisCComp abstract machine instructions
instruction, depicted in Figure 12, formally describes this behaviour. It uses
helper-functions to reduce the size of the rule.
In the assumption of the rule, it is rst checked whether the rule is applicable
to the current conguration. Then the required information about the method
to call is obtained, as for example the method descriptor, the number of parameters, the arguments, and the interface instance on which the method is called.
In the next lines, a new snapshot is created, which is used in the new asynchronous method. After all information have been collected, the calling frame
can be cleaned up by removing the parameters and the interface instance reference, and increasing its program counter by one. The new thread and its rst
frame are created with the helper functions
newF rame() and newT hread(), that
return the required data structures. A function call is also a scheduling point in
12
Kolatzki, Hagner, Goltz, Rausch
DisCComp, so the next active thread is chosen by the function
chooseT hread().
The exact implementation for this function is not xed, as dierent schedulers
can be used.
With the determined information, the new environment can be created. This
is done by rst copying the old state and then setting the manipulated data. In
this case, the new active thread and the new next snapshot-id are set. The successor conguration contains the created environment
management
0
Sn ,
E 0 , the updated snapshot
and the set of threads, containing the newly created thread.
In the presented cases, the semantics of one instruction is dened by exactly
one inference rule, but that does not apply to all instructions. For example the
iftruegoto instruction requires one inference rule for the case that the condition
was evaluated to true and one for false.
As seen in Section 3, a component can declare required interfaces containing
invariants and postconditions for methods. These requirements to the linked
interface have to be checked by the DisCComp abstract machine. Postconditions
are checked whenever the corresponding method is exited with a
vreturn
return
or
instruction, while invariants are checked at every snapshot. For the
check, the DisCComp abstract machine is put on hold and a new exclusive
thread is created. The properties check is transparent for the executing system,
as it does not inuence the conguration. To ensure this, the semantics of the
m.code(pc) = return
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
(4)
hE, Sn, {Σ, pastSn, currentSn} :: Θi
Fig. 13.
instructions
Modied Inference Rule for return
invokesync, return, and vreturn has to be dierent than in normal
return instruction,
mode. Figure 13 shows the modied inference rule for the
with the parts for merging and creating snapshots, and the selection of a new
thread removed. The instruction
invokeasync
can be left unmodied, as no
asynchronous calls are allowed in postconditions and invariants. In case of a
violation of one of the checked conditions, the execution of the component system
is stopped by performing the
violation
instruction and the contract breach is
reported to the user.
5 Translating DisCComp into the DisCComp Abstract
Machine
To dene a translation between the DisCComp language and the instruction set
of the DisCComp abstract machine, the syntax of the source language has to be
A Formal Denition for the Description of Components
13
specied rst. It is given as LL(*)-grammar [14] in a modied Extended BackusNaur Form. This modied style is the input format for the parser generator
ANTLR [13], which is used to implement a prototype of the compiler. ANTLR
allows the user to specify combined parser and lexer rules. Figure 14 depicts
an excerpt of the syntax denition for DisCComp. The nonterminal symbols
ID
and
INT
are lexer rules and specify the identiers and integer numbers in
DisCComp.
component
interface
method
statementsequence
statement
ifstatement
parexpression
expression
impliesExpression
xorExpression
ID
INT
::= `COMPONENT' ID `PROVIDED' interface * (`REQUIRED'
interface *)?
::= `INTERFACE' ID bounds (connection | attribute |
message | method | invariant )*
::= `METHOD' ID typelist (`:' ID)? statementsequence
postcondition *
::= (statement `;')*
::= ifstatement | expression
::= `IF' parexpression thenpart elsepart ? `ENDIF'
::= `(' expression `)'
::= impliesExpression (`:=' expression )?
::= xorExpression (`IMPLIES' xorExpression )?
::= orExpression (`XOR' orExpression )?
::= (`a'. . . `z' | `A'. . . `Z' | `_') (`a'. . . `z' | `A'. . . `Z' |
`0'. . . `9' | `_')*
::= (`0'. . . `9')+
...
Fig. 14.
Syntax Rules for DisCComp
The translation is dened by functions that take an syntactic element of the
input language as argument and return a sequence of instructions of the DisCComp abstract machine, enriched with labels. This kind of translation denition
is also used in [18] to dene the translation of Java code into Java bytecode.
Three translation functions are dened, dealing with the following aspects of
the input language:
1. Structural elements, like components, interfaces, attributes, etc.,
2. statements without return value, and
3. expressions.
The corresponding functions are
C [], S [],
andE
[],
which can call each other
recursively.
Figure 15 depicts an excerpt of the denition for the translation function
C [],
which is responsible for the translation of structural elements, including
the creation of the describing instructions for components, interfaces, and their
sub elements. The function provides overloaded implementations for the dierent
14
Kolatzki, Hagner, Goltz, Rausch
C [COMPONENT name provided required] =ccomponent name ·
· C [provided] · C [required]
C [PROVIDED {inf1 , . . . , infn }] =C [inf1 , ⊥] · . . . · C [infn , ⊥]
C [REQUIRED {inf1 , . . . , infn }] =C [inf1 , >] · . . . · C [infn , >]
C [INTERFACE name [l, u] {e1 , . . . , en }, r] =cinterface name l u ·
· C [e1 , r, name] · . . . · C [en , r, name]
C [MESSAGE name (args) stm, ⊥, inf ] =cmessage name |args| .#var(stm)
calc · S [stm] · return
calc·
...
Fig. 15.
Translation Function C []
syntactic elements that have to be translated. Pattern matching over the keywords and the structure of the syntactic expression is used to select the correct
function instance.
COMPONENT, hence the imC [COMPONENT name provided required] is the entry point for such
A component description starts with the keyword
plementation
input les. It creates the describing instruction for the component and then recursively calls the functions instances for the
PROVIDED- and the REQUIRED-part.
Each translation function is annotated with an , which represents a global translation environment. This environment provides a set of helper functions to access
static information about the parsed input le and its elements, like the number
of local variables in a method. In the implemented prototype of the compiler,
this environment is instantiated with the symbol table.
The behaviour description in methods, messages, and calculated attributes
is a sequence of statements, which is passed to the translation function
S [],
partially depicted in Figure 16.
S [; ] = S [{stm1 . . . stmn }] = S [stm1 ] · . . . · S [stmn ]
S [IF (exp) THEN stm ENDIF;] = E [exp] · not · iftruegoto
S [stm] · endif
endif·
...
Fig. 16.
Translation Function S []
A sequence of statements is decomposed and each part is recursively passed
to the specic implementation of
S []. One possible statement is a branching
IF, THEN, and ENDIF. This statement is
structure indicated by the keywords
A Formal Denition for the Description of Components
15
translated by rst passing the condition expression to the expression translation
function
E [],
which creates the evaluation code for the condition. The result of
not instruction and then the conditional
iftruegoto with the label ENDIF is emitted. To construct
the code for the THEN-part of the branch statement, the S [] is recursively called.
the evaluation is negated by adding the
jump instruction
At the end of the translation, the previously used label is created, referring to
its succeding instruction. As every sequence of statements ends with a
or
vreturn
return
instruction, it is ensured, that every label has an corresponding
instruction to point at.
E [(exp)] = E [exp]
E [exp1 OR exp2 ] = E [exp1 ] · E [exp2 ] · or
E [exp1 + exp2 ] = E [exp1 ] · E [exp2 ] · add
E [exp1 == exp2 ] = E [exp1 ] · E [exp2 ] · cmpeq
E [f ield1 . · · · .f ieldn := exp] = E [f ield1 . · · · .f ieldn−1 ] · E [exp] ·
· setattribute f ieldn
...
Fig. 17.
The translation function
Translation Function E []
E [],
partially depicted in Figure 17, provides the
translation of expressions. A main pattern to translate binary operators for stack
machines is to rst evaluate the argument expressions and then to emit the instruction for the operator. This function is also used to load and store values from
and to local variables and interface attributes. To store a value in an interface
attribute, the rst
n−1
elds are loaded, followed by the evaluation of the ex-
pression. Then the corresponding store instruction for attributes
setattribute
is emitted, with the last eld as its argument.
6 Conclusion
In this paper, we presented an operational semantics for the component description language DisCComp and its execution environment. We presented the two
steps of the formalisation: the denition and implementation of the abstract machine for the execution of systems based on a DisCComp description and the
mapping of the DisCComp component descriptions to the instruction set of the
abstract machine.
As there is now a well dened semantic for DisCComp a next step could be
the verication of systems based on DisCComp descriptions.
16
Kolatzki, Hagner, Goltz, Rausch
References
1. Aho, A.V., Ullman, J.D.: The Theory of Parsing, Translation, and Compiling.
Addison-Wesley (1972)
2. Alber, K., Struckmann, W.: Einführung in die Semantik von Programmiersprachen.
Reihe Informatik Band 59, BI-Wissenschaftsverlag (1988)
3. Atkinson, C., Bayer, J., Muthig, D.: Component-based product line development:
The kobra approach. In: Software Product Line Conference, 2000. pp. 289309.
Kluwer Academic Publishers (2000)
4. Belblidia, N., Debbabi, M.: A dynamic operational semantics for jvml. Journal
of Object Technology 6(3), 71100 (March - April 2007), http://www.jot.fm/
contents/issue_2007_03/article2.html
5. Bruneton, E., Coupaye, T., Leclercq, M., Quéma, V., Stefani, J.B.: The fractal
component model and its support in java. Software: Practice and Experience 36(1112), 12571284 (2006), http://dx.doi.org/10.1002/spe.767
6. Bure², T., Hn¥tynka, P., Plá²il, F.: Sofa 2.0: Balancing advanced features in a
hierarchical component model. In: Software Engineering Research, Management
and Applications, 2006. Fourth International Conference on. pp. 4048 (aug 2006)
7. Crnkovic, I., Sentilles, S., Vulgarakis, A., Chaudron, M.: A classication framework
for software component models. Software Engineering, IEEE Transactions on 37(5),
593 615 (sept-oct 2011)
8. Eddon, G., Eddon, H.: Inside COM+. Microsoft Press Deutschland (1999)
9. Feljan, J., Lednicki, L., Maras, J., Petricic, A., Crnkovic, I.: Classication and survey of component models (ISSN 1404-3041 ISRN MDH-MRTC-242/2009-1-SE), 1
61 (2009), http://www.mrtc.mdh.se/index.php?choice=publications&id=2099
10. Lindholm, T., Yellin, F.: The Java Virtual Machine Specication. Addison-Wesley,
2nd edition edn. (1999)
11. Louden, K.C.: Programming Languages - Principles and Practice. Brooks/ColeThomson Learning, 2nd edition edn. (2003)
12. Object Management Group OMG: Common object request broker architecture
(corba) specication (August 2011), http://www.omg.org/spec/CORBA/3.1.1/
Components/PDF
13. Parr, T.: ANTLR, http://www.antlr.org/
14. Parr, T., Fisher, K.: LL(*): The foundation of the antlr parser generator. In: Proceedings of the 32nd ACM SIGPLAN conference on Programming language design
and implementation. pp. 425436. PLDI '11 (2011)
15. Rausch, A., Informatik, F., Softwarearchitektur, A., Kaiserslautern, T.U.: Disccomp - a formal model for distributed concurrent components (2006)
16. Reussner, R., Becker, S., Happe, J., Koziolek, H., Krogmann, K., Kuperberg, M.:
The palladio component model. Tech. rep., Universität Karlsruhe (2007)
17. Rubinger, A.L., Burke, B.: Enterprise JavaBeans 3.1. O'Reilly Media, 6th edn.
(Oktober 2010)
18. Stärk, R.F., Schmid, J., Börger, E.: Java and the Java Virtual Machine: Denition,
Verication, Validation. Springer Verlag (2001)
19. Szyperski, C., Gruntz, D., Murer, S.: Component software: beyond object-oriented
programming. Addison-Wesley Professional (2002)
20. Wenger, R.: Handbuch der .NET 4.0-Programmierung, vol. 1. Microsoft-Press (July
2010)
A Formal Denition for the Description of Components
A Complete DisCComp Syntax
system
mapping
map
fqname
usedcomponents
initialization
component
interface
connection
attribute
message
method
postcondition
invariant
let
implies
bounds
typelist
typeandname
type
statementsequence
statement
ifstatement
thenpart
elsepart
connect
disconnect
parexpression
expression
impliesExpression
xorExpression
orExpression
`SYSTEM' ID usedcomponents initialization ?
mapping *
::= `MAPPING OF' fqname `TO' fqname map *
::= `MAP' ID `TO' ID
::= ID (`::' ID)*
::= `USED COMPONENTS' ID (`,' ID)*
::= `INITIALIZATION' statementsequence
::= `COMPONENT' ID `PROVIDED' interface *
(`REQUIRED' interface *)?
::= `INTERFACE' ID bounds (connection | attribute |
message | method | invariant )*
::= `CONNECTION' ID `END' typeandname bounds
::= `ATTRIBUTE' typeandname (`CALCULATED BY'
statementsequence )?
::= `MESSAGE' ID typelist statementsequence
postcondition *
::= `METHOD' ID typelist (`:' ID)? statementsequence
postcondition *
::= `POST' ID `(' `)' statementsequence
::= `INVARIANT' ID `(' `)' statementsequence let ?
implies ?
::= `LET' statementsequence
::= `IMPLIES' statementsequence
::= `[' INT `,' (INT | WILDCARD) `]'
::= `(' (typeandname (`,' typeandname )* )? `)'
::= ID `:' type
::= `Void' | `Boolean' | `Integer' | `Real' | `String' |
`Array' | fqname
::=
statement `;')*
ifstatement | expression
::= `IF' parexpression thenpart elsepart ? `ENDIF'
::= `THEN' statementsequence
::= `ELSE' statementsequence
::= `CONNECT' primary `AND' primary `BY' fqname
::= `DISCONNECT' primary `AND' primary `BY' fqname
::= (
::=
`(' expression `)'
impliesExpression (`:=' expression )?
::= xorExpression (`IMPLIES' xorExpression )?
::= orExpression (`XOR' orExpression )?
::= andExpression (`OR' andExpression )?
::=
::=
17
18
Kolatzki, Hagner, Goltz, Rausch
equalityExpression (`AND' equalityExpression )?
relationalExpression
((`==' | `<>') relationalExpression )?
relationalExpression::= addExpression
((`<=' | `<' | `>' | `>=') addExpression )?
addExpression
::= multExpression ((`+' | `-') multExpression )?
multExpression
::= unaryExpression ((`*' | `/') unaryExpression )?
unaryExpression ::= unaryNotExpression
| (`+' | `-') unaryExpression
unaryNotExpression::= primary | `NOT' unaryExpression
primary
::= parexpression | literal | eldOrCall | typeandname
| creator | connect | disconnect
eldOrCall
::= eld (`.' eld )* callPostx ?
callPostx
::= `(' expression (`,' expression )* (`|' expression )?
`)'
| `.'iterationcall
eld
::= ID (`@PAST' | `@PRE')? arrayaccess ?
+
arrayaccess
::= (`[' INT `]')
iterationCall
::= `iterate' `(' typeandname iterInit ? `|' expression
`)'
iterInit
::= `;' expression
creator
::= `NEW' (fqname | `Array of' type )
literal
::= INT | REAL | STRING | BOOL | NULL
andExpression
equalityExpression
BOOL
NULL
ID
INT
REAL
EXPONENT
STRING
ESCSEQ
::=
::=
`true' | `false'
`null'
::= (`a'. . . `z' | `A'. . . `Z' | `_') (`a'. . . `z' | `A'. . . `Z' |
`0'. . . `9' | `_')*
+
::= (`0'. . . `9')
+
::= (`0'. . . `9') `.' (`0'. . . `9')* EXPONENT?
| `.' (`0'. . . `9')* EXPONENT?
+
| (`0'. . . `9') EXPONENT
+
::= (`e' | `E') (`+' | `-')? (`0'. . . `9')
::= `' (ESCSEQ | ∼ (`\' | `') )* `'
::= `\' (`b' | `t' | `n' | `f' | `r' | `' | `'' | `\')
::=
::=
A Formal Denition for the Description of Components
B Complete DisCComp Abstract Machine Semantic
B.1
Interpretation Functions
N : IN T → Z
R : REAL → R
B : BOOL → B
S : ST RIN G → String
V : IN T ∪ REAL ∪ BOOL ∪ ST RIN G → Z ∪ R ∪ B ∪ String
V [n] = N [n]
V [n.o ∗ 10p ] = R[n, o, p]
V [ s ] = S [s]
V [true] = B [true]
V [f alse] = B [f alse]
N [0] = 0
N [1] = 1
N [2] = 2
N [3] = 3
N [4] = 4
N [5] = 5
N [6] = 6
N [7] = 7
N [8] = 8
N [9] = 9
N [n0] = 10 ∗ N [n] + 0
N [n1] = 10 ∗ N [n] + 1
N [n2] = 10 ∗ N [n] + 2
N [n3] = 10 ∗ N [n] + 3
N [n4] = 10 ∗ N [n] + 4
N [n5] = 10 ∗ N [n] + 5
N [n6] = 10 ∗ N [n] + 6
N [n7] = 10 ∗ N [n] + 7
N [n8] = 10 ∗ N [n] + 8
N [n9] = 10 ∗ N [n] + 9
N̂ [0n] = 0.1 ∗ N̂ [n] + 0
N̂ [1n] = 0.1 ∗ N̂ [n] + 0.1
N̂ [2n] = 0.1 ∗ N̂ [n] + 0.2
N̂ [3n] = 0.1 ∗ N̂ [n] + 0.3
N̂ [4n] = 0.1 ∗ N̂ [n] + 0.4
N̂ [5n] = 0.1 ∗ N̂ [n] + 0.5
N̂ [6n] = 0.1 ∗ N̂ [n] + 0.6
N̂ [7n] = 0.1 ∗ N̂ [n] + 0.7
N̂ [8n] = 0.1 ∗ N̂ [n] + 0.8
N̂ [9n] = 0.1 ∗ N̂ [n] + 0.9
R[n, o, p] = (N [n] + N̂ [o]) · 10N [p]
B [true] = >
B [f alse] = ⊥
B [v1 ∨ v2 ] = B [v1 ] ∨ B [v2 ]
B [v1 ∧ v2 ] = B [v1 ] ∧ B [v2 ]
B [v1 IM P LIES v2 ] = ¬B [v1 ] ∨ B [v2 ]
B [v1 XOR v2 ] = (B [v1 ] ∨ B [v2 ]) ∧ ¬(B [v1 ] ∧ B [v2 ])
19
20
Kolatzki, Hagner, Goltz, Rausch
B [v1
>,
>,
= v2 ] =
>,
⊥,
if
if
if
V [v1 ] ∈ R ∧ V [v2 ] ∈ R ∧ V [v1 ] = V [v2 ]
V [v1 ] ∈ String ∧ V [v2 ] ∈ String ∧ V [v1 ] = V [v2 ]
v1 ∈ L ∧ v2 ∈ L ∧ v1 .loc = v2 .loc
else
B [v1 6= v2 ] = ¬B [v1 = v2 ]
(
>, wenn V [v1 ] ∈ R ∧ V [v2 ] ∈ R ∧ V [v1 ] < V [v2 ]
B [v1 < v2 ] =
⊥, sonst
(
>, wenn V [v1 ] ∈ R ∧ V [v2 ] ∈ R ∧ V [v1 ] ≤ V [v2 ]
B [v1 ≤ v2 ] =
⊥, sonst
(
>, wenn V [v1 ] ∈ R ∧ V [v2 ] ∈ R ∧ V [v1 ] > V [v2 ]
B [v1 > v2 ] =
⊥, sonst
(
>, wenn V [v1 ] ∈ R ∧ V [v2 ] ∈ R ∧ V [v1 ] ≥ V [v2 ]
B [v1 ≥ v2 ] =
⊥, sonst
B.2
Instruction Set of the DisCComp Abstract Machine
Codef ile := N0 → DecInstr ∪ F ktInstr
DecInstr
map sourceN ame targetN ame
include componentN ame
| ccomponent name
| cinterface name lowerBound upperBound
| cmethod name returnT ype paramCount varCount startP os
| cmessage name paramCount varCount startP os
| cattribute name type varCount startP os
| cconnection name endN ame type lowerBound upperBound
| cinvariant name inf N ame varCount startP os
| cpostcondition name inf N ame mthN ame varCount startP os
:=
|
F ktInstr
:=
|
|
|
|
|
|
|
|
load index
add
mul
neg
and
xor
cmpeq
cmplt
cmpgt
store index
sub
| div
| or
| implies
| not
| cmpneq
| cmple
| cmpge
|
|
A Formal Denition for the Description of Components
|
|
|
|
|
|
|
|
|
|
|
|
B.3
load
| store
aload
| astore
anew
| asize
return
| vreturn
pop
| dup
swap
| const wert
atpre
| atpast
getattribute atrN ame | setattribute atrN ame
invokesync mthN ame | invokeasync mthN ame
new type
| iftruegoto index
newconnection type
| deleteconnection type
violation
Environment and Conguration
Environment :=
Component :=
Interf ace
:=
Attribute
:=
M ethod
:=
<
/* statischer Anteil */
components:
String → Component,
interf aces:
String → Interf ace,
methods:
String → M ethod,
connections:
String → Connection,
invariants:
String → M ethod∗ ,
postconditions: String × String → M ethod∗ ,
nameM ap:
String → String,
lastComponent: Component,
lastInterf ace: Interf ace,
/* dynamischer Anteil */
threads:
T hread∗ ,
activeT hread:
T hread,
nextSnapshotId: N0 ,
snapshots:
Location × N → Object ∪ Array >
name:
String,
interf aces:
Interf ace∗ >
< name:
String,
parent:
Component,
attributes:
String → Attribute,
connections:
String → Connection,
lowerBound:
N0 ,
upperBound:
N0 ∪ {−1}>
< name:
String,
type:
String,
localV ariableCount: N0 ,
code:
N0 → DecInstr ∪ F ktInstr>
< name:
String,
<
21
22
Kolatzki, Hagner, Goltz, Rausch
Connection :=
inf :
Interf ace,
code:
N0 → DecInstr ∪ F ktInstr,
parameterCount:
N0 ,
localV ariableCount: N0 ,
isAsync:
B>
< endN ame:
String,
endT ype:
String,
lowerBound:
N0 ,
upperBound:
N0 ∪ {−1}>
f rameStack :
F rame∗ ,
activeF rame:
F rame,
pastSnapshot:
N0 ∪ {−1},
currentSnapshot: N0 >
< method:
M ethod,
preSnapshot:
N0 ∪ {−1},
programCounter: N0 ∪ {−1},
preP arameters: V alue∗ ,
localV ariables: V alue∗ ,
operandStack :
V alue∗ >
IN T ∪ REAL ∪ BOOL ∪
ST RIN G ∪ Location ∪ N ull
T hread
:= <
F rame
:=
V alue
:=
Location :=
N,
N ∪ {UNCHANGED}>
< loc:
sn:
N ull
0,
:= < loc:
sn:
UNCHANGED>
Object
:= < type:
Array
:= < size:
attributes:
values:
B.4
String,
String → V alue>
N0 ,
N0 → V alue>
Rules for Operations on Local Variables
m.code(pc) = load i
v = getLocalV ariable(l, i)
o0 = v :: o
0
pc = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(5)
A Formal Denition for the Description of Components
23
m.code(pc) = load i
m.code(pc + 1) = atpre
v = getLocalV ariable(preP aram, i)
o0 = v :: o
pc0 = pc + 2
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(6)
m.code(pc) = store i
v = getStackElement(o, 1)
l0 = setLocalV ariable(l, i, v)
o0 = popStack(o, 1)
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l0 , o0 :: Σ, pastSn, currentSn :: Θ
B.5
(7)
Rules for Array Access
m.code(pc) = aload
index = getStackElement(o, 1)
loc = getStackElement(o, 2)
(
arr =
Sn(loc, currentSn)
Sn(loc, loc.sn)
wenn loc.sn = U N CHAN GED
sonst
v = arr.values(index)
o0 = popStack(o, 1)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o00 :: Σ, pastSn, currentSn :: Θ
(8)
24
Kolatzki, Hagner, Goltz, Rausch
m.code(pc) = astore
value = getStackElement(o, 3)
index = getStackElement(o, 2)
loc = getStackElement(o, 3)
arr = Sn(loc, currentSn)
arr0 = ensureSize(arr, index)
arr00 = arr0 [index 7→ value]
0
Sn = Sn[(loc, currentSn) 7→ arr00 ]
o0 = popStack(o, 3)
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn0 , m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(9)
m.code(pc) = asize
loc = getStackElement(o, 1)
arr = Sn(loc, currentSn)
v = arr.size
0
o = popStack(o, 1)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o00 :: Σ, pastSn, currentSn :: Θ
(10)
m.code(pc) = anew
loc = newLocation(Sn)
arr = newArray()
Sn0 = Sn[(loc, currentSn) 7→ arr]
o0 = loc :: o
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn0 , m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(11)
A Formal Denition for the Description of Components
B.6
25
Rules for Operators
m.code(pc) = add
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = V [arg1] + V [arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(12)
m.code(pc) = sub
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = V [arg1] − V [arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(13)
m.code(pc) = mul
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = V [arg1] ∗ V [arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(14)
m.code(pc) = div
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = V [arg1]/V [arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(15)
26
Kolatzki, Hagner, Goltz, Rausch
m.code(pc) = neg
arg = getStackElement(o, 1)
v = −V [arg ]
0
o = popStack(o, 1)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(16)
m.code(pc) = or
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 ∨ arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(17)
m.code(pc) = and
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 ∧ arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(18)
m.code(pc) = implies
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 IM P LIES arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(19)
A Formal Denition for the Description of Components
27
m.code(pc) = xor
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 XOR arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(20)
m.code(pc) = not
arg = getStackElement(o, 1)
v = ¬B[arg ]
0
o = popStack(o, 1)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(21)
m.code(pc) = cmpeq
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 = arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(22)
m.code(pc) = cmpneq
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 6= arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(23)
28
Kolatzki, Hagner, Goltz, Rausch
m.code(pc) = cmplt
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 < arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(24)
m.code(pc) = cmple
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 ≤ arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(25)
m.code(pc) = cmpgt
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 > arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(26)
m.code(pc) = cmpge
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
v = B[arg1 ≥ arg2]
o0 = popStack(o, 2)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(27)
A Formal Denition for the Description of Components
B.7
29
Rules for the Stack Management
m.code(pc) = pop
0
o = popStack(o, 1)
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(28)
m.code(pc) = swap
arg1 = getStackElement(o, 1)
arg2 = getStackElement(o, 2)
o0 = popStack(o, 2)
00
o = arg2 :: arg1 :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o00 :: Σ, pastSn, currentSn :: Θ
(29)
m.code(pc) = dup
arg = getStackElement(o, 1)
o0 = arg :: o
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(30)
m.code(pc) = const v
o0 = v :: o
0
pc = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(31)
30
B.8
Kolatzki, Hagner, Goltz, Rausch
Rules for Accessing Interfaces
m.code(pc) = getattribute n
loc = getStackElement(o, 1)
(
obj =
Sn(loc, currentSn)
Sn(loc, loc.sn)
wenn loc.sn = U N CHAN GED
sonst
v = obj.attributes(n)
o0 = popStack(o, 1)
o00 = v :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o00 :: Σ, pastSn, currentSn :: Θ
(32)
m.code(pc) = setattribute n
loc = getStackElement(o, 2)
v = getStackElement(o, 1)
obj = Sn(loc, currentSn)
obj 0 = obj
0
obj .attributes = obj.attributes[n 7→ v]
Sn0 = Sn[(loc, currentSn) 7→ obj 0 ]
o0 = popStack(o, 2)
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn0 , m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(33)
m.code(pc) = atpre
loc = getStackElement(o, 1)
loc0 = loc
loc0 .sn = preSn
0
o = popStack(o, 1)
o00 = loc0 :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o00 :: Σ, pastSn, currentSn :: Θ
(34)
A Formal Denition for the Description of Components
31
m.code(pc) = atpast
loc = getStackElement(o, 1)
loc0 = loc
0
loc .sn = pastSn
0
o = popStack(o, 1)
o00 = loc0 :: o0
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o :: Σ, pastSn, currentSn :: Θ
B.9
(35)
Rules for Interface and Connection Management
m.code(pc) = new s
loc = newLocation(Sn)
inf = E.interf aces(s)
obj = newObject(inf )
0
Sn = Sn[(loc, currentSn) 7→ obj]
o0 = loc :: o
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn0 , m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(36)
m.code(pc) = newconnection s
sourceLoc = getStackElement(o, 2)
targetLoc = getStackElement(o, 1)
o0 = popStack(o, 2)
conn = E.connections(s)
conn.upperBound = 1
sourceObj = Sn(sourceLoc, currentSn)
sourceObj 0 = sourceObj
0
sourceObj .attributes = sourceObj.attributes[conn.endN ame 7→ targetLoc]
Sn0 = Sn[sourceLoc 7→ sourceObj 0 ]
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn0 , m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(37)
32
Kolatzki, Hagner, Goltz, Rausch
m.code(pc) = newconnection s
sourceLoc = getStackElement(o, 2)
targetLoc = getStackElement(o, 1)
o0 = popStack(o, 2)
conn = E.connections(s)
conn.upperBound > 1
sourceObj = Sn(sourceLoc, currentSn)
sourceObj 0 = sourceObj
sourceObj.attributes(conn.endN ame) = N ull
loc = newLocation(Sn)
arr = newArray()
arr0 = ensureSize(arr, 0)
arr00 = arr0 [0 7→ targetLoc]
Sn0 = Sn[(loc, currentSn) 7→ arr00 ]
0
sourceObj .attributes = sourceObj.attributes[conn.endN ame 7→ loc]
Sn00 = Sn0 [sourceLoc 7→ sourceObj 0 ]
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn00 , m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(38)
m.code(pc) = newconnection s
sourceLoc = getStackElement(o, 2)
targetLoc = getStackElement(o, 1)
o0 = popStack(o, 2)
conn = E.connections(s)
conn.upperBound > 1
sourceObj = Sn(sourceLoc, currentSn)
sourceObj 0 = sourceObj
sourceObj.attributes(conn.endN ame) 6= N ull
loc = sourceObj.attributes(conn.endN ame)
arr = Sn(loc, currentSn)
arr0 = ensureSize(arr, arr.size)
arr00 = arr0 [arr.size 7→ targetLoc]
Sn0 = Sn[(loc, currentSn) 7→ arr00 ]
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn0 , m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(39)
A Formal Denition for the Description of Components
33
m.code(pc) = deleteconnection s
sourceLoc = getStackElement(o, 2)
o0 = popStack(o, 2)
conn = E.connections(s)
conn.upperBound = 1
sourceObj = Sn(sourceLoc, currentSn)
sourceObj 0 = sourceObj
0
sourceObj .attributes = sourceObj.attributes[conn.endN ame 7→ N ull]
Sn0 = Sn[sourceLoc 7→ sourceObj 0 ]
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn0 , m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(40)
m.code(pc) = deleteconnection s
sourceLoc = getStackElement(o, 2)
o0 = popStack(o, 2)
conn = E.connections(s)
conn.upperBound > 1
sourceLoc.attributes(conn.endN ame) = N ull
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(41)
34
Kolatzki, Hagner, Goltz, Rausch
m.code(pc) = deleteconnection s
sourceLoc = getStackElement(o, 2)
targetLoc = getStackElement(o, 1)
o0 = popStack(o, 2)
conn = E.connections(s)
conn.upperBound > 1
sourceLoc.attributes(conn.endN ame) 6= N ull
loc = sourceObj.attributes(conn.endN ame)
arr = Sn(loc, currentSn)
0
arr = removeV alue(arr, targetLoc)
Sn0 = Sn[(loc, currentSn) 7→ arr0 ]
pc0 = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn0 , m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
B.10
(42)
Rules for Function- Calls and Returns
m.code(pc) = invokesync n
method = E.methods(n)
argLen = method.parameterCount
args = getStackElementList(o, argLen)
loc = getStackElement(o, argLen + 1)
Sn0 = mergeSnapshot(Sn, currentSn)
newSn = E.nextSnapshotId
00
Sn = createSnapshot(Sn0 , newSn)
o0 = popStack(o, argLen + 1)
pc0 = pc + 1
f = newF rame(method, args, newSn, currentSn)
t = f :: m, preSn, pc0 , preP aram, l, o0 :: Σ, currentSn, newSn
0
t00 :: Θ0 = chooseT hread(t0 :: Θ)
E0 = E
0
E .nextSnapshotId = E.nextSnapshotId + 1
E 0 .activeT hread = t00
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
0
E , Sn00 , t00 :: Θ0
(43)
A Formal Denition for the Description of Components
35
m.code(pc) = invokeasync n
method = E.methods(n)
argLen = method.parameterCount
args = getStackElementList(o, argLen)
loc = getStackElement(o, argLen + 1)
newSn = E.nextSnapshotId
Sn0 = createSnapshot(Sn0 , newSn)
o0 = popStack(o, argLen + 1)
pc0 = pc + 1
f = newF rame(method, args, newSn, currentSn)
t0 = newT hread(f, newSn)
t00 :: Θ0 = chooseT hread(t0 :: Θ)
E0 = E
E 0 .nextSnapshotId = E.nextSnapshotId + 1
E 0 .activeT hread = t00
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
0
E , Sn0 , t00 :: Θ0
(44)
m.code(pc) = return
0
Sn = mergeSnapshot(Sn, currentSn)
newSn = E.nextSnapshotId
00
Sn = createSnapshot(Sn0 , newSn)
t0 = {Σ, currentSn, newSn}
t00 :: Θ0 = chooseT hread(t0 :: Θ)
E0 = E
E 0 .nextSnapshotId = E.nextSnapshotId + 1
E 0 .activeT hread = t00
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
0
E , Sn00 , t00 :: Θ0
(45)
36
Kolatzki, Hagner, Goltz, Rausch
m.code(pc) = vreturn
Sn0 = mergeSnapshot(Sn, currentSn)
newSn = E.nextSnapshotId
Sn00 = createSnapshot(Sn0 , newSn)
v = getStackElement(o, 1)
t0 =
o0 = v :: ō
m̄, preSn, pc, preP aram, ¯
l, o0 :: Σ, currentSn, newSn
t00 :: Θ0 = chooseT hread(t0 :: Θ)
E0 = E
E 0 .nextSnapshotId = E.nextSnapshotId + 1
E 0 .activeT hread = t00
hE, Sn, {{m, preSn, pc, preP aram, l, o} ::
m̄, preSn, pc, preP aram, ¯
l, ō :: Σ, pastSn, currentSn} :: Θi →
0
E , Sn00 , t00 :: Θ0
B.11
(46)
Rules for Controlow
m.code(pc) = iftruegoto i
v = getStackElement(o, 1)
o0 = popStack(o, 1)
B[v ] = >
pc0 = i
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
(47)
m.code(pc) = iftruegoto i
v = getStackElement(o, 1)
o0 = popStack(o, 1)
B[v ] = ⊥
0
pc = pc + 1
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, m, preSn, pc0 , preP aram, l, o0 :: Σ, pastSn, currentSn :: Θ
m.code(pc) = violation s
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
V IOLAT ION (s)
(48)
(49)
A Formal Denition for the Description of Components
B.12
37
Helper-Functions
In diesem Kapitel werden die in den Inferenzregeln verwendeten Hilfsfunktionen
genauer speziziert.
newComponent
newComponent : String → Component
(
component.name = name
newComponent(name) = component if
component.interf aces =::
newInterface
newInterf ace : String × N × N × Component → Interf ace
inf.name = n
inf.parent = p
inf.attributes = f : f (x) = undef ined
newInterf ace(n, l, u, p) = inf if
inf.connections = g : g(x) = undef ined
inf.lowerBound = l
inf.upperBound = u
newAttribute
newAttribute : String × String × N × N × CodeF ile → Attribute
attrib.name = n
attrib.type = t
newAttribute(n, t, l, c, f ) = attrib if
attrib.localV ariableCount = l
attrib.code = g : g(x) = f (c + x)
newMethod
newM ethod : String × Interf ace × N0 × N0 × N0 × B × CodeF ile → M ethod
method.name = n
method.inf = i
method.parameterCount = p
newM ethod(n, i, p, l, c, a, f ) = method if
method.localV ariableCount = l
method.isAsync = a
method.code = g : g(x) = f (c + x)
38
Kolatzki, Hagner, Goltz, Rausch
newConnection
newConnection : String × N0 × N0 ∪ {−1} → M ethod
conn.endN ame = n
newConnection(n, l, u) = conn if conn.lowerBound = l
conn.upperBound = u
newFrame
newF rame : M ethod × V alue∗ × N0 ∪ {−1} × N → F rame
f rame.method = m
f rame.preSnapshot = p
f rame.programCounter = 0
newF rame(m, l, c, p) = f rame if
f rame.preP arameters = l
f rame.localV ariables = l
f rame.operandStack =::
newThread
newT hread : F rame × N → T hread
thread.threadStack = f ::
newT hread(f, c) = thread if thread.pastSnapshot = −1
thread.currentSnapshot = c
head
head : V alue∗ → V alue
head(v :: l) = v, ∀(v, l) ∈ V alue × V alue∗
tail
tail : V alue∗ → V alue∗
tail(∅) = ∅
tail(v :: l) = l, ∀(v, l) ∈ V alue × V alue∗
A Formal Denition for the Description of Components
39
getStackElement
getStackElement : V alue∗ × N → V alue
getStackElement(l, 1) = head(l)
getStackElement(l, i) = getStackElement(tail(l), i − 1), ∀i > 1
getStackElementList
getStackElementList : V alue∗ × N → V alue∗
getStackElementList(l, 0) =::
getStackElementList(l, i) = head(l) :: getStackElementList(tail(l), i − 1), ∀i > 0
popStack
popStack : V alue∗ × N → V alue∗
popStack(l, 0) = l
popStack(l, i) = popStack(tail(l), i − 1), ∀i > 0
getLocalVariable
getLocalV ariable : V alue∗ × N → V alue
getLocalV ariable(l, 0) = head(l)
getLocalV ariable(l, i) = getLocalV ariable(tail(l), i − 1), ∀i > 0
setLocalVariable
setLocalV ariable : V alue∗ × N × V alue → V alue∗
setLocalV ariable(l, 0, v) = v :: tail(l)
setLocalV ariable(l, i, v) = head(l) :: setLocalV ariable(tail(l), i − 1, v), ∀i > 0
mergeSnapshot
mergeSnapshot : Snapshot × N → Snapshot
∀l l : Location ∧ Sn(l, i) 6= undef ined
sn[(l, 0) 7→ mergeObject(Sn(l, 0), Sn(l, i))]
mergeSnapshot(Sn, i) = sn if
∀j, ∀l j > 0 ∧ l : Location
sn[(l, j) 7→ Sn(l, j)]
40
Kolatzki, Hagner, Goltz, Rausch
mergeObject
mergeObject : Object × Object → Object
mergeObject(o1 , o2 ) =
o2
o1
undef ined
o
o1 =undef ined∧
o2 6=undef ined
o2 =undef ined∧
o1 6=undef ined
o1 =undef ined∧
o2 =undef ined
o.type = o1 .type
o.attributes = ∀s, s ∈ String∧
if
∧o1 .attributes(s) 6= undef ined :
o1 .attributes[s 7→ o2 .attributes(s)]
sonst
createSnapshot
createSnapshot : Snapshot × N → Snapshot
∀l l : Location
sn[(l, i) 7→ Sn(l, 0)]
createSnapshot(Sn, i) = sn if
∀j j 6= i, ∀l l : Location
sn[(l, j) 7→ Sn(l, j)]
newLocation
newLocation : Snapshot → Location
(
newLocation(Sn) = location
if
location.sn = UNCHANGED ∧
∀i ∈ N0 Sn(location, i) = undef ined
newObject
newObject : Interf ace → Object
00 00
obj.type = inf.parent.name + / + inf.name
∀s, s ∈ String ∧ inf.attributes(s) 6= undef ined
newObject(inf ) = obj if
obj.attributes[s 7→ initV alue(inf.attributes(s).type)]
∀t, t ∈ String ∧ inf.connections(t) 6= undef ined
obj.attributes[t 7→ 0]
A Formal Denition for the Description of Components
41
newArray
newObject : Array
(
arr.size = 0
newArray() = arr if
∀t, t ∈ N0 arr.values(t) = undef ined
ensureSize
ensureSize : Array × N0 → Array
ret.size >= size
∀i, i ∈ N0 ∧ i <= arr.size
ensureSize(arr, size) = ret if
ret.values(i) = arr.values(i)
∀i, i ∈ N0 ∧ i <= size ∧ i > arr.size
ret.values[i 7→ 0]
removeValue
removeV alue : Array × V alue → Array
removeV alue(removeOneV alue(arr, n))
removeV alue(arr, value) =
∃n ∈ N0 (arr.values(n) = value)
arr
wenn
sonst
removeOneValue
removeOneV alue : Array × N0 → Array
arr0 .size = arr.size − 1
∀n ∈ N0 , n < value
0
removeOneV alue(arr, value) = arr if
arr0 .values(n) = arr.values(n)
∀m ∈ N0 , m >= value ∧ m < arr.size
arr0 .values(m) = arr.values(m + 1)
initValue
initV alue : String → V alue
initV alue(type) =
0
0.0
00
f alse
null
, wenn
, wenn
, wenn
, wenn
, sonst
type = Integer
type = Real
type = String
type = Boolean
42
Kolatzki, Hagner, Goltz, Rausch
chooseThread
chooseT hread : T hread∗ → T hread :: T hread∗
(
chooseT hread(T ) = t :: T 0
B.13
if
t∈T
T 0 = T \t
Rules for System Initialisation
codeF ile(pc) ∈ F ktInstr
pc0 = pc + 1
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc0 :: Γ
codeF ile(pc) = undef ined
hE, hcodeF ile, pci :: Γ i → hE, Γ i
Γ =∅
hE, Γ i → IN IT COM P LET E
(50)
(51)
(52)
codeF ile(pc) = include s
codeF ile0 = loadF ile(s)
pc0 = 0
hE, hcodeF ile, pci :: Γ i →
E, codeF ile, pc0 :: hcodeF ile, pci :: Γ
(53)
Rules for Declaration Instructions
codeF ile(pc) = ccomponent s
comp = newComponent(s)
E0 = E
0
E .components = E.components[s 7→ comp]
E 0 .lastComponent = comp
pc0 = pc + 1
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc0 :: Γ
(54)
A Formal Denition for the Description of Components
43
codeF ile(pc) = cinterface s i1 i2
inf = newInterface(s, i1 , i2 , E.lastComponent)
E0 = E
E 0 .interf aces[s 7→ inf ]
E 0 .lastInterf ace = inf
pc0 = pc + 1
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc0 :: Γ
(55)
codeF ile(pc) = cattribute s1 s2 i1 i2
attrib = newAttribute(s2 , i1 , i2 , E.lastInterface, codeFile)
E0 = E
0
inf = E.lastInterf ace
0
inf .attributes = E.lastInterf ace.attributes[s 7→ attrib]
E 0 .interf aces = E.interf aces[s1 7→ inf 0 ]
E 0 .lastInterf ace = inf 0
pc0 = pc + 1
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc0 :: Γ
(56)
codeF ile(pc) = cconnection s1 s2 s3 i1 i2
conn = newConnection(s1 , s2 , s3 , i1 , i2 , E.lastInterface)
E0 = E
inf 0 = E.lastInterf ace
0
inf .connections = E.lastInterf ace.connections[s2 7→ conn]
E 0 .interf aces = E.interf aces[inf 0 .name 7→ inf 0 ]
E 0 .connections = E.connections[s1 7→ conn]
E 0 .lastInterf ace = inf 0
pc0 = pc + 1
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc0 :: Γ
(57)
codeF ile(pc) = cmethod s1 s2 i1 i2 i3
meth = newMethod(s1 , E.lastInterface, i1 , i2 , i3 , ⊥ , codeFile)
E0 = E
E 0 .methods = E.methods[s1 7→ meth]
pc0 = pc + 1
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc0 :: Γ
(58)
44
Kolatzki, Hagner, Goltz, Rausch
codeF ile(pc) = cmessage s1 i1 i2 i3
meth = newMethod(s1 , E.lastInterface, i1 , i2 , i3 , > , codeFile)
E0 = E
0
E .methods = E.methods[s1 7→ meth]
0
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc
:: Γ
pc0 = pc + 1
(59)
codeF ile(pc) = cinvariant s1 s2 i1 i2
meth = newMethod(s1 , E.lastInterface, 0, i1 , i2 , ⊥ , codeFile)
E0 = E
invs = E.invariants(s2 )
0
E .invariants = E.invariants[s2 7→ invs ∪ {meth}]
0
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc
:: Γ
pc0 = pc + 1
(60)
codeF ile(pc) = cpostcondition s1 s2 s3 i1 i2
meth = newMethod(s1 , E.lastInterface, 0, i1 , i2 , ⊥ , codeFile)
E0 = E
postc = E.postconditions(s2 , s3 )
0
E .postconditions = E.postconditions[s2 × s3 7→ postc ∪ {meth}]
pc0 = pc + 1
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc0 :: Γ
(61)
codeF ile(pc) = map s1 s2
E0 = E
0
E .nameM ap = E.nameM ap[s1 7→ s2 ]
pc0 = pc + 1
hE, hcodeF ile, pci :: Γ i → E, codeF ile, pc0 :: Γ
(62)
A Formal Denition for the Description of Components
B.14
45
Modied Rules for Contract Checks
m.code(pc) = invokesync n
method = E.methods(n)
argLen = method.parameterCount
args = getStackElementList(o, argLen)
loc = getStackElement(o, argLen + 1)
o0 = popStack(o, argLen + 1)
pc0 = pc + 1
f = newF rame(method, args, newSn, currentSn)
t = f :: m, preSn, pc0 , preP aram, l, o0 :: Σ, currentSn, newSn
0
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, t0 :: Θ0
(63)
m.code(pc) = return
0
t = {Σ, currentSn, newSn}
hE, Sn, {{m, preSn, pc, preP aram, l, o} :: Σ, pastSn, currentSn} :: Θi →
E, Sn, t0 :: Θ0
(64)
m.code(pc) = vreturn
v = getStackElement(o, 1)
t0 =
o0 = v :: ō
m̄, preSn, pc, preP aram, ¯
l, o0 :: Σ, currentSn, newSn
hE, Sn, {{m, preSn, pc, preP aram, l, o} ::
m̄, preSn, pc, preP aram, ¯
l, ō :: Σ, pastSn, currentSn} :: Θi →
E, Sn, t0 :: Θ0
C Complete Translation Denition
C [SYSTEM cmps init mapping ] =C [cmps] · C [init] · C [mapping ]
C [USED COMPONENTS {cmp1 . . . cmpn }] =include cmp1 · . . . · include cmp2
C [INITIALIZATION stm] =S [stm]
C [MAPPING OF name1 TO name2 maps] =map name1 name2 · C [maps, name1 , name2 ]
C [{map1 , . . . , mapn }, src, trg ] =C [map1 , src, trg ] · . . . · C [mapn , src, trg ]
C [MAP name1 TO name2 , src, trg ] =map src#name1 trg#name2
C [COMPONENT name provided required] =ccomponent name · C [provided] · C [required]
(65)
46
Kolatzki, Hagner, Goltz, Rausch
C [PROVIDED {inf1 , . . . , infn }] =C [inf1 , ⊥] · . . . · C [infn , ⊥]
C [REQUIRED {inf1 , . . . , infn }] =C [inf1 , >] · . . . · C [infn , >]
C [INTERFACE name [l, u] {e1 , . . . , en }, r ] =cinterface name l u · C [e1 , r, name] · . . . · C [en , r, name]
C [INTERFACE name [l, ∗] {e1 , . . . , en }, r ] =cinterface name l − 1 · C [e1 , r, name] · . . . · C [en , r, name]
C [CONNECTION name END end : type [l, u], ⊥, inf ] =cconnection name end type l u
C [CONNECTION name END end : type [l, ∗], ⊥, inf ] =cconnection name end type l − 1
C [ATTRIBUTE name type, ⊥, inf ] =cattribute name type 0 − 1
C [ATTRIBUTE name type CALCULATED BY stm, ⊥, inf ] =cattribute name type .numV ars(stm)
calc · S [stm] · load
calc·
.varId( result ) · vreturn
C [METHOD name (args) stm, ⊥, inf ] =cmethod name U nit |args| .numV ars(stm)
calc · S [stm] · return
C [METHOD name (args) : ret stm, ⊥, inf ] =cmethod name ret |args| .numV ars(stm)
calc · S [stm] · load
calc·
calc·
.varId( result ) · vreturn
C [MESSAGE name (args) stm, ⊥, inf ] =cmessage name |args| .numV ars(stm)
calc · S [stm] · return
C [INVARIANT name exps let implies, inf ] =cinvariant name inf .numV ars(let)
calc · E [exps] · not · iftruegoto end·
S [let] · E [implies] · iftruegoto end·
violation name · end · return
calc·
calc·
C [CONNECTION name END end : type [l, u], >, inf ] =
C [ATTRIBUTE name type, >, inf ] =
C [METHOD name (args) stm {p1 , . . . , pn }, >, inf ] =C [p1 , inf, name] · . . . · C [pn , inf, name]
C [METHOD name (args) : ret stm {p1 , . . . , pn }, >, inf ] =C [p1 , inf, name] · . . . · C [pn , inf, name]
C [MESSAGE name (args) stm {p1 , . . . , pn }, >, inf ] =C [p1 , inf, name] · . . . · C [pn , inf, name]
C [POSTCONDITION name {stm1 , . . . , stmn }, inf, mth] =cpostcondition name inf mth
calc
.numV ars({stm1 , . . . , stmn })
·
not·
S [stm1 ] · iftruegoto
,wenn .boolExpr(stm1 )
,sonst
err
· ...·
S [stmn ] ·
not·
iftruegoto
err
noErr·
noErr
· const true · iftruegoto
err · violation
name ·
S [; ] =
S [{stm1 . . . stmn }] =S [stm1 ] · . . . · S [stmn ]
S [IF (exp) THEN stm ENDIF;] =E [exp] · not · iftruegoto
S [stm] ·
endif
,wenn
,sonst
endif·
.boolExpr(stmn )
A Formal Denition for the Description of Components
S [IF (exp) THEN stm1 ELSE stm2 ENDIF;] =E [exp] · not · iftruegoto
else·
S [stm1 ] · const true · iftruegoto
else · S [stm2 ] · endif
endif·
S [CONNECT exp1 AND exp2 BY name; ] =E [exp1 ] · E [exp2 ] · newconnection name
S [DISCONNECT exp1 AND exp2 BY name; ] =E [exp1 ] · E [exp2 ] · deleteconnection name
S [exp; ] =E [exp]
E [{exp1 , . . . , expn }] =E [exp1 ] · and · . . . · and · E [expn ]
E [(exp)] =E [exp]
E [exp1 IMPLIES exp2 ] =E [exp1 ] · E [exp2 ] · implies
E [exp1 XOR exp2 ] =E [exp1 ] · E [exp2 ] · xor
E [exp1 OR exp2 ] =E [exp1 ] · E [exp2 ] · or
E [exp1 AND exp2 ] =E [exp1 ] · E [exp2 ] · and
E [exp1 == exp2 ] =E [exp1 ] · E [exp2 ] · cmpeq
E [exp1 <> exp2 ] =E [exp1 ] · E [exp2 ] · cmpneq
E [exp1 <= exp2 ] =E [exp1 ] · E [exp2 ] · cmple
E [exp1 < exp2 ] =E [exp1 ] · E [exp2 ] · cmplt
E [exp1 > exp2 ] =E [exp1 ] · E [exp2 ] · cmpgt
E [exp1 >= exp2 ] =E [exp1 ] · E [exp2 ] · cmpge
E [exp1 + exp2 ] =E [exp1 ] · E [exp2 ] · add
E [exp1 - exp2 ] =E [exp1 ] · E [exp2 ] · sub
E [exp1 * exp2 ] =E [exp1 ] · E [exp2 ] · mul
E [exp1 / exp2 ] =E [exp1 ] · E [exp2 ] · div
E [+exp] =E [exp]
E [-exp] =E [exp] · neg
E [NOT exp] =E [exp] · not
E [lit] =const lit
E [NEW name] =new name
E [NEW Array of name] =anew
E [f ield1 ] · . . . · E [f ieldn ]
,wenn .isLocalV ar(f ield ) ∨ f ield = self
1
1
E [f ield1 . · · · .f ieldn ] =
E [self ] · E [f ield1 ] · . . . · E [f ieldn ]
,sonst
E [f ield1 . · · · .f ieldn .f kt(exp1 , . . . , expn )] =E [f ield1 . · · · .f ieldn ] · E [f kt(exp1 , . . . , expn )]
E [exp1 ] · . . . · E [expn ]·
(
invokeasync f kt ,wenn .isAsyncCall(f kt)
invokesync f kt
,sonst
E [self ] =load 0
(
E [f ield] =
load .varId(f ield)
getattribute f ield
,wenn
.islocalV ar(f ield)
,sonst
E [f ield[index]] =E [f ield] · const index · aload
E [f ield@P AST ] =E [f ield] · atpast
E [f ield@P RE ] =E [f ield] · atpre
E [localV ar := exp] =E [exp] · store .varId(localV ar)
47
48
Kolatzki, Hagner, Goltz, Rausch
E [f ield1 . · · · .f ieldn := exp] =E [f ield1 . · · · .f ieldn−1 ] · E [exp] · setattribute f ieldn
E [f ield1 . · · · .f ieldn [index] := exp] =E [f ield1 . · · · .f ieldn ] · const index · E [exp] · astore
E [f ld1 . · · · .f ldn .iterate(var; init|exp)] =E [f ld1 . · · · .f ldn ] · E [init] · const 0 · store .counterId ·
check·
dup · asize · load .counterId · swap · cpmge · iftruegoto done·
dup · load .counterId · aload · store .varId(var) · E [exp]·
dup · load .counterId · load .varId(var) · astore·
const 1 · load .counterId · add · store .counterId·
const true · iftruegoto check · done · pop
E [f ld1 . · · · .f ldn .f orall(var|exp)] =E [f ld1 . · · · .f ldn ] · const 0 · store .counterId · check·
dup · asize · load .counterId · swap · cpmge · iftruegoto noValue·
dup · load .counterId · aload · store .varId(var) · E [exp]·
const 1 · load .counterId · add · store .counterId·
iftruegoto check · pop · const f alse·
const true · iftruegoto exit · noValue · pop · const true · exit
E [f ld1 . · · · .f ldn .exists(var|exp)] =E [f ld1 . · · · .f ldn ] · const 0 · store .counterId · check·
dup · asize · load .counterId · swap · cpmge · iftruegoto noValue·
dup · load .counterId · aload · store .varId(var) · E [exp] · not·
const 1 · load .counterId · add · store .counterId·
iftruegoto check · pop · const true·
const true · iftruegoto exit · noValue · pop · const f alse · exit
E [f ld1 . · · · .f ldn .any(var|exp)] =E [f ld1 . · · · .f ldn ] · const 0 · store .counterId · check·
dup · asize · load .counterId · swap · cpmge · iftruegoto noValue·
dup · load .counterId · aload · store .varId(var) · E [exp] · not·
const 1 · load .counterId · add · store .counterId·
iftruegoto check · pop · loac .varId(var)·
const true · iftruegoto exit · noValue · pop · const null · exit
Technische Universität Braunschweig
Informatik-Berichte ab Nr. 2009-05
2009-05
A. Rausch, U. Goltz, G. Engels,
M. Goedicke, R. Reussner
LaZuSo 2009: 1. Workshop für langlebige und
zukunftsfähige Softwaresysteme 2009
2009-06
T. Müller, M. Lochau, S. Detering,
F. Saust, H. Garbers, L. Märtin,
T. Form, U. Goltz
Umsetzung eines modellbasierten durchgängigen
Enwicklungsprozesses für AUTOSAR-Systeme mit
integrierter Qualitätssicherung
2009-07
M. Huhn, C. Knieke
Semantic Foundation and Validation of Live Activity
Diagrams
2010-01
A. Litvinenko and H. G. Matthies
Sparse data formats and efficient numerical methods for
uncertainties quantification in numerical aerodynamics
2010-02
D. Grunwald, M. Lochau,
E. Börger, U. Goltz
An Abstract State Machine Model for the Generic Java
Type System
2010-03
M. Krosche, R. Niekamp
Low-Rank Approximation in Spectral Stochastic Finite
Element Method with Solution Space Adaption
2011-01
L. Märtin, M. Schatalov, C. Knieke
Entwicklung und Erweiterung einer Werkzeugkette im
Kontext von IT-Ökosystemen
2011-02
B. V. Rosić, A. Litvinenko,
O. Pajonk, H. G. Matthies
Direct Bayesian update of polynomial chaos
representations
2011-03
H. G. Matthies
White Noise Analysis for Stochastic Partial Differential
Equations
2011-04
O. Pajonk, B.V. Rosić,
A. Litvinenko, and H. G. Matthies
A Deterministic Filter for non-Gaussian Bayesian
Estimation
2011-05
H. G. Matthies
A Hitchhiker’s Guide to Mathematical Notation and
Definitions
2011-06
R. van Glabbeek, U. Goltz,
J.-W. Schicke
On Causal Semantics of Petri Nets
2011-07
H. Cichos, S. Oster, M. Lochau,
A. Schürr
Extended Version of Model-based Coverage-Driven Test
Suite Generation for Software Product Lines
2011-08
W.-B. Pöttner, J. Morgenroth,
S. Schildt, L. Wolf
An Empirical Performance Comparison of DTN Bundle
Protocol Implementations
2011-09
H. G. Matthies, A. Litvinenko,
O. Pajonk, B. V. Rosić and
E. Zander
Parametric and Uncertenty Computations with Tensor
Product Representations
2011-10
B. V. Rosić, A. Kučerová,
J. Sýkora, A. Litvinenko,
O. Pajonk and H. G. Matthies
Parameter Identification in a Probabilistic Setting
2011-11
M. Espig, W. Hackbusch, A.
Litvinenko, H. G. Matthies and
E. Zander
Efficient Analysis of High Dimensional Data in Tensor
Formats
2011-12
S. Oster
A Semantic Preserving Feature Model to CSP
Transformation
2012-01
O. Pajonk, B. V. Rosić and
H. G. Matthies
Deterministic Linear Bayesian Updating of State and
Model Parameters for a Chaotic Model
2012-02
B. V. Rosić and H. G. Matthies
Stochasticc Plasticity - A Variational Inequality
Formulation and Functional Approximation Approach I:
The Linear Case
2012-03
J. Rang
An analysis of the Prothero–Robinson example for
constructing new DIRK and ROW methods
2012-04
S. Kolatzki, M. Hagner, U. Goltz
and A. Rausch
A Formal Definition for the Description of Distributed
Concurrent Components - Extended Version
© Copyright 2026 Paperzz