Re: Long.valueOf(long) CodeAttribute max_locals wrong?
- From: Roland de Ruiter <roland.de.ruiter@xxxxxxxxxxxxxxx>
- Date: Sat, 20 Sep 2008 16:43:46 +0200
On 20-9-2008 15:15, softwarepearls_com wrote:
On Sep 20, 2:17 pm, Roland de Ruiter
<roland.de.rui...@xxxxxxxxxxxxxxx> wrote:
On 20-9-2008 11:57, softwarepearls_com wrote:
When looking at the CodeAttribute for valueOf(long) in Long.class (JREA long value requires two local variable slots.
1.6.0_10), the file states that max_locals is 3.
Yet when looking at the bytecode for the method, the highest local
variable index used by the code is 0 (in the lload_0 instructions).
Since the variable is a long, that, to me, would give this static
method a max_locals of 2, not 3.
When looking at the source code,
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
.. there is the "offset" local variable.. but the compiler does not
require a local variable slot for it, since it is a constant.
So does the max_locals CodeAttribute field deal with the "source code
view" of local variables, or with the JVM view of local variables?
Yes, which is why I would expect max_locals to be 2, but it is 3 in
the .class from the JRE I'm using (Sun's Windows 1.6.0_10-rc). The 3
is reported by two completely different .class parsing tools (using
two different parsing APIs), so that value is 100% accurate. How do
you explain the value when there's just one 2-slot long involved?
Same in 1.6.0_07 (WinXP). The third slot probably is reserved for the final int offset. The Java runtime classes have been compiled without debug information, and apparently the compiler has optimized and omitted code for storing the value 128 in the third slot.
Compiling code with debug information (local variables, in this case) should provide proper initialization code for the final int offset, because debuggers (and other instrumentation software) may access the names and/or values of the local variables.
I can replicate it with the following class:
package test;
public class Locals {
private static class LongCache {
private LongCache() {
}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for (int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int) l + offset];
}
return new Long(l);
}
}
Compiling it without debug information (javac -g:none Locals.java) produces the following byte code (decompiled using javap -classpath . -c -l -verbose Locals):
Code:
Stack=4, Locals=3, Args_size=1
0: lload_0
1: ldc2_w #2; //long -128l
4: lcmp
5: iflt 27
8: lload_0
9: ldc2_w #4; //long 127l
12: lcmp
13: ifgt 27
16: getstatic #6; //Field test/Locals$LongCache.cache:[Ljava/lang/Long;
19: lload_0
20: l2i
21: sipush 128
24: iadd
25: aaload
26: areturn
27: new #7; //class java/lang/Long
30: dup
31: lload_0
32: invokespecial #8; //Method java/lang/Long."<init>":(J)V
35: areturn
StackMapTable: number_of_entries = 1
frame_type = 27 /* same */
--------------------------------------------------------------------
Compiling it *with* debug information (javac -g Locals.java) produces the following byte code. As you can see, the code now contains a "sipush 128" followed by "istore_2" as the first two byte code instructions. These two initialize the local variable "offset", of course. This version also contains a LocalVariableTable.
------------------------------------------------
Code:
Stack=4, Locals=3, Args_size=1
0: sipush 128
3: istore_2
4: lload_0
5: ldc2_w #2; //long -128l
8: lcmp
9: iflt 31
12: lload_0
13: ldc2_w #4; //long 127l
16: lcmp
17: ifgt 31
20: getstatic #6; //Field test/Locals$LongCache.cache:[Ljava/lang/Long;
23: lload_0
24: l2i
25: sipush 128
28: iadd
29: aaload
30: areturn
31: new #7; //class java/lang/Long
34: dup
35: lload_0
36: invokespecial #8; //Method java/lang/Long."<init>":(J)V
39: areturn
LineNumberTable:
line 15: 0
line 16: 4
line 17: 20
line 19: 31
LocalVariableTable:
Start Length Slot Name Signature
0 40 0 l J
4 36 2 offset I
----------------------------------------------------
Maybe the JVM specification somewhere states that the number of local variables in the compiled code should reflect the actual number of local variables in the source code, irrespective of whether debug information is available or not. You probably should read the spec...
--
Regards,
Roland
.
- Follow-Ups:
- Re: Long.valueOf(long) CodeAttribute max_locals wrong?
- From: softwarepearls_com
- Re: Long.valueOf(long) CodeAttribute max_locals wrong?
- References:
- Long.valueOf(long) CodeAttribute max_locals wrong?
- From: softwarepearls_com
- Re: Long.valueOf(long) CodeAttribute max_locals wrong?
- From: Roland de Ruiter
- Re: Long.valueOf(long) CodeAttribute max_locals wrong?
- From: softwarepearls_com
- Long.valueOf(long) CodeAttribute max_locals wrong?
- Prev by Date: Re: Long.valueOf(long) CodeAttribute max_locals wrong?
- Next by Date: Re: Long.valueOf(long) CodeAttribute max_locals wrong?
- Previous by thread: Re: Long.valueOf(long) CodeAttribute max_locals wrong?
- Next by thread: Re: Long.valueOf(long) CodeAttribute max_locals wrong?
- Index(es):
Relevant Pages
|
Loading