6

Here is one snippet of code

public class Classifier {
    public static void main(String[] args) 
    {
        Integer x = -127;//this uses bipush
        Integer y = 127;//this use bipush
        Integer z= -129;//this use sipush
        Integer p=32767;//maximum range of short still sipush
        Integer a = 128; // use sipush
        Integer b = 129786;// invokes virtual method to get Integer class

    }

}

Here is partial byte code of this

      stack=1, locals=7, args_size=1
         0: bipush        -127
         2: invokestatic  #16                 // Method java/lang/Integer.valueO
f:(I)Ljava/lang/Integer;
         5: astore_1
         6: bipush        127
         8: invokestatic  #16                 // Method java/lang/Integer.valueO
f:(I)Ljava/lang/Integer;
        11: astore_2
        12: sipush        -129
        15: invokestatic  #16                 // Method java/lang/Integer.valueO
f:(I)Ljava/lang/Integer;
        18: astore_3
        19: sipush        32767
        22: invokestatic  #16                 // Method java/lang/Integer.valueO
f:(I)Ljava/lang/Integer;
        25: astore        4
        27: sipush        128
        30: invokestatic  #16                 // Method java/lang/Integer.valueO
f:(I)Ljava/lang/Integer;
        33: astore        5
        35: ldc           #22                 // int 129786
        37: invokestatic  #16                 // Method java/lang/Integer.valueO
f:(I)Ljava/lang/Integer;
        40: astore        6
        42: return

As i see for Integer range between -128 to 127 it uses bipush which push a byte onto the stack as an integer value. In a range -32768 to 32767 it uses short as a wrapper class as sipush. For next it uses Integer. What JVM uses byte and short to store Integer value?

  • Isn't this a duplicate of https://stackoverflow.com/questions/20897020/why-integer-class-caching-values-in-the-range-128-to-127 ? – Denys Séguret Apr 26 '15 at 08:35
  • @dystroy my one question still remains unanswered why byte and short for int ? –  Apr 26 '15 at 08:43
  • 1
    If you have two separate questions, it's really best to ask two separate questions. Lots of people might know the answer to one but not the other; should they give answers or not? And how will you pick which answer to accept? Please don't combine two questions in one posting. – Dawood ibn Kareem Apr 26 '15 at 09:06

3 Answers3

6

It is not stored as byte or short at runtime, just in bytecode. Let's say you want to store value 120 into Integer. You write the compiler, so you parse the source code and you know the constant value 120 can fit into one signed byte. Because you don't want to waste space in your bytecode to store value 120 as 32bit(4 bytes) value if it can be stored into 8 bits(1 byte), you will create special instruction, that will be able to load only one byte from method bytecode and store it on the stack as 32bit integer. That means, at runtime, you really have integer data type.

The resulting code is smaller and faster than using ldc everywhere, which needs more interaction with jvm beceause of manipulation with runtime constant pool.

bipush has 2 bytes, one byte opcode, second byte immediate constat value. Because you have only one byte for value, it can be used for values between -128 to 127.

sipush has 3 bytes, one byte opcode, second and third byte immediate constant value.

bipush format:

bipush
byte

sipush format:

sipush
byte1
byte2
Krab
  • 6,526
  • 6
  • 41
  • 78
1

As far as my i've understood.

As you can from remaining byte code instruction it doesn't store int as byte or short First why bipush or short : bipush has 2 bytes one for opcode and second for value. i.e which can range between -128 tp 127 (i.e 2 power 8) It saves space and time of execution. As you can see from remianing code compiler does creates a reference of that variable as integer type

2: invokestatic  #16                 // Method java/lang/Integer.valueO
f:(I)Ljava/lang/Integer;

and then astore_1 which store what's on top of the stack i.e a reference here into local variable 1 Similar is for sipush where you can store value from range (-32768 to 32767) beacuse it's 3 byte instruction set, one byte for opcode and rest two byte for value (i.e can hold 2 power 16)

Now why not lDC JVM has a per-type constant pool. Byte code requires data, but most of the time this data is too large to store directly in the byte codes. so it's stored in the constant pool and the byte code contains a reference to the constant pool. What ldc does push a constant #index from a constant pool (String, int or float) onto the stack Which consumes extra time and cycles Here is a rough comparision between ldc operation and bipush operation

enter image description here enter image description here

JVM Bytecode ref here it says

Where possible, its more efficient to use one of bipush, sipush, or one of the const instructions instead of ldc.

Ankur Anand
  • 3,873
  • 2
  • 23
  • 44
0

One reason may be the advantages concerning the byte code that have been mentioned in other answers.

However, one could also reason about this by starting from the language. Particularly, you don't want to insert a cast when the (constant) value is actually representable in the target type.

So, one reason for the observed behavior is: The compiler uses the smallest possible type that can represent the given constant value.

For the assignment to an int (or Integer) it would not be necessary - but it does not do any harm when the bytecode assigns a "smaller" type to a "larger" type. Conversely, for smaller types, it is necessary to use the smaller type, so using the "bytecode for the smallest type" is the default behavior.


This is also implicitly referred to as "compile-time narrowing of constant expressions" in Section 5.2., Assignment Contexts of the Java Language Specification:

A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.

...

The compile-time narrowing of constant expressions means that code such as:

byte theAnswer = 42;

is allowed. Without the narrowing, the fact that the integer literal 42 has type int would mean that a cast to byte would be required:

byte theAnswer = (byte)42;  // cast is permitted but not required
Community
  • 1
  • 1
Marco13
  • 53,703
  • 9
  • 80
  • 159