JVM instructions - sload

Noskol :

I guess it is a basic question, but why there is no sload instruction? Why can you load all primitives besides short? (There is saload, but still...)

For :

public class ShortTest {
    public void test() {
        short i = 1;
        System.out.print(i);
    }
}

Compiler still uses iload_1. Is it because short is 16 bit type and processors handle better 32bits (since all modern processors are 32/64bits)?

Holger :

Refer to the JVM specification, §2.11.1. Types and the Java Virtual Machine:

Note that most instructions in Table 2.11.1-A do not have forms for the integral types byte, char, and short. None have forms for the boolean type. A compiler encodes loads of literal values of types byte and short using Java Virtual Machine instructions that sign-extend those values to values of type int at compile-time or run-time. Loads of literal values of types boolean and char are encoded using instructions that zero-extend the literal to a value of type int at compile-time or run-time. Likewise, loads from arrays of values of type boolean, byte, short, and char are encoded using Java Virtual Machine instructions that sign-extend or zero-extend the values to values of type int. Thus, most operations on values of actual types boolean, byte, char, and short are correctly performed by instructions operating on values of computational type int.

It’s worth recalling that in Java, any integer arithmetic not involving long will have an int result, regardless of whether the input is byte, char, short, or int.

So a line like

short i = 1, j = 2, k = i + j;

will not compile, but require a type cast, like

short i = 1, j = 2, k = (short)(i + j);

And this type cast will be the only indicator that short is involved. Letting debug hints aside, there is no formal declaration of local variables in bytecode, but only assignments of values which determine their type. So local variables of type short simply do not exist. The code above compiles to

     0: iconst_1
     1: istore_1
     2: iconst_2
     3: istore_2
     4: iload_1
     5: iload_2
     6: iadd
     7: i2s
     8: istore_3

which is identical to the compiled form of

int i = 1, j = 2, k = (short)(i + j);

But mind that the compile-time type of variables can change which method the compiler chooses for an invocation in case of overloads. Which is especially important if the types carry different semantics, like in the case of print(boolean) or print(char). While the value passed to the method has an int type in either case, the outcome is entirely different.

Another example of differences enforced by the compiler is

{
    int i = 1;
    i++;
}
{
    short s = 1;
    s++;
}

which gets compiled to

     0: iconst_1
     1: istore_1
     2: iinc          1, 1
     5: iconst_1
     6: istore_1
     7: iload_1
     8: iconst_1
     9: iadd
    10: i2s
    11: istore_1

So, since the calculation is always performed in 32 bit, the compiler inserts the necessary code to truncate the result to short for the second increment. Note again the absence of variable declarations, so the code is identical to the compiled form of

int i = 1;
i++;
i = 1;
i = (short)(i+1);

It’s also worth looking at the Verification Type System, as the verifier will check the validity of all transfers from and to local variables:

The type checker enforces a type system based upon a hierarchy of verification types, illustrated below.

Verification type hierarchy:

                             top
                 ____________/\____________
                /                          \
               /                            \
            oneWord                       twoWord
           /   |   \                     /       \
          /    |    \                   /         \
        int  float  reference        long        double
                     /     \
                    /       \_____________
                   /                      \
                  /                        \
           uninitialized                    +------------------+
            /         \                     |  Java reference  |
           /           \                    |  type hierarchy  |
uninitializedThis  uninitialized(Offset)    +------------------+  
                                                     |
                                                     |
                                                    null

So the type system is simplified, compared to the Java language types, and the verifier doesn’t mind, e.g. if you pass a boolean value to a method expecting a char, as both are int types.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=308216&siteId=1
JVM
JVM