Question

In Java this is the case:

public void method() {
  if (condition) {
    Object x = ....;
  }
  System.out.println(x); // Error: x unavailable
}

What I'm wondering is this: Is the fact that x is limited to the scope of the if-statement just a feature of the Java compiler, or is x actually removed from the stack after the if-statement?

Was it helpful?

Solution

No, code blocks don't get a separate stack frame, the use the one of the surrounding method.

However, once a variable leaves scope, it's place in the current stack frame can be re-used for other variables.

The structure and use of a stack frame is described in the Java Virtual Machine Specification § 3.6 Frames:

A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes, whether that completion is normal or abrupt (it throws an uncaught exception).

This definitely specifies a 1:1 relation between method invocations and frames.

OTHER TIPS

Blocks are a part of the Java language (which is a structured programming language) while they are not a part of the compiled bytecode (which is an non-structured language).

A method specification in a class file specifies how many local variables the method uses in total, above the actual list of instructions. But where the blocks once where in the Java code can not be inferred from the bytecode.

First of all, in the bytecode variables are stored in the variable slots and variable slots and not on the stack. The slot could be reused by another variable, but it is not guaranteed that value would be removed from the variable slot.

For example, the following class

  public class A {
    public void method(boolean condition) {
 6    if (condition) {
 7      Object x = "";
 8      System.out.println(x);
 9    }
10    System.out.println(condition);
    }
  }

is compiled into this bytecode:

// class version 50.0 (50)
public class A {
  ...

  // access flags 0x1
  public method(Z)V
   L0
    LINENUMBER 6 L0
    ILOAD 1
    IFEQ L1
   L2
    LINENUMBER 7 L2
    LDC ""
    ASTORE 2
   L3
    LINENUMBER 8 L3
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 2
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   L1
    LINENUMBER 10 L1
   FRAME SAME
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ILOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (Z)V
   L4
    LINENUMBER 11 L4
    RETURN
   L5
    LOCALVARIABLE this LA; L0 L5 0
    LOCALVARIABLE condition Z L0 L5 1
    LOCALVARIABLE x Ljava/lang/Object; L3 L1 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

Note that variable x created at line 7 is stored into the variable slot 2, which is still available at the bytecode corresponding to line 10.

There is no specification on how Java language have to be compiled into the bytecode other then few examples how to properly compile some language constructs. However Java compiler is allowed to eliminate unused variables. E.g. if x were assigned, but not used anywhere, compiler is allowed to drop that code. Similarly, compiler is inlining all the static constants.

Yes, it is really removed from the stack making the slot previously occupied by 'x' reusable by some other local variable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top