assembly - Understanding volatile and non-volatile read/write in Java -


my java code follows

public class myclass {     volatile int voltile ;  //7     int nonvoltile ;   //8      public static void main(string[] args) {         for(int i=1; i<100000; i++){             f();         }     }      static void f(){   //16         myclass t = new myclass();  //17         t.voltile = t.nonvoltile;  //18          t.nonvoltile = 0x11111; //20         t.voltile = 0x22222;  //21          t.nonvoltile = t.nonvoltile + 1; //23         t.voltile = t.voltile + 1; //24      } } 

generated assembly snippets function "f" follows

for volatile write

  0x024c73ff: mov    0xc(%esi),%eax   0x024c7402: mov    %eax,0x8(%esi)   0x024c7405: lock addl $0x0,(%esp)     ;*putfield voltile                                         ; - j.assembly.myclass::f@13 (line 18) 

i have following questions

  1. why 2 move instructions above? why not directly mov 0xc(%esi) 0x8(%esi)
  2. what use of 0x024c7405: lock addl $0x0,(%esp)?

for volatile read

  0x024c7425: mov    0x8(%esi),%eax     ;*getfield voltile                                         ; - j.assembly.myclass::f@40 (line 24) 

only single read instruction generated

  1. is volatile read happening main memory?
  2. why nothing lock addl instruction lock used there volatile write?

as asked pasting complete assembly

compileroracle: print *myclass.f compiled method (c1)     142   14   !         j.assembly.myclass::f (81 bytes)  total in heap  [0x024c72c8,0x024c77d8] = 1296  relocation     [0x024c7398,0x024c73bc] = 36  main code      [0x024c73c0,0x024c7600] = 576  stub code      [0x024c7600,0x024c7620] = 32  oops           [0x024c7620,0x024c7624] = 4  metadata       [0x024c7624,0x024c7628] = 4  scopes data    [0x024c7628,0x024c76a4] = 124  scopes pcs     [0x024c76a4,0x024c77d4] = 304  dependencies   [0x024c77d4,0x024c77d8] = 4 loaded disassembler hsdis-i386.dll decoding compiled method 0x024c72c8: code: [disassembling mach='i386'] [entry point] [verified entry point] [constants]   # {method} {0x14830304} 'f' '()v' in 'j/assembly/myclass'   #           [sp+0x40]  (sp of caller)   0x024c73c0: mov    %eax,0xffffc000(%esp)   0x024c73c7: push   %ebp   0x024c73c8: sub    $0x38,%esp   0x024c73cb: mov    $0x14830350,%edx   ;   {metadata('j/assembly/myclass')}   0x024c73d0: mov    %fs:0x0,%ecx   0x024c73d8: mov    0xfffffff4(%ecx),%ecx   0x024c73db: mov    0x34(%ecx),%eax   0x024c73de: lea    0x10(%eax),%edi   0x024c73e1: cmp    0x3c(%ecx),%edi   0x024c73e4: ja     0x024c7589   0x024c73ea: mov    %edi,0x34(%ecx)   0x024c73ed: mov    0x60(%edx),%ecx   0x024c73f0: mov    %ecx,(%eax)   0x024c73f2: mov    %edx,0x4(%eax)   0x024c73f5: xor    %ecx,%ecx   0x024c73f7: mov    %ecx,0x8(%eax)   0x024c73fa: mov    %ecx,0xc(%eax)   0x024c73fd: mov    %eax,%esi          ;*new  ; - j.assembly.myclass::f@0 (line 17)    0x024c73ff: mov    0xc(%esi),%eax   0x024c7402: mov    %eax,0x8(%esi)   0x024c7405: lock addl $0x0,(%esp)     ;*putfield voltile                                         ; - j.assembly.myclass::f@13 (line 18)    0x024c740a: movl   $0x11111,0xc(%esi)  ;*putfield nonvoltile                                         ; - j.assembly.myclass::f@19 (line 20)    0x024c7411: mov    $0x22222,%eax   0x024c7416: mov    %eax,0x8(%esi)   0x024c7419: lock addl $0x0,(%esp)     ;*putfield voltile                                         ; - j.assembly.myclass::f@25 (line 21)    0x024c741e: movl   $0x11112,0xc(%esi)  ;*putfield nonvoltile                                         ; - j.assembly.myclass::f@35 (line 23)    0x024c7425: mov    0x8(%esi),%eax     ;*getfield voltile                                         ; - j.assembly.myclass::f@40 (line 24)    0x024c7428: inc    %eax   0x024c7429: mov    %eax,0x8(%esi)   0x024c742c: lock addl $0x0,(%esp)     ;*putfield voltile                                         ; - j.assembly.myclass::f@45 (line 24)    0x024c7431: lea    0x20(%esp),%edi   0x024c7435: mov    %esi,0x4(%edi)   0x024c7438: mov    (%esi),%eax   0x024c743a: mov    %eax,%ebx   0x024c743c: ,    $0x7,%ebx   0x024c743f: cmp    $0x5,%ebx   0x024c7442: jne    0x024c74ca   0x024c7448: mov    %eax,(%edi)   0x024c744a: mov    0x4(%esi),%ebx   0x024c744d: mov    0x60(%ebx),%ebx   0x024c7450: xor    %eax,%ebx   0x024c7452: mov    %fs:0x0,%eax   0x024c745a: mov    0xfffffff4(%eax),%eax   0x024c745d: xor    %ebx,%eax   0x024c745f: ,    $0xffffff87,%eax   0x024c7462: je     0x024c74eb   0x024c7468: test   $0x7,%eax   0x024c746d: jne    0x024c74be   0x024c746f: test   $0x180,%eax   0x024c7474: jne    0x024c749a   0x024c7476: mov    (%edi),%eax   0x024c7478: ,    $0x1ff,%eax   0x024c747e: mov    %fs:0x0,%ebx   0x024c7486: mov    0xfffffff4(%ebx),%ebx   0x024c7489: or     %eax,%ebx   0x024c748b: lock cmpxchg %ebx,(%esi)   0x024c748f: jne    0x024c7595   0x024c7495: jmp    0x024c74eb   0x024c749a: mov    0x4(%esi),%ebx   0x024c749d: mov    0x60(%ebx),%ebx   0x024c74a0: mov    %fs:0x0,%eax   0x024c74a8: mov    0xfffffff4(%eax),%eax   0x024c74ab: or     %eax,%ebx   0x024c74ad: mov    (%edi),%eax   0x024c74af: lock cmpxchg %ebx,(%esi)   0x024c74b3: jne    0x024c7595   0x024c74b9: jmp    0x024c74eb   0x024c74be: mov    (%edi),%eax   0x024c74c0: mov    0x4(%esi),%ebx   0x024c74c3: mov    0x60(%ebx),%ebx   0x024c74c6: lock cmpxchg %ebx,(%esi)   0x024c74ca: mov    (%esi),%eax   0x024c74cc: or     $0x1,%eax   0x024c74cf: mov    %eax,(%edi)   0x024c74d1: lock cmpxchg %edi,(%esi)   0x024c74d5: je     0x024c74eb   0x024c74db: sub    %esp,%eax   0x024c74dd: ,    $0xfffff003,%eax   0x024c74e3: mov    %eax,(%edi)   0x024c74e5: jne    0x024c7595         ;*monitorenter                                         ; - j.assembly.myclass::f@51 (line 26)    0x024c74eb: mov    0xc(%esi),%eax     ;*getfield nonvoltile                                         ; - j.assembly.myclass::f@54 (line 27)    0x024c74ee: inc    %eax   0x024c74ef: mov    %eax,0xc(%esi)     ;*putfield nonvoltile                                         ; - j.assembly.myclass::f@59 (line 27)    0x024c74f2: mov    0x8(%esi),%eax     ;*getfield voltile                                         ; - j.assembly.myclass::f@64 (line 28)    0x024c74f5: inc    %eax   0x024c74f6: mov    %eax,0x8(%esi)   0x024c74f9: lock addl $0x0,(%esp)     ;*putfield voltile                                         ; - j.assembly.myclass::f@69 (line 28)    0x024c74fe: lea    0x20(%esp),%eax   0x024c7502: mov    0x4(%eax),%edi   0x024c7505: mov    (%edi),%esi   0x024c7507: ,    $0x7,%esi   0x024c750a: cmp    $0x5,%esi   0x024c750d: je     0x024c7527   0x024c7513: mov    (%eax),%esi   0x024c7515: test   %esi,%esi   0x024c7517: je     0x024c7527   0x024c751d: lock cmpxchg %esi,(%edi)   0x024c7521: jne    0x024c75a6         ;*monitorexit                                         ; - j.assembly.myclass::f@73 (line 26)    0x024c7527: add    $0x38,%esp   0x024c752a: pop    %ebp   0x024c752b: test   %eax,0xdd0100      ;   {poll_return}   0x024c7531: ret                       ;*return                                         ; - j.assembly.myclass::f@80 (line 30)    0x024c7532: mov    %fs:0x0,%esi   0x024c753a: mov    0xfffffff4(%esi),%esi   0x024c753d: mov    0x1a4(%esi),%eax   0x024c7543: movl   $0x0,0x1a4(%esi)   0x024c754d: movl   $0x0,0x1a8(%esi)   0x024c7557: mov    %eax,%esi   0x024c7559: lea    0x20(%esp),%eax   0x024c755d: mov    0x4(%eax),%ebx   0x024c7560: mov    (%ebx),%edi   0x024c7562: ,    $0x7,%edi   0x024c7565: cmp    $0x5,%edi   0x024c7568: je     0x024c7582   0x024c756e: mov    (%eax),%edi   0x024c7570: test   %edi,%edi   0x024c7572: je     0x024c7582   0x024c7578: lock cmpxchg %edi,(%ebx)   0x024c757c: jne    0x024c75b7         ;*monitorexit                                         ; - j.assembly.myclass::f@78 (line 26)    0x024c7582: mov    %esi,%eax   0x024c7584: jmp    0x024c75ec   0x024c7589: mov    %edx,%edx   0x024c758b: call   0x024bc740         ; oopmap{off=464}                                         ;*new  ; - j.assembly.myclass::f@0 (line 17)                                         ;   {runtime_call}   0x024c7590: jmp    0x024c73fd   0x024c7595: mov    %esi,0x4(%esp)   0x024c7599: mov    %edi,(%esp)   0x024c759c: call   0x024bdc40         ; oopmap{esi=oop [36]=oop off=481}                                         ;*monitorenter                                         ; - j.assembly.myclass::f@51 (line 26)                                         ;   {runtime_call}   0x024c75a1: jmp    0x024c74eb   0x024c75a6: lea    0x20(%esp),%eax   0x024c75aa: mov    %eax,(%esp)   0x024c75ad: call   0x024bde00         ;   {runtime_call}   0x024c75b2: jmp    0x024c7527   0x024c75b7: lea    0x20(%esp),%eax   0x024c75bb: mov    %eax,(%esp)   0x024c75be: call   0x024bde00         ;   {runtime_call}   0x024c75c3: jmp    0x024c7582   0x024c75c5: nop       0x024c75c6: nop       0x024c75c7: mov    %fs:0x0,%esi   0x024c75cf: mov    0xfffffff4(%esi),%esi   0x024c75d2: mov    0x1a4(%esi),%eax   0x024c75d8: movl   $0x0,0x1a4(%esi)   0x024c75e2: movl   $0x0,0x1a8(%esi)   0x024c75ec: add    $0x38,%esp   0x024c75ef: pop    %ebp   0x024c75f0: jmp    0x024bbec0         ;   {runtime_call}   0x024c75f5: hlt       0x024c75f6: hlt       0x024c75f7: hlt       0x024c75f8: hlt       0x024c75f9: hlt       0x024c75fa: hlt       0x024c75fb: hlt       0x024c75fc: hlt       0x024c75fd: hlt       0x024c75fe: hlt       0x024c75ff: hlt     [exception handler] [stub code]   0x024c7600: call   0x024bd6c0         ;   {no_reloc}   0x024c7605: push   $0x77f387fc        ;   {external_word}   0x024c760a: call   0x024c760f   0x024c760f: pusha     0x024c7610: call   0x77e22130         ;   {runtime_call}   0x024c7615: hlt     [deopt handler code]   0x024c7616: push   $0x24c7616         ;   {section_word}   0x024c761b: jmp    0x0245c2b0         ;   {runtime_call} oopmapset contains 2 oopmaps  #0  oopmap{off=464} #1  oopmap{esi=oop [36]=oop off=481} picked _java_options: -djava.net.preferipv4stack=true java hotspot(tm) client vm warning: printing of assembly code enabled; turning on debugnonsafepoints gain additional output 

what see in generated disassembly peculiarity of java volatile fields.
topic cannot explained briefly because arises the way cpus evolved , works, put, given instructions:

 thread 0                       thread 1  int x = 0, y = 0;              while (y==0);  x = 1;                         int z = x, w = y;  y = x + 1; 

thread 1 can ends z=0 , w=2.
not want. better understand why happen refer this great blog or this nice text.

to address problem java define memory model, can read more in chapter 17.4 of java language specification.
in model defined relationship between instructions called happen-before , such relationship ensures every side-effect of instruction happen-before instruction visible latter.
put guarantees have no nasty surprise in example above, where, being in 2 different thread, instructions x = 1 , int z = x not in happen-before relationship , there no guarantee write x visible thread (there guarantee visible thread 0).

the chapter 17.4 lists makes 2 instructions in happen-before relationship, example being in same thread.
condition make 2 instructions in such relationship being kind of relationship: synchronize-with relationship.
java volatile field generate synchronize-with between write , read field. strong condition!
put: volatile -> synchronize-with -> happen-before -> serialization of side effects.

so java volatile mechanism of synchronization can used instead of lock.

in order satisfy happen-before relationship between threads necessary use memory barrier.

you compiled java code ia32 architecture, a.k.a. x86. there various fence instructions in such architecture dedicated fine tuning. , there raw serializing instructions: these instructions guarantee every other instruction before, including side effects, completed before serializing 1 completed.
barriers of poor man.

  lock addl $0x0,(%esp) 

as can see instruction nothing, adds 0 dword @ esp, using lock prefix, which serializing, therefore acting memory barrier. heavy 1 honest.

the other questions of answer:

  • there 2 moves because reading nonvoltile (first move) , writing voltile (second move).
  • the volatile read don't need barrier because 1 used every write voltile serializes both write , read operations.
  • the volatile read happens main memory if don't consider cache hierarchy. note considering first of 3 instructions increment field.

Comments

Popular posts from this blog

sublimetext3 - what keyboard shortcut is to comment/uncomment for this script tag in sublime -

java - No use of nillable="0" in SOAP Webservice -

ubuntu - Laravel 5.2 quickstart guide gives Not Found Error -