6. imperative and object-oriented programs

113
6. Imperative and Object- oriented Programs From: Chapter 6, Modern Compiler Design, by Dick Grunt et al.

Upload: maddox

Post on 12-Jan-2016

26 views

Category:

Documents


0 download

DESCRIPTION

6. Imperative and Object-oriented Programs. From: Chapter 6, Modern Compiler Design , by Dick Grunt et al. Introduction. Much of the compiler construction is independent of the source code paradigm Still paradigm-specific techniques. Introduction. Roadmap - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 6.  Imperative and Object-oriented Programs

6. Imperative and Object-oriented Programs

From: Chapter 6, Modern Compiler Design, by Dick Grunt et al.

Page 2: 6.  Imperative and Object-oriented Programs

Imperative & OO 2

Introduction

• Much of the compiler construction is independent of the source code paradigm

• Still paradigm-specific techniques

Page 3: 6.  Imperative and Object-oriented Programs

Imperative & OO 3

Page 4: 6.  Imperative and Object-oriented Programs

Imperative & OO 4

Introduction

Roadmap

6. Imperative and object-oriented programs6.1 Context handling

6.1.1 Identification

6.1.2 Type checking

6.2 Source language data representation and handling6.2.1 Basic types to 6.2.9 Object types

6.3 Routines and their activation

6.4 Code generation for control flow statements

6.5 Code generation for modules

Page 5: 6.  Imperative and Object-oriented Programs

Imperative & OO 5

6.1 Context handling

• lexical syntactic context • Context handling is concerned with long-distance relations:

– E.g., relating the type of a variable in a declaration to its use in an expression

• The first task of the context phase:– Taking the annotated syntax tree and to find the defining occurrence of

each applied occurrence of an identifier or operator in the program

• The second task of the context phase:– Performing the context checking on each node of the tree, as specified by

the rules in the language definition.

• Context handling is also called semantic checking,– Emphasizing the meaning for correct meaning more than for correct

context use

Page 6: 6.  Imperative and Object-oriented Programs

Imperative & OO 6

6.1.1 Identification

• Identification is the process of finding the defining occurrence of a given applied occurrence of an identifier or operator.

month: integer RANGE[1..12];…month:=1;WHILE month<=12 DO print_string(month_name[month]); month:=month+1;DONE;

Defining occurrence

The remaining month are applied occurrences.

Page 7: 6.  Imperative and Object-oriented Programs

Imperative & OO 7

6.1.1 Identification

• Symbol table (or name list)– All information about an item is collected.

– It is the task of the identification process to connect all occurrences of an identifier to its proper entry.

• Not all identifiers must be looked up in the same set of entries:– E.g., variables must be looked up among the local and global identifiers,

– Field selectors must be looked up among the field selectors of a given type, etc.

• Each of these sets of entries define a name space, and – the syntactic positions of variable names, routine names, and some others

live in one name space, the general name space, and

– Field selectors live in a special name spaces belonging to records types.

Page 8: 6.  Imperative and Object-oriented Programs

Imperative & OO 8

6.1.1 Identification

• The first i in i.i is looked up in the general space, leading to its identification as a variable of type struct one_int.

• The second i is then looked up in the special name space of the field selector of the type struct one_int.

struct one_int_ int i;} i; … i.i=3

Page 9: 6.  Imperative and Object-oriented Programs

Imperative & OO 9

6.1.1 Identification

• In principle, any position that can be distinguished syntactically or contextually can have its own name space.

• C has three main name spaces– One containing all the names of enums, structs, and unions,

– One containing labels, and

– One containing the rest, including variable identifiers, routine identifiers, type identifiers, and enumeration value identifiers.

• In addition, C has a name space for each struct and each union;– These name spaces contain only the field selectors of the corresponding st

ruct and untions.

Page 10: 6.  Imperative and Object-oriented Programs

Imperative & OO 10

6.1.1.1 Scopes

• The scopes work in in stack fashion:– There is a stack of scope elements,

– One for each scope entered, and

– All actions are performed on the top element(s).

• The rules:– A new empty scope element is stacked upon scope entry;

– Declared identifiers are entered in the top scope element;

– Applied identifiers are looked up in the scope elements from top to bottom; and

– The top element is removed upon scope exit, thus removing all declarations from that scope.

Page 11: 6.  Imperative and Object-oriented Programs

Imperative & OO 11

Page 12: 6.  Imperative and Object-oriented Programs

Imperative & OO 12

6.1.1.1 Scopes

• The organization shown in Fig. 6.2 is simple and intuitive, but lacks two features essential for use in a practical compiler:– No provisions for name spaces and

– Not use the fast symbol table access

Page 13: 6.  Imperative and Object-oriented Programs

Imperative & OO 13

Page 14: 6.  Imperative and Object-oriented Programs

Imperative & OO 14

Page 15: 6.  Imperative and Object-oriented Programs

Imperative & OO 15

Page 16: 6.  Imperative and Object-oriented Programs

Imperative & OO 16

Page 17: 6.  Imperative and Object-oriented Programs

Imperative & OO 17

6.1.1.2 Overloading

• If all identifiers in a scope hide the identifiers with the same names in older scopes, identification is relatively simple:– the definition record pointed at by the decl field in Fig. 6.4 provides the

definition sought.

• If overloading is allowed, identifiers do not hide all identifiers with the same name:

PUT(s: STRING)does not hide PUT(i: INTEGER) in Ada3 + 5 integer addition3.1 + 5.1 floating point addition

Page 18: 6.  Imperative and Object-oriented Programs

Imperative & OO 18

6.1.1.2 Overloading

• The ambiguity caused by the overloading is resolved by considering the context in which the name to be identified occurs.

• Two issues here:1. In the presence of overloading the identifiers the identifier identification

process comes up with a set of definitions, rather than with a single identification.

• The definitions are selected from the list of definitions supplied by the decl field in Fig. 6.4.

• The rules for selecting such a set of definitions from the list of all definitions depend on the source language.

2. Concerning the reduction of this set to a single definition• If more than one definition remains, the identifier is ambiguous;• if no applicable definition remains, it is undefined; and• if exactly one definition remains, it is the definition of the identifier in the giv

en context.

Page 19: 6.  Imperative and Object-oriented Programs

Imperative & OO 19

6.1.1.2 Overloading

• Example: to identify the PUT in PUT(“Hello”)Assume the scope stack:

level 1: procedure PUT(String) = P64; procedure PUT(Matrix) = P57;level 0: procedure PUT(Integer) = P48; procedure PUT(String) = P33; procedure PUT(FILE_TYPE, INTEGER) = P27; procedure PUT(FILE_TYPE, STRING) = P14;

procedure PUT(String) = P64;procedure PUT(Matrix) = P57;procedure PUT(Integer) = P48;procedure PUT(FILE_TYPE, INTEGER) = P27;procedure PUT(FILE_TYPE, STRING) = P14;

The call Identify(“PUT”) will return the list

Compiler rejects them because of type or number mismatch.

Page 20: 6.  Imperative and Object-oriented Programs

Imperative & OO 20

6.1.2 Type checking

• Looking up an identifier leading to an information record– The most basic property is the kind of the object

• a constant, a variable, a routine, a type, a module, etc.

– The first step in checking the proper use of the identifier is checking this property.

• Some of the kids specify objects that involve values, for example, constants, variables, and routines.– types: sets of values and operations

– type checking for such objects is not trivial at all

Page 21: 6.  Imperative and Object-oriented Programs

Imperative & OO 21

6.1.2 Type checking

• Type checking is involved in large part of the annotated syntax tree:– rules specifying which types can be combined with a certain operator;

– rules for formal and actual parameter types in a routine call; and

– assigning an expression values to variable

• Type information in a compiler has to be implemented in such a way that all these and many other checks can be performed conveniently.

Page 22: 6.  Imperative and Object-oriented Programs

Imperative & OO 22

6.1.2 Type checking

• Types are usually introduced by name through type declarations.

TYPE Int_Array = ARRAY [Integer 1..10] OF Integer;VAR a: ARRAY [Integer 1..10] OF Real; /* Anonymous */

TYPE #type01_in_line_35 = ARRAY [Integer 1..10] OF Integer;VAR a: #type01_in_line_35;

• Forward references:

TYPE Ptr_List_Entry = POINTER TO List_Entry;TYPE List_Entry = RECORD Element: Integer; Next: Ptr_List_Entry; END RECORD;

Page 23: 6.  Imperative and Object-oriented Programs

Imperative & OO 23

6.1.2.1 The type table

• All types in a compilation unit are collected in a type table, each entry containing:– its type constructor (‘basic’, ‘record’, ‘array’, ‘pointer’, and others);

– the size and alignment requirements of a variable of the type;

– the types of the components, if applicable.

• Various information is being recorded for types:– for a basic type: its precise type (integer, real, etc.);

– for a record type: the list of the record fields, with their names and types;

– for an array type: the number of dimensions, the index type(s), and the element type;

– for a pointer type: the reference type;

– for other type constructor: the appropriate information.

Page 24: 6.  Imperative and Object-oriented Programs

Imperative & OO 24

6.1.2.1 The type table

• The type table entry must contain all the type information required to perform the type checking and code generation.– The exact content therefore depends on the source language at hand.

– The representation in the compiler, on the other hand, depends on the implementation language, the language in which the compiler is written.

– In an imperative implementation language: the representation of a type is a record with a variant part.

– In an OO implementation language: a type would be a an object class with all fields and methods that all type constructors share, and each type constructor would have its own subclass, with extension specific for the type constructor at hand.

Page 25: 6.  Imperative and Object-oriented Programs

Imperative & OO 25

6.1.2.1 The type table

• DemonstrationType constructors: record and

pointer

Built-in type: integer

Before starting processing the input:

Type table: Symbol table:

TYPE 0: INTEGER “integer”: TYPE 0

Page 26: 6.  Imperative and Object-oriented Programs

Imperative & OO 26

6.1.2.1 The type table

Let us process the following type declarations:

Type table: Symbol table:

TYPE 0: INTEGER “integer”: TYPE 0

TYPE 1: ID_REF “b” a: TYPE 1

b: UNDEFINED_TYPE

TYPE a = b;TYPE b = POINTER TO a;TYPE c = d;TYPE d = c;

After the first type declaration, TYPE a = b;

Page 27: 6.  Imperative and Object-oriented Programs

Imperative & OO 27

6.1.2.1 The type table

Let us process the following type declarations:

Type table: Symbol table:

TYPE 0: INTEGER “integer”: TYPE 0

TYPE 1: ID_REF “b” a: TYPE 1

TYPE 2: ID_REF “a” b: TYPE 3

TYPE 3: POINTER TO TYPE 2

TYPE a = b;TYPE b = POINTER TO a;TYPE c = d;TYPE d = c;

After the type declaration, TYPE b = POINTER TO a;

Page 28: 6.  Imperative and Object-oriented Programs

Imperative & OO 28

6.1.2.1 The type table

Let us process the following type declarations:

Type table: Symbol table:

TYPE 0: INTEGER “integer”: TYPE 0

TYPE 1: ID_REF “b” a: TYPE 1

TYPE 2: ID_REF “a” b: TYPE 3

TYPE 3: POINTER TO TYPE 2 C: TYPE 4

TYPE 4: ID_REF “d” D: TYPE 5

TYPE 5: ID_REF “c”

TYPE a = b;TYPE b = POINTER TO a;TYPE c = d;TYPE d = c;

After the last two type declarations,

Page 29: 6.  Imperative and Object-oriented Programs

6.1.2.1 The type table

• Now that the input have been processed, all identifier references must be resolved. Because of1. Cycle detection

2. Unique indexing in the type table

• Steps:1. Replacing the identifier references in the type table by type reference:

• A reference to an entry in the symbol table which refers to an entry in the type table is replaced by a direct reference to this type table entry

Type table: Symbol table:

TYPE 0: INTEGER “integer”: TYPE 0

TYPE 1: TYPE 3 a: TYPE 1

TYPE 2: TYPE 1 b: TYPE 3

TYPE 3: POINTER TO TYPE 2 C: TYPE 4

TYPE 4: TYPE 5 D: TYPE 5

TYPE 5: TYPE 4

Page 30: 6.  Imperative and Object-oriented Programs

Imperative & OO 30

6.1.2.1 The type table

• Steps:2. Cycle detection by the closure algorithm

Page 31: 6.  Imperative and Object-oriented Programs

6.1.2.1 The type table

Type table: Symbol table:

TYPE 0: INTEGER “integer”: TYPE 0

TYPE 1: TYPE 3 a: TYPE 3

TYPE 2: TYPE 3 b: TYPE 3

TYPE 3: POINTER TO TYPE 2 C: TYPE 4

TYPE 4: ERRONEOUS_TYPE D: TYPE 5

TYPE 5: ERRONEOUS_TYPE

Type table: Symbol table:

TYPE 0: INTEGER “integer”: TYPE 0

TYPE 1: TYPE 3 a: TYPE 1

TYPE 2: TYPE 3 b: TYPE 3

TYPE 3: POINTER TO TYPE 2 C: TYPE 4

TYPE 4: TYPE 4 D: TYPE 5

TYPE 5: TYPE 4

Page 32: 6.  Imperative and Object-oriented Programs

Imperative & OO 32

6.1.2.2 Type equivalence

• Two kinds of type equivalence: name equivalence and structural equivalence

• Name equivalence– Two types are name-equivalent when they have the same name

TYPE t1 = ARRAY [Integer] OF Integer;TYPE t2 = ARRAY [Integer] OF Integer;

TYPE t3 = ARRAY [Integer] OF Integer;TYPE t4 = t3;

Not name-equivalent

Name-equivalent

• Implementing a name equivalence check is easy: – Check whether the same index in the type table

Page 33: 6.  Imperative and Object-oriented Programs

Imperative & OO 33

6.1.2.2 Type equivalence

• Structural equivalence– Two types are structure-equivalent when variable of these types can

assume the same values and allow the same operations.

TYPE t5 = RECORD c: Integer; p: POINTER TO t5; END RECORD; TYPE t6 = RECORD c: Integer; p: POINTER TO t6; END RECORD;TYPE t7 = RECORD c: Integer; p: POINTER TO RECORD c: Integer; p: POINTER TO t5; END RECORD; END RECORD; /* t5, t6, t7 are all S. E. */

• Difficult to implement and is hardly used anymore.

Page 34: 6.  Imperative and Object-oriented Programs

Imperative & OO 34

6.1.2.3 Coercions

• An implicit data and type conversions

• Exactly which coercions the compiler can insert depends on the language.

• The presence of coercions complicates operator and routine identification, because– Operand and result type may need to be coerced to another type, before a

matching identification can be found.

Page 35: 6.  Imperative and Object-oriented Programs

Imperative & OO 35

6.1.2.3 Coercions

• Finding the proper coercions in an AST, for a language with arbitrary sets of types, contexts, and coercions, is a very difficult problem, for which no solution has yet been found.

• The approach here is similar to the one used in Section 6.1.1.2 to handle overloading of identifiers, and works for moderately complicated coercions rules.1. Finds all types in each node that might play a role,

2. Crosses out all inapplicable types

3. In the end any type set in a node is empty, no identification could be made, and if any of the type set contains more than one element, an ambiguity has been detected.

Page 36: 6.  Imperative and Object-oriented Programs

Imperative & OO 36

6.1.2.4 Cast and conversions

• A cast specified the required type explicitly.

• A cast differs from an explicit conversion in that it still uses the coercion system of the language.

• In contrast, an explicit conversion is a function which transforms data of one type to that of another types.

Page 37: 6.  Imperative and Object-oriented Programs

Imperative & OO 37

6.1.2.5 Kind checking

• Kind checking is trivial, but the complication arises from the fact that the actual kinds we are concerned with are locations and values rather than constants and variables.

Page 38: 6.  Imperative and Object-oriented Programs

Imperative & OO 38

Page 39: 6.  Imperative and Object-oriented Programs

Imperative & OO 39

6.2 Source language data representation and handling

• Discuss some of the data structures that represent source language data at run time, and the run-time manipulation needed to deal with the source language operation on these data.

• In the source language, a data item has a type, which may be a basic built-in type of the language, or a constructed type, built using one of the type constructors in the language.

• The target language data types are usually limited to single bytes, integers of various sizes, address representations, and floating point numbers of several sizes.

Page 40: 6.  Imperative and Object-oriented Programs

Imperative & OO 40

6.2 Source language data representation and handling

• Every source language data type is mapped to a particular combination of target language data types, and the run-time representation of a source language data item is the result of application of this mapping.

• It is the task of compiler writer to create such a mapping.

• We assume here that the target language has the common arithmetic, comparison, and copy operations, and has a byte-addressable memory.

Page 41: 6.  Imperative and Object-oriented Programs

Imperative & OO 41

6.2.1 Basic types

• Usual basic types in source language:– Characters,

– integers of several sizes, and

– Floating point numbers of several sizes.

• Operation on these types– Addition,

– Subtraction,

– Multiplication,

– Division and

– Remainder

• All of these can be mapped directly to the target language data types and operations.

Page 42: 6.  Imperative and Object-oriented Programs

Imperative & OO 42

6.2.1 Basic types

• Some source languages have a void type, corresponding to no value at all.

• A target representation for a void type is not needed.

Page 43: 6.  Imperative and Object-oriented Programs

Imperative & OO 43

6.2.2 Enumeration types

• An enumeration type defines a set of names to be the values of the new data type.

• Run-time representation– Integer, ranging from 0 to total number minus 1

• Allowed operations– Copying,

– Comparison for equality, greater, smaller,

– Increment/decrement

– All available in the target language

• Boolean type– true and false– 0 for false 1 for true

Page 44: 6.  Imperative and Object-oriented Programs

Imperative & OO 44

6.2.3 Pointer types

• Pointers represent the address of source language data structures.

• Run-time representation– An unsigned integer of a size large enough to represent address

• The integer operations for copying, assignment, comparisons, etc, are available for pointer as well.– Some target machines have special instruction for addressing modes for

dealing with pointers.

Page 45: 6.  Imperative and Object-oriented Programs

Imperative & OO 45

6.2.3 Pointer types

• Dereferencing– Obtaining the value of data structure the pointer refers to– If the value to be obtained is small enough to fit in a register,

• Dereferencing can be implemented as a single machine instruction,

– Otherwise, • The situation is complicated, e.g., array, structure.

• Dereferencing, theoretically, delivers values on top of the working stack,– However, it is more efficient to find out the final destination, e.g., q=*p;,

is translated as

byte_copy(&q, p, sizeof(T));

Page 46: 6.  Imperative and Object-oriented Programs

Imperative & OO 46

6.2.3 Pointer types

• When dereferencing is used only for field selection

• For the implementation of the latter case:– First, dereferencing ptr on the top of the working stack

– Then replacing the top of the stack by the selected field

– Or, compiler computes the pointer to the field, and then dereferences that pointer (*ptr).field as *(&(ptr->.field)).

ptr->field, or (*ptr).field

Page 47: 6.  Imperative and Object-oriented Programs

Imperative & OO 47

6.2.3.1 Bad pointers

• Dangers making pointers hard to use1. The pointer was never initialized;

2. The pointer is a null pointer, normally used to indicate the absence of a value, but the programmer forgot to check;

3. The pointer once referred to a value, but that value was located on the heap and has been removed since by a free() operation, leaving a pointer dangling;

4. The pointer once referred to a value, but that value was located in the activation record of a routine that has been terminated, leaving a pointer dangling;

Page 48: 6.  Imperative and Object-oriented Programs

Imperative & OO 48

6.2.3.1 Bad pointer

• Languages differ in their approach to bad pointers.– C: the best one can hope pf any of the above errors is that program crashes

before it produces incorrect results.

– The memory management unit (MMU) of most processors will generate an exception if pointer is null (error 2)

• But the behavior for error 1 is erratic

• Pointers of types 3 and 4 are good, no MMU assistance can be expected for them.

• Avoiding pointers is a good way to solve pointer problem, like Java and functional and logic languages, but require a lot of programming support.

Page 49: 6.  Imperative and Object-oriented Programs

Imperative & OO 49

6.2.3.1 Bad pointer

• Bad pointers elimination by the language design view– Automatic initialization of pointer (error 1)

– Error 2 can be eliminated by creating two kind of constructors special to pointer: ‘pointers’, and ‘references’.

– Having a garbage collector and disallowing calls to free(0) eliminates dangling pointers to the heap (error 3).

– Disallowing pointers to local variables eliminates other dangling pointers (error 4).

Page 50: 6.  Imperative and Object-oriented Programs

Imperative & OO 50

6.2.3.2 Pointer scope rules

• Error 4 is the most problematic, since a good pointer turns into a dangling pointer through a routine exit, an action that is only remotely associated with the pointer.

Page 51: 6.  Imperative and Object-oriented Programs

Imperative & OO 51

6.2.4 Record types

• A fixed number of members of possibly different types are grouped together.

• Address alignment; gap insertion

struct example { int member1; double member2;};

member1

member2

member1

member2

gap

Page 52: 6.  Imperative and Object-oriented Programs

Imperative & OO 52

6.2.4 Record types

• The mandatory operations on record types– Field selection;

• Adding the offset of the field within the record and accessing that address

– Copying• Copying all field individually, or by copying the whole record, including the

gaps

– Field comparisons• Can be done field by field.

struct example { int member1; double member2;};

int compare_example(struct example *s1, struct example *s2){ if (s1->member1 != s2->member1) return 0; if (s1->member2 != s2->member2) return 0; retturn 1;}

Page 53: 6.  Imperative and Object-oriented Programs

Imperative & OO 53

6.2.5 Union types

• A union type is a data type of which the values are one of a set of types.

union{ int I; float f;}… a.i … /* access the value of type int */… a.f … /* access the value of type float */

• Undiscriminated vs. discriminated unions

• The run-time representation is like a record, except that all fields overlap.– Size= the size of the largest field

• Field selection of an undiscriminated union: offset 0

• Copying: a memory copy of the size of the union

Page 54: 6.  Imperative and Object-oriented Programs

Imperative & OO 54

6.2.6 Array types

• An array type – Series of items of the same type

– 1D (vector), 2D(matrix), or more

– One or m ore index expressions

• Run-time representation:– A consecutive sequence of the representation of the elements, starting

from the base address

– Row-major order

– Column-major order

• Element section, or indexing, A[i1, i2, …, in]

base(A)+((i1-LB1)LEN2LEN3…LENn

+((i2-LB2)LEN3…LENn + … +((in-LBn)el_size

Page 55: 6.  Imperative and Object-oriented Programs

Imperative & OO 55

6.2.6 Array types

• Array descriptor

Page 56: 6.  Imperative and Object-oriented Programs

Imperative & OO 56

6.2.7 Set types

• Set types– Usually limited to sets of a small subrange of integers

• Best implemented as bitsets– In a bitset, each value in the subrange is represneted by a single bit.

• If the bit is set, it is a member of the set; otherwise, not.

– Stored in target machine words

• Operations:– Set union: bitwise OR

– Set intersection: bitwise AND

– Symmetric set difference: bitwise EXCLUSIVE OR

– Set difference: a bitwise NOT followed by a bitwise AND

Page 57: 6.  Imperative and Object-oriented Programs

Imperative & OO 57

6.2.8 Routine types

• In C a routine as data can be implemented simply as a pointer to its code;– An indirect routine call is then used to activate it.

• The best implementation of routines as data in languages that allow more advanced operations on routines.

Page 58: 6.  Imperative and Object-oriented Programs

Imperative & OO 58

6.2.9 Object types

• An object is a record with built-in methods, with some additional features.– Abstract data type

• Basic operations:– Field selection

– Copying

– Method invocation1. The method must be identified, and

2. The call must be made

• Objects have constructors and destructors

• Suppose we have an object class A with methods m1 and m2 and fields a1 and a2.a1

a2m1_Am2_A

Page 59: 6.  Imperative and Object-oriented Programs

Imperative & OO 59

6.2.9 Object types

void m2_A(Class_A *this, int i){ Body of method m2_A, accessing any object fields x as this->x}a.m2(3) m2_A(&a,3)

Page 60: 6.  Imperative and Object-oriented Programs

Imperative & OO 60

6.2.9.1 Feature 1: Inheritance

• Inheritance– Base a class B on a class A, so that B inherits the methods and fields of A,

in addition to its own fields and methods

– Type extension

– A is the parent class of B; B is a subclass of A.

a1

a2b1

m1_A

m2_Am3_B

Run-time representation of class B

Compile-time table of methods for class B

Page 61: 6.  Imperative and Object-oriented Programs

Imperative & OO 61

6.2.9.2 Feature 2: Method overriding

• When a class B extends a class A, it may redefine one or more of A’s methods: method overriding

• The method is declared in the parent class P, and then defined in class P and possibly redefined in any of its subclasses.

• In C and Java,– A virtual method allows the method declaration to occur without a

definition

– Abstract class, in which at least one virtual method occurs

Page 62: 6.  Imperative and Object-oriented Programs

Imperative & OO 62

6.2.9.2 Feature 2: Method overriding

• Assume the method m2 is redefined in class B

m1_A_A

m2_A_Am3_B

m1_A_A

m2_A_Bm3_B_B

m2_A_B: a method m2 declared in class A and defined in class B

• Suppose a: class A, b: class B– a.m2(…)m2_A_A– b.m2(…)m2_A_B

Page 63: 6.  Imperative and Object-oriented Programs

Imperative & OO 63

6.2.9.3 Feature 3: Polymorphism

• Polymorphism– A variable of type ‘pointer to class A’ may actually refer to an object of class A or a

ny of its extension.

• The implementation of this feature requires a new operation, pointer supertyping:

– Converting a pointer to an object of class B to a pointer to an object of a parent class A

class B *b = …class A *a = b; class A *a = convert_ptr_to_B_to_ptr_to_A(b);

• convert_ptr_to_B_to_ptr_to_A() is a compile-time operation.• Because an object of class B starts with the fields of class A, the valte of the pointer

need not be changed and the only effect consists of changing the type of the pointer.

a1

a2b1

Pointer to BPointer to A inside B

Page 64: 6.  Imperative and Object-oriented Programs

Imperative & OO 64

6.2.9.4 Feature 4: Dynamic binding

• p : class A * can actually refer to an object of class B– p.m2 : m2_A_A or m2_A_B ?

– Static binding• p refers to an object of class A m2_A_A• Trivial to implement

– Dynamic binding• if it refers to B m2_A_B• if it refers to A m2_A_A• Used by most of the OO languages

Page 65: 6.  Imperative and Object-oriented Programs

Imperative & OO 65

6.2.9.4 Feature 4: Dynamic binding

• Two significant consequences of dynamic binding– There are two kind of As out there,

• ‘genuine’ As use m2_A_A and• As ‘embedded’ in Bs use m2_A_B• The two can not be distinguished statically.• It follows that from now on, the object representation must include dynamic ty

pe information, telling if it is an A or a B.

– B’s methods require a pointer to B to obtain access to all B’s fields.• As m2 may be called through a pointer of type ’pointer to A’ that dynamically

points to an object of class B, we need another operation, pointer (re)subtyping.

• The method invocation p->m2(3), where p is statically a pointer to an object of class A, could then be translated to

switch (dynamic_type_of(p)){ case Dynamic_class_A: m2_A_A(p,3); break; case Dynamic_class_B: m2_A_B(convert_ptr_to_A_to_ptr_to_B(p),3); break;

Page 66: 6.  Imperative and Object-oriented Programs

Imperative & OO 66

Page 67: 6.  Imperative and Object-oriented Programs

Imperative & OO 67

6.2.9.5 Feature 5: Multiple inheritance

Page 68: 6.  Imperative and Object-oriented Programs

Imperative & OO 68

Page 69: 6.  Imperative and Object-oriented Programs

Imperative & OO 69

6.2.9.6 Feature 5: Dependent multiple inheritance

Page 70: 6.  Imperative and Object-oriented Programs

Imperative & OO 70

Page 71: 6.  Imperative and Object-oriented Programs

Imperative & OO 71

6.3 Routines and their activation

• A routine call1. Supplying a new environment containing at least some temporary memor

y, the local variables;

2. Passing information to the new environment, the parameters;

3. Transfer of the flow of control to the new environment, with guaranteed return;

4. Returning information from the new environment, the return value(s).

Page 72: 6.  Imperative and Object-oriented Programs

Imperative & OO 72

6.3.1 Activation records

• The basic ingredient of a routine activation is the new environment.– The data structure supporting the new environment is the activation recor

d, also called frame.

• An AR holds the data pertinent to an invocation of routine or object method;– It represents an activation and not yet terminated routine.

• It contains – User data

• Local variables, parameters, return values, register contents;

– Administration data• Code address, pointers to other ARs.

Page 73: 6.  Imperative and Object-oriented Programs

Imperative & OO 73

6.3.1 Activation records

• In non-concurrent code, only one of the ARs represents a running routine; all the others are suspended.

• The instruction being executed is located in the code of the running routine and the program counter, PC, points at it.

• The AR of the running routine is indicated by a frame pointer, FP.– The FP is usually resided in a dedicated register.

• We concern here with allocating, deallocating, and otherwise organizing the ARs in an efficient way.– Usually using stack

– Others complicate the use of stack

Page 74: 6.  Imperative and Object-oriented Programs

Imperative & OO 74

6.3.1.1 The content of an activation record

Page 75: 6.  Imperative and Object-oriented Programs

Imperative & OO 75

6.3.2 Routines

• A routine is just a piece of code reachable through a pointer to oits first instruction, its code address.

• Classical subroutine– The code is running…

– S is now running and R suspended …R is then the parent of S …

– When S is finished, R is resumed …

• Other kinds of routines– iterator: a routine that can be suspended temporarily and return to its pare

nt without losing its AR. E.g., Fig. 6.23

– Couroutine: Like the iterator it can suspend itself, but unlike the iterator suspending does not imply a return to the parent but rather transfers the control to a named coroutine. Fig. 6.24

Page 76: 6.  Imperative and Object-oriented Programs

Imperative & OO 76

Page 77: 6.  Imperative and Object-oriented Programs

Imperative & OO 77

Page 78: 6.  Imperative and Object-oriented Programs

Imperative & OO 78

6.3.2 Routines

• Independently of these variants, routines can be global or nested.– The code in a global routine only has access to global entities and to its

own local entities.

– The code of a nested routine, declared on the same level as local variables, has access to these same global and strictly local environment, but also entities declared in lexically intervening routines, as shown in Fig. 6.25

Page 79: 6.  Imperative and Object-oriented Programs

Imperative & OO 79

Page 80: 6.  Imperative and Object-oriented Programs

Imperative & OO 80

6.4 Code generation for control flow statements

• Section 4.2: code generation for expression and basic blocks

• Here: code generation for statements that affect the flow of control, and thus demarcate the basic blocks

• Three level of control flow can be distinguished:– Local flow of control, which determines the statement inside a routine or

method to be executed next (6.4.1);

– Routine calls and method invocations, which perform the parameters transfer and flow-of-control manipulation needed to activate a new routine (6.4.2);

– Non-local lump, which transfer the flow of control out of current running routine into an ancestor routine (6.4.2.3).

Page 81: 6.  Imperative and Object-oriented Programs

Imperative & OO 81

6.4 Code generation for control flow statements

• Assumptions:– All source code expression, with one exception, have already been

evaluated and that the results have been stored in an appropriate place, usually a register.

• The exception: Boolean expressions used for flow control (6.4.1.1)

– The existence of a mechanism in the compiler for allocating temporary variables and labels.

Page 82: 6.  Imperative and Object-oriented Programs

Imperative & OO 82

6.4 Code generation for control flow statements

• To describe the code generation for flow of control, we will use the four statement types below:– A simple goto statement: GOTO label;

– An indirect goto statement: GOTO label register;

– A conditional goto statement, in two forms: • IF condition register THEN GOTO label

and

IF NOT condition register THEN GOTO label;

– An assignment statement: destination := source.

Page 83: 6.  Imperative and Object-oriented Programs

Imperative & OO 83

6.4.1 Local flow control

• The two main mechanisms for influencing the local flow of control in imperative languages and object-oriented languages are– ‘selection’ and ‘repetition’.

• More often they depend on the results of Boolean expressions, and – in many cases it is useful to translate them in special ways.

Page 84: 6.  Imperative and Object-oriented Programs

Imperative & OO 84

6.4.1.1 Boolean expressions in flow of control

• Most BEs are used to affect the flow of control rather than to produce a value;– Call this kind of BEs Boolean control expressions.

• Two reasons to treat BCEs specially:1. Having to do with two properties of machine instructions

• The result of the comparisons in BEs are produced in special condition register, rather than 0/1 register;

• The most usual way of affecting the flow of control is by a conditional jump

/* code for the BE: */comparison code, yielding a condition valueconversion from condition value to Boolean/* code for the conditional jump */conversion from Boolean to condition valuejump on condition value

The code sequence if the BEs are treated in the usual way.But treated specially, the code can Then be avoided.

The second reason to be continued …

Page 85: 6.  Imperative and Object-oriented Programs

Imperative & OO 85

6.4.1.1 Boolean expressions in flow of control

2. Related to property of some programming languages:• Lazy Boolean operators:

– Operator that evaluate operands only when their value is needed

– E.g., && and || operators in C

– Unconditonal evaluation of both expression are produced for expr1 && expr2

code to compute expre1 and loc1

code to compute expre2 and loc2

code for the && operator on loc1 and loc2

• In short, BCEs are tightly interrelated with conditional jumping.

Page 86: 6.  Imperative and Object-oriented Programs

Imperative & OO 86

Page 87: 6.  Imperative and Object-oriented Programs

Imperative & OO 87

6.4.1.1 Boolean expressions in flow of control

• For example, according to Fig. 6.38, the call Generate code for Boolean control expression(

Parse (“i>0 && j>0”), No label, Else label):

Compare_greater I, 0IF NOT condition register THEN GOTO Else labelCompare j, 0IF NOT condition register THEN GOTO Else label

Page 88: 6.  Imperative and Object-oriented Programs

Imperative & OO 88

6.4.1.2 Selection statementsThe if-statement

• General form

IF Boolean expression THEN true sequence ELSE false sequence END IF;

if-statement

Boolean exp. true seq. false seq.

Boolean control code(Boolean expression, 0, false_label) code for true sequenceGOTO end_label;false_label: code for false sequenceend_label:

Boolean control code(Boolean expression, 0, end_label) code for true sequenceGOTO end_label;end_label:

Page 89: 6.  Imperative and Object-oriented Programs

Imperative & OO 89

6.4.1.2 Selection statementsThe case-statement

CASE case expression IN I1: statement sequence1

In: statement sequencen

ELSE else-statement sequenceEND CASE;

Page 90: 6.  Imperative and Object-oriented Programs

Imperative & OO 90

6.4.1.2 Selection statementsThe case-statement

• Using jump table

tmp_case_value := case expression;IF tmp_case_value < Ilow THEN GOTO label_else;IF tmp_case_value > Ihigh THEN GOTO label_else;GOTO table [tmp_case_value – Ilow];

• Case labels organized into a balanced binary tree– Each node of the tree represents one case label I,

– the right branch indicates a subtree with case labels larger than I,

– the left branch indicates a subtree with case labels smaller than I,

label_k:IF tmp_case_value < Ik THEN GOTO label of left branch of node_k;IF tmp_case_value > Ik THEN GOTO label of right branch of node_k;code for statement sequencek

GOTO label_next;

Page 91: 6.  Imperative and Object-oriented Programs

Imperative & OO 91

6.4.1.3 Repetition statementsThe while-statement

WHILE Boolean expression DO statement sequence END WHILE;

test_label: Boolean control code (Boolean expression, 0, end_label); code for statement sequence; GOTO test_label;end_label;

GOTO test_label;sequence_label: code for statement sequence;test_label; Boolean control code (Boolean expression, sequence_label, 0);

Page 92: 6.  Imperative and Object-oriented Programs

Imperative & OO 92

6.4.1.3 Repetition statementsThe for-statement

FOR I IN lower bound .. Upper bound DO statement sequence END FOR;

i := lower bound;tmp_ub := upper bound;WHILE i<= tmp_ub DO code for statement sequence i := i +1;END WHILE;

i := lower bound;tmp_ub := upper bound;IF I > tmp_ub THEN GOTO end_label;loop_label: code for statement sequence IF I = tmp_ub THEN GOTO end_label; i := i +1; GOTO loop_label;End_label:

Page 93: 6.  Imperative and Object-oriented Programs

Imperative & OO 93

6.4.1.3 Repetition statementsThe for-statement

• More general for of for-statementFOR I IN 1..6 STEP 2

DO …

END FOR;

Page 94: 6.  Imperative and Object-oriented Programs

Imperative & OO 94

6.4.2 Routine invocation

• Routine calls and object method invocation

• Two issues in calling a routine– Routine identification

– How to perform the call and return

• Non-local goto statement

• Method invocation and routine call differ– RC determine statically

– MI determined at run time by using a dispatch table

– A method has direct access to the fields of the object (6.2.9)

Page 95: 6.  Imperative and Object-oriented Programs

Imperative & OO 95

6.4.2.1 Routine identification – what to call

• Usually this has already been done during semantic checking.– For overloaded routine, a single routine is called if the input is correct.

• Routine variables:– The routine to be called may be the result of an expression.

– A routine value, and indirect routine call

• In OO languages, method identification is not so simple.– In Section 6.2.9.4, in many case a dispatch table must be consulted at run

time to find the method to be invoked.

Page 96: 6.  Imperative and Object-oriented Programs

Imperative & OO 96

6.4.2.2 Routine calls – how to call it

• Calling a routine – Transfer control

– Create component of an activation record

– Before creating the components of the AR, space for the AR itself must created

– Stack is usually used

– Stacks grow in memory

– Advantages of using stack• No explicit allocation and deallocation needed

• The working stack of the caller and the parameter of the callee can be combined

Page 97: 6.  Imperative and Object-oriented Programs

Imperative & OO 97

6.4.2.2 Routine calls – how to call itThe parameter area and parameter transfer

• The parameters of the routine must be stored or pushed to the location in which the callee expects them.– The compiler must impose a rule for accomplishing this.

– For example, when parameters are passed on the stack, the last parameter is pushed first.

• If the routine returns a result, the parameter area may also contain a pointer to the location in which this result must be stored.

• For a parameter with dynamic component, e.g., a dynamic array, – The dynamic component is allocated on the heap,

– The parameter of the AR then containing a pointer to the component, or a descriptor of known size with a pointer to the component.

Page 98: 6.  Imperative and Object-oriented Programs

Imperative & OO 98

6.4.2.2 Routine calls – how to call itThe parameter area and parameter transfer

• Called by value– The rvalue of the actual parameter is used as the initial value of the corresponding f

ormal parameters.

• Some form of output parameters– Called by reference

• The change is effected immediately

– Called by result• The change is effected upon return from the call

– Both can be implemented by passing the lvalue of the actual parameter istead of its rvalue.

– In call-by-reference• An assignment to a formal parameter is implemented by an assignment to its lvalue.

– In call-by-result• Allocating a local variable for the parameter, using this throughout the routine, and copy t

o the corresponding lvalue upon return.

– Call by value-result: call-by-value + call-by-result

Page 99: 6.  Imperative and Object-oriented Programs

Imperative & OO 99

6.4.2.2 Routine calls – how to call itThe administration part

• The administration part includes the frame pointer, representing the dynamic link, and the return or continuation address.

• May contain the FP of the lexically enclosing routine, representing static link.

• The old frame pointer is saved in the AD part and FP is set to indicate the new AR.

• Space to save some machine registers• For example, for local variables and temporaries

• When this is the case, these registers must be saved on routine call entry and restored on routine exit.

• Two frequently used schemes for register saving and restoring– Callee-saves scheme

– Caller-saves scheme

Page 100: 6.  Imperative and Object-oriented Programs

Imperative & OO 100

6.4.2.2 Routine calls – how to call itThe local variable area

• Once control has been transferred to the callee, the callee can start building the local variable area, the part of the AR in which the local variables and complier temporaries reside.

• Usually, the compiler can determine the size of the component, by considering it as a record of which the local variables of the routine are fields.

• The compiler also knows what temporary variables are required for the code of the routine, by keeping track of their number, size and alignment requirements during the code generation phase for the routine.

Page 101: 6.  Imperative and Object-oriented Programs

Imperative & OO 101

6.4.2.2 Routine calls how to call itThe working stack

• The local variable area is followed by the working stack, used o for anonymous intermediate results from expressions.

• It my also be used for the bounds of for-statements, although it is more common to put these in temporaries.

• Going through the code of a routine, the compiler can easily keep track of the size of the WS and record its maximum size.

Page 102: 6.  Imperative and Object-oriented Programs

Imperative & OO 102

6.4.2.2 Routine calls – how to call itThe dynamic allocation part

• If the target language allows ARs of dynamically extensible size, the AR may also have a separate dynamic allocation part for local variables.

• Some processor do not allow DA part, because they require the size of the AR to be specified when it is created.

– SPARC, for example

Page 103: 6.  Imperative and Object-oriented Programs

Imperative & OO 103

6.4.2.2 Routine calls – how to call itThe returning function results

• If the callee returns a value, the result can be made available to the caller in several ways.– For ‘simple’; type, it uses a machine register, called the function result

register.

– For ‘compound’ result, not naturally fit onto a register, three solutions1. If the compiler knows the size of the result, it can allocate a temporary

variable in the data space of the caller, and pass its address as an extra parameter to the callee.

2. Space for the result can be allocated dynamically by the callee, and a pointer to the allocated space is returned through the function result pointer.

3. The result can be left on the working stack of the callee, in the dynamic allocation part of its AR, or in one of its local variables, with a pointer in the function result register.

Page 104: 6.  Imperative and Object-oriented Programs

Imperative & OO 104

6.4.2.2 Routine calls – how to call itThe calling and return sequence

• The calling sequence consists of the following steps:– Create an AR.

– Evaluate parameters and store them in the AR.

– Fill the administration part of the AR, including• Frame pointer of the caller and the return address,

• Lexical pointer, if required,

• Probably some machine register, and

• Possibly the old stack pointer.

– Transfer control to the callee.

– Make the frame pointer FP points to the AR of the callee.

– Update the stack pointer SP, allowing enough space for the local variable part.

Page 105: 6.  Imperative and Object-oriented Programs

Imperative & OO 105

6.4.2.2 Routine calls – how to call itThe calling and return sequence

• The return sequence consists of the following steps:– If the callee has a return value, store the result in the area designated for

it.

– Restore the machine registers that was saved in the administration part.

– Update the stack pointer SP so that it indicates the frame pointer FP.

– Restore the frame pointer FP from the administration part.

– Transfer control to the caller, using the saved return address.

– Release the AR of the callee

Page 106: 6.  Imperative and Object-oriented Programs

Imperative & OO 106

6.4.2.2 Routine calls – how to call itActivation records and stack layout

Page 107: 6.  Imperative and Object-oriented Programs

Imperative & OO 107

6.4.3 Run-time error handling

• Handling of a run-time error consists of two parts:– The error must be detected and

– The actions for the error must be performed.

• Both have their problems:– Detecting the error may be difficult and

– Some of the required actions are very inconvenient.

Page 108: 6.  Imperative and Object-oriented Programs

Imperative & OO 108

6.4.3.1 Detecting a run-time error

• Detecting a run-time error caused by external circumstances is very system-specific.– E.g., a memory failure may or may not be made available to the program.

– It is up to the run-time system to make errors caused by external circumstance available if it can.

• Examples of run-time errors caused by program itself are:– Integer overflow,

– Array bound errors,

– Division by zero, and

– Dereferencing s null pointer.

Page 109: 6.  Imperative and Object-oriented Programs

Imperative & OO 109

6.4.3.1 Detecting a run-time error

• Some of these errors cause the OS to give an interrupt, but often, the compiler must generate checks to detect these run-time errors.

• Several error conditions can be checked for examining certain bits in the processor status word.

• Most processors lack special facilities for higher-level error conditions, for example, array or range bound errors.– Compiler must generate code to perform a check.

– However, it is quite expensive to do so.

Page 110: 6.  Imperative and Object-oriented Programs

Imperative & OO 110

6.4.3.2 Handling a run-time error

• Errors occur– Producing an intelligible error message

– Terminating the program

– Memory dump

• Many languages, however, include a mechanism for dealing with run-time errors.

Page 111: 6.  Imperative and Object-oriented Programs

Imperative & OO 111

6.4.3.2 Handling a run-time errorSignal handlers

• A simple mechanism for dealing with run-time error is the signal statement.– A signal statement binds a specific class of error conditions to a specific

user-defined routine, the signal handler.

• Whenever a run-time error occurs, the corresponding signal handler is called.– It might hen close open files, free system resources, print a message, and

terminate the program.– Alternatively, it could deal with in some other way with the error, and just

return.

• To implement the signal statement, the run-time system maintains a program-wide list of (error condition class, signal handler) pairs, so it can call the corresponding signal handler when a run-time error occurs.

Page 112: 6.  Imperative and Object-oriented Programs

Imperative & OO 112

Page 113: 6.  Imperative and Object-oriented Programs

Imperative & OO 113

6.4.3.2 Handling a run-time errorException handlers

• An exception handler specifies a particular error condition and a set of statements that will be executed should this error condition occur.– This allows an exception handler to access the local variable of the block

or routine in which the error condition occurred.

• For each exception handler, the compiler generates the code corresponding to the statements in the exception handler, terminating it with a jump to the end of the block associated with the handler, and labels this code with a unique handler label.– Also for each block or routine with exception handlers, it generates a table

(exception, handler label) tuples, with one entry for each exception handler.