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
- why 2 move instructions above? why not directly mov 0xc(%esi) 0x8(%esi)
- 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
- is volatile read happening main memory?
- 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) , writingvoltile
(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
Post a Comment