• No results found

Potential Problem Areas

Heap Objects Stable Storage

4.3.5 The Instruction Set

4.3.10.1 Potential Problem Areas

The first potential problem area is in abstract data type creation. In order to produce an efficient implementation it is desirable for addresses to be calculated statically whenever possible. When the fields of objects may be of different sizes, as is the case with abstract types, this is clearly a problem.

The use of abstract data types also creates problems. Notice that in example 17 the compiler can not determine statically which implementation of the abstract type is being used. The objects referred to anumber and incremented may be of different sizes and reside on different stacks. This is the same problem as that encountered with parametric polymorphism.

4.3.10.2 P.A.M. Implementation of abstract data types

The mechanisms used to implement parametric polymorphism may also serve to implement abstract data types. Since abstract data types are first class data objects in Napier, they may be passed around freely and placed in the persistent store. Therefore, the technique of holding dynamic tag information in procedure closures is not sufficient to implement abstract data types. However, the tags may be carried around in the object that implements the abstact type. Furthermore, it is possible to calculate the addresses of the tags statically. It is desirable to be able to calculate not just the addresses of the tags, but the addresses of all the fields of an abstract data type. Clearly, since the objects may be of differenrt sizes, and may be pointer or non pointer types this creates a problem. The solution is to use the double scalar, double pointer technique discussed in the previous section in connection with polymorphic objects.

Abstract data types in Napier are implemented as structures with each field of witness type being allocated two addresses, one for the pointer type and one for the non-pointer type. The last fields in the structure contain the dynamic tags for the witnesses followed by the constancy bitmap found in all structures. This technique allows all the addresses to be calculated statically.

When a use clause is executed the dynamic tags are extracted from the abstract data type. These are placed on the execution stack and the block associated with the use clause executed. Once the dynamic tags have been placed on the stack the situation is implementationally identical to the situation found in polymorphic procedures. The fields in the abstract type may be dereferenced in order to extract or assign values using the poly subscript instructions already provided to support parametric polymorphism.

4.3.11 Debugging Support

The predecessors of PAM, the S-algol and PS-algol abstract machines both have an instruction called line number. This instruction takes as a parameter an integer representing the line number of the current instruction sequence. When this instruction is executed the parameter is saved in a register. Thus, the line on which an error occurs may be displayed. This scheme may be extended so that when a procedure call is executed the line number of the current line is saved in the calling frame and a new line number stored in the register. Therefore, a complete calling sequence may be reported by traversing the dynamic chain. In an environment where only one source program is running, this technique works well. However, in PS-algol, the use of first class functions and separate compilation means that line numbers do not uniquely identify lines of source code. Consequently, a more sophisticated mechanism is required, and the Persistent Abstract Machine is designed

accordingly. ^

I

When PAIL code is generated a literal pointer instruction is planted in the code stream. This i

i

I

- J ,

■T

1

some abstract source from the code stream into a location in the currently active frame. This links the source code with the currently running procedure. When an error occurs it is possible to display thé source code of where the error has occurred to the user.

Since the source is stored in the currently active frame the dynamic call chain may be displayed to the user. The abstract code PAIL contains context information so that the static environment may also be shown.

PAIL code is decorated by the compiler with address information of the identifiers in the

current procedure. This information is all that is required to allow the user to browse over f the name-value bindings stored in the frame. When and how this may be done remains

unresolved.

I

If a programmer has encapsulated information within an abstract data type it is safe to # assume that data was intended to be hidden. If a fault occurs in that abstract data type,

should a debugging system be allowed to examine the contents of that abstract data type? It is not clear what the answer to this question is. On one hand there is a practical argument that says if data which may have been expensive to gather is held in an erroneous program there should be some mechanism to retrieve that data. On the other hand there is the purist view that says that if data has been encapsulated any discovery of hidden types is a breach of type security and hence modularity.

4.4 Conclusions

This chapter has described the important features of the Persistent Abstract Machine. The predecessors of the current machine have been examined briefly. The good parts of machines predecessors have been retained or modified in the new machine and the bad parts discarded. It is only through implementations that it is possible to make this distinction between good and bad.

The Persistent Abstract Machine is an implementation vehicle for language and system experimentation. As such it has been designed with modularity in mind arid therefore does not contain any language specific support. Instead, it supports a wide range of typed algorithmic languages. Most importantly, the machine is independent of the type system of the languages which it supports. It is also independent of the persistent object management system that supports it, allowing experimentation in this field to continue independent of abstract machine design. This decoupling will aid our future experiments.

Perhaps the most important part of the machine is the way in which it implements polymorphism. The machine implements universal polymorphism over objects of different sizes in an efficient manner. The scheme used to support polymorphism may be extended without modification to support a powerful notion of abstract types. It is thought that this mechanism may also be used to support inclusion polymorphism. This will be the subject of further investigation.