3.7 Local Variables

Every method has a pool of up to 65,536 local variables. Very few methods use this many; most use fewer than 100. The actual number is given by the .limit locals directive immediately after the .method directive:

 .method public foo ()V .limit locals 5           ; No more than 5 locals may be used 

If you omit the .limit locals directive, the Oolong assembler will guess that it should reserve enough space for the highest-numbered local variable in your method. You can use the .limit locals directive if you think you know better than the Oolong assembler.

Local variables are similar to, but not quite the same as, the local variables in Java programs. Oolong local variables don't have names. Variables are referenced by number, starting at 0. As with stack entries, long and double values take up two consecutive local variables. You refer to it by the lower number. You can have a long in variable 1, in which case you may not use variable 2 because it's already spoken for by the long in 1.

There's no requirement for aligning long and double values. You can have a double value in variables 1 and 2 and another one in 4 and 5.

The instructions that deal with local variables are called load and store instructions. These load values from the local variable onto the stack and store values from the top of the stack into a local variable. "Load" and "store" are familiar to most programmers as "push" and "pop." They are used like this:

 aload 0     ; Push the reference in local 0 onto the stack iload 5     ; Push the int in local 5 lstore 3    ; Store the long on top of the stack             ; into locals 3 and 4 

For efficiency reasons, there are special instructions to load and store local variables 0, 1, 2, and 3. You might imagine that local variable 0 is used much more frequently than local variable 245. For example,

 fload_3 

has exactly the same effect as

 fload 3 

except that the former requires slightly less space in the resulting class file. Depending on the JVM implementation you use, it might even be a little more efficient.

Unlike Java, variables are dynamically typed, not statically typed. You can store any of the five stack types (int, float, double, long, reference) in any variable. This means that you can use slot 3 to store an int early in the method, then use it again later to store a float or half a double. The verification algorithm even approves of this behavior.

A local variable can hold values of different types at different times. The following example stores a String, an int, and a double in the same local variable, one after the other:

 ldc "A String"       ; Put a string onto the stack astore_0             ; Store a string into variable 0 sipush 12345         ; Put an int onto the stack istore_0             ; Store an int into the same variable ldc 2.718281828D     ; Put a double on the stack dstore_0             ; Store the double into variables 0 and 1 

When you load from a local variable, you must use the load instruction that corresponds to the type of the value that is stored in the field. This code is illegal:

 iconst_3             ; Load the constant 3 onto the stack istore_2             ; Store it in variable 2 aload_2              ; FOUL! Must use an iload instead 

Also, you must use a store instruction appropriate to the value on top of the stack.

 ldc "Hello"          ; Push a reference onto the stack fstore 3             ; FOUL! You must use an astore instead 

The JVM verification algorithm checks for illegal operations before the code is permitted to run. It errs on the side of caution: if it can't prove that the right instruction is used in every case, it rejects the class. The verification algorithm is discussed in detail in chapter 6.

Another thing to know about local variables is that double and long values take up two local variables, not one. For example,

 ldc "Hello, world"    ; Push a String astore_2              ; Store it in variable 2 ldc 3.14159D          ; Push a double-precision value dstore_1              ; Store it in both variables 1 and 2 

The former contents of variable 2 are wiped out, so if you now try

 aload_2               ; FOUL! 

the JVM will find that variable 2 no longer holds a reference and the verification algorithm will reject the program.

Tables 3.4 and 3.5 summarize the load and store instructions.

3.7.1 Initializing Variables

All variables must be explicitly initialized before they are used. JVM fields are initialized to default values (0 for numeric types, null for reference types). Local variables are not initialized. Programs must store into a local variable before reading from it. Otherwise, the program will be rejected by the verification algorithm.

Initialization means that you have to do a store before you do any loading. To initialize variable 7 to an int 3, use these instructions:

 .method static public someMethod()V ; All variables are currently uninitialized iconst_3 istore 7                  ; Variable 7 is now initialized to 3 ;; The rest of the method .end method 

Table 3.4. Load instructions
Mnemonic Argument Effect
iload n Push the int in local variable n onto the stack.
lload n Push the long in local variables n and n + 1 onto the stack.
fload n Push the float in local variable n onto the stack.
dload n Push the double in local variables n and n + 1 onto the stack.
aload n Push the reference in local variable n onto the stack.
iload_0   Push the int in local variable 0 onto the stack.
iload_1   Push the int in local variable 1 onto the stack.
iload_2   Push the int in local variable 2 onto the stack.
iload_3   Push the int in local variable 3 onto the stack.
lload_0   Push the long in local variables 0 and 1 onto the stack.
lload_1   Push the long in local variables 1 and 2 onto the stack.
lload_2   Push the long in local variables 2 and 3 onto the stack.
lload_3   Push the long in local variables 3 and 4 onto the stack.
fload_0   Push the float in local variable 0 onto the stack.
fload_1   Push the float in local variable 1 onto the stack.
fload_2   Push the float in local variable 2 onto the stack.
fload_3   Push the float in local variable 3 onto the stack.
dload_0   Push the double in local variables 0 and 1 onto the stack.
dload_1   Push the double in local variables 1 and 2 onto the stack.
dload_2   Push the double in local variables 2 and 3 onto the stack.
dload_3   Push the double in local variables 3 and 4 onto the stack.
aload_0   Push the reference in local variable 0 onto the stack.
aload_1   Push the reference in local variable 1 onto the stack.
aload_2   Push the reference in local variable 2 onto the stack.
aload_3   Push the reference in local variable 3 onto the stack.

This code is illegal:

 .method static public someIllegalMethod()V iload_0                   ; FOUL! Variable 0 is uninitialized ;; The rest of the method doesn't matter .end method 

Table 3.5. Store instructions
Mnemonic Argument Effect
istore n Store an int in local variable n.
lstore n Store a long in local variables n and n + 1.
fstore n Store a float in local variable n.
dstore n Store a double in local variables n and n + 1.
astore n Store a reference in local variable n.
istore_0   Store an int in local variable 0.
istore_1   Store an int in local variable 1.
istore_2   Store an int in local variable 2.
istore_3   Store an int in local variable 3.
lstore_0   Store a long in local variables 0 and 1.
lstore_1   Store a long in local variables 1 and 2.
lstore_2   Store a long in local variables 2 and 3.
lstore_3   Store a long in local variables 3 and 4.
fstore_0   Store a float in local variable 0.
fstore_1   Store a float in local variable 1.
fstore_2   Store a float in local variable 2.
fstore_3   Store a float in local variable 3.
dstore_0   Store a double in local variables 0 and 1.
dstore_1   Store a double in local variables 1 and 2.
dstore_2   Store a double in local variables 2 and 3.
dstore_3   Store a double in local variables 3 and 4.
astore_0   Store a reference in local variable 0.
astore_1   Store a reference in local variable 1.
astore_2   Store a reference in local variable 2.
astore_3   Store a reference in local variable 3.

The JVM verification algorithm is capable of detecting whether or not all variables are initialized before allowing your code to run. If your code is running, you can be sure that there are no variables used before initialization. This feat is actually rather remarkable, since in general it's impossible to predict how a program will run just from looking at it. Read chapter 6 to find out how its done.

3.7.2 Local Variables as Method Arguments

Some local variables are initialized for you automatically by the JVM. These local variables are used as method arguments. For example, consider this method:

 .class DemoClass .method static lotsOfArguments(IJF[[Ljava/lang/String;)D 

This corresponds to the Java method declaration

 static double lotsOfArguments    (int a, long b, float c, String[][] d) 

Local variable 0 is assigned to the first argument, local variable 1 to the second, and so on. In this case, five local variable slots are required, corresponding to the Java variables a, b, c, and d. Five slots are required for four variables because variable b requires two slots because it is a long.

If you call the method like this (from Java),

 DemoClass.lotsOfArguments(9, 1066L, 99.44, new String[5][10]) 

then variable 0 contains the int 9, variables 1 and 2 have the long 1066, variable 3 has the float 99.44, and variable 4 contains a reference to an array of Strings. If the method is not static, there is an additional argument. That argument is variable 0, and it corresponds to this in Java. For example,

 .class MyClass .method doSomeMath(IFF)F 

Four local variable slots are initialized in this method. Local variable 1 is an int, and variables 2 and 3 are floats. Variable 0 is a reference to an instance of the class MyClass, and it's guaranteed not to be null. Suppose you invoke the method like this (from Java):

 MyClass obj = new MyClass(); float return = obj.doSomeMath(100, 14.0, 3.14); 

In the body of the method, variable 0 will be a reference to obj. Variable 1 will be 100, 2 will be 14.0, and 3 will be 3.14. Any other variables will be uninitialized.

The return of the method is not allocated a particular variable. Even though the method returns a float, there is no variable corresponding to that float. Unlike the arguments, the return value is not assigned a slot. Instead, the returned value comes from the operand stack.



Programming for the Java Virtual Machine
Programming for the Javaв„ў Virtual Machine
ISBN: 0201309726
EAN: 2147483647
Year: 1998
Pages: 158
Authors: Joshua Engel

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net