Why does the JVM have a separate array of local variables?

98 Views Asked by At

This question is sort of the opposite of this existing one: What is the role of operand stack in JVM?

That question asks why the JVM does not operate directly on the local variables. I'm wondering, since we have the stack anyway, why not operate only on the stack and forego the local variables entirely?

I guess it would need a few more instructions to manipulate the stack (much like advanced RPN calculators do), but how does one know whether that tradeoff would be worth it? Is this design rationale recorded somewhere?

The specification is light on rationale (https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-2.html#jvms-2.6.1), but I suspect that's because the specification is the wrong document for it, and maybe there's an annotated specification somewhere like with Ada?

2

There are 2 best solutions below

2
Thomas Kläger On BEST ANSWER

Is this design rationale recorded somewhere?

I doubt that you will find a satisfying answer to this question.

When people began working on what is now known as Java around 30 years ago this wasn't a big commitee and some elaborate process . It was a small group of people working tightly together and explicitly formed to work autonomously without the bureaucracy that was stalling other Sun projects". The process was therefore probably more: someone proposed something to the group, there was some discussion and then it was decided without much writing down of rationales.

Source for the "small group": https://en.wikipedia.org/wiki/Java_(software_platform)#History


Some thoughts on the other points you've made:

I guess it would need a few more instructions to manipulate the stack (much like advanced RPN calculators do)

Without local variables you would have to replace iload, aload and some more variants with ipick, apick and similar variants that pick a value from some offset from the top of the operand stack and push it on top of the operand stack.

Similarly you would need to replace istore, astore and some more variants with ireplace, areplace and similar variants that pop a value from the operand stack and replace the value at some offset of the top of the operand stack with the popped value.

The main difference between the existing instructions and the proposed instructions would be that the existing instructions always use the same offset for a specific local variable while the proposed instructions would have to use different offsets for a specific local variable depending on how much values have been pushed to the operand stack.

but how does one know whether that tradeoff would be worth it?

IMHO not using local variables would make Java byte code harder to work with (for example when doing Verification of class Files) without reaping any benefits.

Note that at runtime there are no separate memory spaces for local variables and the operand stack. Conceptually the JVM uses one Frame per method invocation and this frame contains the local variables and the operand stack.

0
Arfur Narf On

To evaluate a = b * c, for example, it's push b; push c; multiply; pop a.

After the multiply, b and c are not 'in' the stack. The values were only temporarily there.

I think the appropriate way to look at the operand stack is to consider it as a set of fast registers. Like general-register machines, arithmetic is done in the fast registers; the stack has the benefit that the 'register addresses' are implicit, saving some instruction bits.

If you want b and c to be 'always' in the stack, which means they're at arbitrary locations relative to the stack top, then you've just turned your stack into a non-stack machine since you either need 3-address instructions (like 'multiply a,b,c') or you need an accumulator (so 'load a; multiply b; store c'), where in each case a,b,c are the addresses of some locations in the stack - possibly encoded as offsets from the stack top.

What makes that a 'non-stack' architecture is that arithmetic is no longer being done on the topmost cells of the stack, implicitly identified, but instead is between arbitrary locations explicitly identified.