next up previous contents
Next: The Problem with Up: Variable and Constant Previous: Variables and Constants

Variables and Constants as Objects or Arrays

 

So the choice is between compiling variables of primitive types into objects or into arrays. Java features so called wrapper classes for primitive types. These classes allow you to store a value of a primitive type in an object of a class of the corresponding type. So if you have a variable of one of the Pascal types integer, real, char or boolean, you could compile these into an object of respectively class Integer, Float, Character or Boolean. The problem with these wrapper classes is that it is not possible to change the value in the object. This means that you would not be able to change the value of a variable, which is of course not what we want. The only other option left when you want to compile variables into objects is to implement the classes to store the values in yourself, in such a way that it is possible to change the values. These classes could be quite simple, like:

    Class PascalType {
        public CorrespondingJavaType value;
    }

You have to read PascalType as one of the primitive Pascal types and read CorrespondingJavaType as the corresponding primitive Java type. Compiling variables into instances of these classes would provide you with a reference to the variables so you can pass that reference when you have to pass that variable as a call-by-reference parameter. It would also mean that you have to make the necessary constant_pool[] entries needed to refer to the field of the object, like a CONSTANT_Class_info entry for each of the classes, a CONSTANT_Fieldref_info entry plus the entries it needs for each of the classes and a CONSTANT_Methodref_info entry for the <init> method for each of the classes. Making these constant_pool[] entries and implementing classes for each of the primitive types can be avoided by compiling the variables into arrays.

When you compile the variables into arrays of one element of the type of the variable, you also have a reference to the variable and it is quite simple to access or change the value. All you have to do when you want to access it is to load the arrayref and index on the operand stack and either load the value from the array or store a value in the array.

This is the option I chose. To handle variables and constants the same way I also compiled the constants into arrays of one element. This way you do not have make a difference when you want to load the value of a variable or a constant. It is of course not necessary as constants do not need references because it is not possible to pass them as call-by-reference parameters. The only constants that are not compiled into arrays of one element are string constants. Strings have to be stored in an object of the class java.lang.String which means they already have a reference. It would be unnecessary work to load the value if you store the reference in an array. String constants in Pascal are kind of special anyway because they can never be passed as actual parameters. String constants will just get an entry in the fields[] table as the other variables and constants but unlike the other variables and constants this entry will also have a ConstantValue attribute.

By making a testprogram in Java and viewing it with jdisco, I found out that global variables that are arrays are created in the class initialization method <clinit>. This method contains the following sequence of instructions for each array that has to be created:

 
 iconst_1		     		 load the size of the array;

newarray atype create an array of atype with the size on top of the stack;

putstatic index store the arrayref in the global field at index in the

constant_pool[].

The operand atype of the newarray instruction is a value indicating the type of the elements in the array.

The operand index of the putstatic instruction is the index of the CONSTANT_Fieldref_info entry in the constant_pool[] describing the field.

Because we also want constants to be arrays of one element, and there is no way to initialize an array when it is declared, we have to store the value of the constant in the array in a method. The <clinit> method is the right place to do that. For constants the sequence of instructions is therefore a bit different:

 
 iconst_1		    		 load the size of the array;

newarray atype creates an array of type with the size on top of the stack;

dup duplicate the arrayref;

putstatic index store one arrayref in the variable;

iconst_0 load the index of the element to hold the value;

ldc valindex load the value of the constant on the operand stack;

<t>astore store the value in the element.

The dup instruction is used because we need the arrayref twice, the first time to store the reference itself and the second time to store the value.

The ldc instruction loads the value of the constant on the operand stack. The value is stored at index valindex in the constant_pool[]. Every time the compiler comes across a real value, an integer value or a string value in the Pascal program, it stores the value in respectively a CONSTANT_Float_info entry, a CONSTANT_Integer_info entry or a CONSTANT_String_info entry in the constant_pool[]. The index of such an entry is the valindex. The ldc instruction naturally has to be a ldc_w instruction when valindex is a wide index.

The <t>astore instruction stores the value in the element, where <t> is the letter for the type of the array, where i stands for int, f for float, c for char and b for boolean. The instructions to store and load elements of arrays of type boolean are the bastore and baload instructions, the same instruction used for arrays of type byte.

To summarize, variables are compiled as follows:

Constants, except string constants, are compiled as follows:

String constants are compiled as follows:

All variables and constants are also made global, because nested procedures still have to be able to access the local variables of the procedure they are declared in, as I described in the previous subsection. Local variables are made global by prefixing their name with the string `` $_'' followed by a unique number, also described in the previous subsection.

Making the local variables global solves some problems, but is inadequate in the presence of recursive procedures or functions, as will be explained in the next subsection.



next up previous contents
Next: The Problem with Up: Variable and Constant Previous: Variables and Constants



mark@bottom.xs4all.nl