Java opcodes for volatile variables   Leave a comment

Let’s look at what happens when we access a volatile variable in Java. Consider a simple class like this. We have two variables i and j and both are being incremented. j is volatile.

package com.salil.threads;

public class IncrementClass {
	
	static volatile int j = 0;
	static int i = 0;

	public static void main(String args[]) {
        //Empty loop that does nothing except run for
        //some time so that JIT kicks in
		for(int a=0;a<1000000;a++);

		i++;
		j++;
	}
}

Let’s run javap using the command “javap -c -v com.salil.threads.IncrementClass” and take a look at the java bytecode generated as shown below:

Classfile /C:/Users/sasurendran/Dropbox/Practicals/Threads/out/production/Threads/com/salil/threads/IncrementClass.class
  Last modified Dec 29, 2014; size 623 bytes
  MD5 checksum 87df18c0f05fa02a44339a77989ab435
  Compiled from "IncrementClass.java"
public class com.salil.threads.IncrementClass
  SourceFile: "IncrementClass.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:
   #1 = Methodref          #6.#26         //  java/lang/Object."":()V
   #2 = Integer            1000000 <-- The constant for our for loop in line no. 11
   #3 = Fieldref           #5.#27         //  com/salil/threads/IncrementClass.i:I
   #4 = Fieldref           #5.#28         //  com/salil/threads/IncrementClass.j:I
   #5 = Class              #29            //  com/salil/threads/IncrementClass
   #6 = Class              #30            //  java/lang/Object
   #7 = Utf8               j
   #8 = Utf8               I
   #9 = Utf8               i
  #10 = Utf8               
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               LocalVariableTable
  #15 = Utf8               this
  #16 = Utf8               Lcom/salil/threads/IncrementClass;
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               a
  #20 = Utf8               args
  #21 = Utf8               [Ljava/lang/String;
  #22 = Utf8               StackMapTable
  #23 = Utf8               
  #24 = Utf8               SourceFile
  #25 = Utf8               IncrementClass.java
  #26 = NameAndType        #10:#11        //  "":()V
  #27 = NameAndType        #9:#8          //  i:I <-- Constant representing the integer variable 'i'
  #28 = NameAndType        #7:#8          //  j:I <-- Constant representing the integer variable 'j'
  #29 = Utf8               com/salil/threads/IncrementClass
  #30 = Utf8               java/lang/Object
{
  static volatile int j;
    flags: ACC_STATIC, ACC_VOLATILE <-- The flag telling the JVM that the variable 'j' is volatile and hence to insert 
                                                                     <-- the necessary memory barriers while accessing this variable

  static int i;
    flags: ACC_STATIC

  public com.salil.threads.IncrementClass();
    flags: ACC_PUBLIC

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return        
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Lcom/salil/threads/IncrementClass;

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC

    Code:
      stack=2, locals=2, args_size=1
  

     //The byte code generated for our for loop
         0: iconst_0                          <-- Push '0' on the operand stack  
         1: istore_1                           <-- Pop '0' out of the operand stack and set it as the value of local variable 1
         2: iload_1                             <-- Push the value of the local variable 1 onto the operand stack      
         3: ldc           #2            // int 1000000 <-- Push the constant no. 2 from the constant pool onto the operand stack
         5: if_icmpge     14               <-- Pop the top two values out of the operand stack if the first value
                                                            popped is greater than or equal to the second jump to step 14 -->
         8: iinc          1, 1                   <-- Increment local variable 1 which is i by 1
        11: goto          2                     <-- jump to step 2
        //End of the for loop
  

    //Increment i
        14: getstatic     #3  // Field i:I <-- Get the value of constant pool #3 (i) and push it onto the operand stack
        17: iconst_1      <-- Push the constant 1 onto the operand stack 
        18: iadd          <-- Add the values on the operand stack and push the result onto  the operand stack
        19: putstatic     #3   // Field i:I <-- pop the value from the stack and set it in i
    //End of Increment i
  

    //Increment j <-- Same as what was done for i increment j
        22: getstatic     #4                  // Field j:I
        25: iconst_1      
        26: iadd          
        27: putstatic     #4                  // Field j:I
    //End of Increment j
        30: return        
      LineNumberTable:
        line 10: 0
        line 11: 14
        line 12: 22
        line 15: 30
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               2      12     1     a   I
               0      31     0  args   [Ljava/lang/String;
      StackMapTable: number_of_entries = 2
           frame_type = 252 /* append */
             offset_delta = 2
        locals = [ int ]
           frame_type = 250 /* chop */
          offset_delta = 11


  static {};
    flags: ACC_STATIC

    Code:
      stack=1, locals=0, args_size=0
         0: iconst_0      
         1: putstatic     #4                  // Field j:I
         4: iconst_0      
         5: putstatic     #3                  // Field i:I
         8: return        
      LineNumberTable:
        line 5: 0
        line 6: 4
}

As you can see a few lines of code has turned into several lines of java opcode. To make sense of this we will have to look at the JVM 7 specifications. The areas of interest I have marked in red and comments that I have added are preceded by <– and looked this <– A comment I made.

The first area of interest are a few declarations in the constant pool. The constant # 2 is the ‘1000000’ which is used in our for loop. The other two constants of interest are #27 and #28 which are field references to i and j respectively.

Next area marked in red  is the ACC_VOLATILE flag marking the variable j as a volatile variable and you will that variable ‘i’ immediately below it is marked as static but not volatile.

In the next red marked section we go to the actual java opcodes that perform the operations we specified in the code. To understand these opcodes go to the JVM instruction set section of the specifications. Instructions 0 to 11 is the for loop. Read through my comments in red to understand how the for loop is achieved.

Next look at the opcodes to increment i and then look at the opcodes to increment j. As you can see that both these opcodes look exactly similar except that they are referencing different constants for the constant pool. But variable ‘j’ is volatile so how does the Java Compiler signal to the JVM to protect the variable if the opcodes for volatile and normal variables are exactly the same. The answer lies in the flag marking ‘j’ as volatile. The JVM reads this flag and then at runtime executes the appropriate assembly level instructions to protect j. We shall see this in the next post.

 

 

Advertisements

Posted January 1, 2015 by salilsurendran in Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: