Compiling local variables and constants to global variables so that they can still be accessed by nested procedures that are also made global seemed like a good idea. For local constants it is, but for local variables it might cause troubles. The problem lies in the fact that when you have a recursive function in which variables are declared, all `instances' of the function change the same global variables. This will cause problems, because values stored in the variables by one instance can be overwritten by another instance. If that first instance of the procedure is again active and uses these values, incorrect values are used, producing incorrect results.
An example of such a function is:
procedure ack(a :integer; var b :integer); var i, j :integer; begin if (a = 1) or (a = 2) then b := 1 else ack(a-1, i); ack(a-2, j); b := i + j; end;
This problem can be solved by not making the local variables global, but keeping them local instead. This causes the problem of nested procedures or functions not being able to access the local variables of the procedure or function they are declared in. This can be solved by passing all local variables as call-by-reference variables to every nested procedure or function. This way these procedures or functions can access the local variables and change them. Because they are passed call-by-reference the real local variables will be changed.
As the local variables stay local, other instances of the procedure or function in case of a recursive call have their own local variables. As it is impossible for one procedure or function to access the local variables of another, it also is not possible for one instance of a recursive procedure or function to change the local variables of another.
Local constants can still be declared as global constants, as they can never be changed. This way you do not have to pass them around as parameters.
Local variables do not have an entry in the fields[] table and do not have entries in the constant_pool[]. Instead they have an entry in the local variable table of the frame of the method. This also means the arrays are not created the same way as the global arrays. The arrays of the local variables are simply created in the code of the method they are declared in, instead of in the <clinit> method.
The first positions in the local variable table of the method are for the parameters of the method. These are automatically allocated by the JVM. In case of a local variable declaration, you simply take the next unused position in the local variable table. At that position you can store any value, provided they are all of the same type. So when you have a declaration of a local variable, you add the following sequence of instructions to the code[] array of the method:
iconst_1 load size of array;newarray atype create array and push arrayref;
astore next_unused_pos store the arrayref in local variable.
The astore instruction stores the arrayref in the local variable table at position next_unused_pos, the next unused position. The next time the arrayref is needed, it can be found at that position.