> From: Mark Thomas [mailto:ma...@apache.org] > Subject: Re: RV-Predict bugs
> To re-cap. The assertion is that > === > String foo; > doSomething() { > if (foo == null) { > foo = calculateNewValue(); > } > return foo; > } > === > can be transformed (by the complier?) to > === > String foo; > String bar; > doSomething() { > bar = foo; > if (foo == null) { > foo = calculateNewValue(); > bar = foo; > } > return bar; > } > === > Ignoring re-ordering this transformation creates an obvious concurrency > issue (foo is changed from null to non-null after its value is copied to > bar and before foo is tested for null). Correct. That changed the original logic of the method, creating a timing window that wasn't there before. In compiler language (see below), it rematerialized a load for a shared memory location. > The questions I have are: > 1. Is such a transformation legal? I assume the answer is yes but I've > been struggling to find the language in the JLS that permits this. Is it > 17.4 "An implementation is free to produce any code it likes, as long as > all resulting executions of a program produce a result that can be > predicted by the memory model."? > 2. Why would something make a transformation like this? This brings us > back to the question of theoretical issues vs. practical issues which > helps us judge the severity of any given issue. 1. No (at least not in the real world). 2. Compiler bug. An analogous example is the one-time gcc error that transformed if (a == 0) a = 1; into temp = a; if (temp == 0) temp = 1; a = temp; This caused immense havoc, besides being a performance killer. For reference, read the LLVM spec for concurrency handling: http://llvm.org/docs/Atomics.html In particular, this section on instruction ordering: http://llvm.org/docs/Atomics.html#atomic-orderings Note the difference in implementation between handling shared variables in C/C++ (NotAtomic) and shared variables in Java (Unordered). (For those not familiar with LLVM, it's the compilation tool chain used for OS X, iOS, Android, PS4, and many other platforms.) The key bit of information pertinent to Java is this: "In terms of the optimizer, this prohibits any transformation that transforms a single load into multiple loads, transforms a store into multiple stores, narrows a store, or stores a value which would not be stored otherwise. Some examples of unsafe optimizations are narrowing an assignment into a bitfield, *rematerializing a load*, and turning loads and stores into a memcpy call. Reordering unordered operations is safe, though, and optimizers should take advantage of that because unordered operations are common in languages that need them." The above may go beyond the theoretical limitations of the memory model, but is representative of what compilers must do in order to generate workable programs in the real world. This isn't academia, it's business. I think I'm done here. - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org