views:

68

answers:

4

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?

+7  A: 

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.

Joachim Sauer
Ok. Taking it a step further: Is that part of a specification, or just how it's commonly implemented?
Bart van Heukelom
I don't think the JVMS (which is more appropriate here than the JLS) actually mandates that behaviour - maybe I missed it but I read a fair share of it. It might be true with Hotspot but surely this is open to the implementor.
musiKk
@musikk: it doesn't mandate the re-use of local variable "slots", that one is common practice. However, the JVM Spec *does* mandate the one-frame-per-method-invocation method which implies that code blocks don't have a separate frame.
Joachim Sauer
Applies only if you're not using some obscure compiler, which compiles Java blocks into bytecode methods ;-) So, to answer @Barts initial comment, No, I don't believe it is part of the JLS.
aioobe
But I'd assume compiling code blocks into methods is specification-illegal, because exception stack traces wouldn't match with the source code, confusing IDEs and debuggers.
Bart van Heukelom
@Joachim: Yes, you're absolutely right.
musiKk
+2  A: 

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.

aioobe
I disagree: the JVM spec *does* describe stack frames in quite some detail, in fact: [JVM Spec §3.6 Frames](http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#17257)
Joachim Sauer
Aha, thanks, updating!
aioobe
Actually, I wrote that the *JLS* does not specify scope of variables in relation to stack frames. Which is technically true, right?
aioobe
A: 

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

Vanya
It is not removed. More over, in the bytecode variables are stored in 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.
Eugene Kuleshov
+1  A: 

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.

Eugene Kuleshov