Previous | Table of Contents | Next |
Although intermediate languages are frequently used in compiler construction (Chow & Ganapathi, 1983; Ottenstein, 1984), there are two efforts worth considering here:
Both ILs are currently in use; moreover, Java VM builds heavily upon Pcode, and so we can see the evolution of one useful IL into another.
An overview of the operation of a Pcode Pascal compiler is shown in Figure 4.4. The compiler box is responsible for assessing the validity of the source program and generating an appropriate IL representation of the program. The program is then executed by interpretation of the IL text. Another possibility is that the IL text is subsequently translated into machine As native code. This approach is consistent with the compiler suite shown in Figure 4.3(b).
Figure 4.4. An overview of a compiler/interpreter pair.
Consider the following Pascal statement:
t.total := t.total + 3
which increments the total field of variable t by 3. The compiler component is a front end for Pascal and generates the following (annotated) Pcode representation of the preceding statement:
ldoi 9 ; pushes the value kept at slot 9 onto the ; run-time stack; the compiler decided that ; slot 9 is where t.total should be stored. ; ldci 3 ; pushes the integer constant 3 ; adi ; pops the stacks top two elements, forms ; their sum, and then pushes the result onto ; the stack; the previous instructions have ; caused the values of t.total and 3 to ; be the addends for this instruction ; sroi 9 ; stores at slot 9 (t.total) the value popped ; from the stack
These Pcode instructions are then executed by the interpreter component.
Pcode is designed so that writing a Pcode interpreter is vastly simpler than writing a Pascal compiler; moreover, the compiler and interpreter components are each written in Pascal. These two design considerations were instrumental to the success of Pascal because they significantly reduce the cost of porting the compiler. A Pcode-generating Pascal compiler is ported between platforms as shown in Figure 4.5.
Figure 4.5. Porting a compiler using its intermediate language.
If machine A already has a Pcode-generating Pascal compiler, then Pcode generated on A can be executed on machine B after B has a Pcode interpreter. The compiler itself is compiled into Pcode on A, and when that Pcode is moved to B and interpreted by its Pcode interpreter, the result is a Pascal compiler that runs on B. Because of its portability, the UCSD Pascal compiler (Jensen, 1985) quickly became available on a great number of microcomputers and thus fostered a broad Pascal user community.
Like Pcode, Java VM uses a stack machine model to evaluate expressions, with instructions to place values on a stack and to perform arithmetic operations on them. Because Java is object oriented, Java VM has instructions to invoke methods (operations belonging to an object), to refer to data encapsulated within class instances, and to check object instances with respect to a class hierarchy.
To illustrate both the use of an IL as well as the cleverness with which Java VM was fashioned, consider the following code sequence:
t.total += 3
where total is a public data element of a class instance of type obj. This statement has the effect of incrementing the data item total by 3.2 Translated into Java VM, the (annotated) instructions generated from the statement are
2It is better programming style to access such data through an appropriate member function; this example is pedagogically expedient.
getfield #5 <obj.total I> ; Slot 5 holds the reference ; for t, so this instruction ; pushes onto the stack the ; field total of a reference ; to type obj which is an ; integer (I) ; iconst_3 ; pushes the constant 3 ; iadd ; pops the stacks top two ; elements and pushes their ; sum onto the stack ; putfield #5 <obj.total I> ; pop the result off the stack ; and store it in slot 5s ; (ts) integer total field
The code sequence first fetches the value of total, which places the value on the stack. After the value 3 is pushed on the stack, the iadd instruction forms the sum, and the result is then stored back to total.
Previous | Table of Contents | Next |