Java Forum / General / February 2006
Possible contradiction between JLS and Sun's Java compiler
Oliver Wong - 09 Feb 2006 20:22 GMT From the JLS 3rd edition:
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.26
<quote> a=b=c means a=(b=c), which assigns the value of c to b and then assigns the value of b to a. </quote>
I'm inferring that if "a" and "c" are double precision floating points, and "b" is a single precision floating point, then the assignment from "c" to "b" may result in some rounding, and the assignment to "a" will give "a" the rounded value in "b", and not the original value from "c".
However, a friend of mine said when they disassembled the code produced by javac essentially says "read c; duplicate; write b; write a;" which seems to contradict what the JLS claims.
I'm at work right now, and I don't have easy access to a class file disassembler, so I was wondering if someone could verify whether JavaC and the JLS really do contradict each other for me.
- Oliver
Monique Y. Mudama - 09 Feb 2006 20:37 GMT > From the JLS 3rd edition: > [quoted text clipped - 17 lines] > disassembler, so I was wondering if someone could verify whether JavaC and > the JLS really do contradict each other for me. You seem to be talking about the Sun jre specifically ...
It doesn't seem like a violation of the spec to make something behave with better precision than is promised in the spec.
 Signature monique
Ask smart questions, get good answers: http://www.catb.org/~esr/faqs/smart-questions.html
Oliver Wong - 09 Feb 2006 21:06 GMT >> From the JLS 3rd edition: >> [quoted text clipped - 26 lines] > > You seem to be talking about the Sun jre specifically ... I think this is a "compile-time" issue, in that assuming the JLS is correct, the implementation of Javac is emitting an incorrect sequence of bytecode (if my friend's claim is actually true). So, I am indeed speaking of Sun's specific implementation (e.g. perhaps other compilers, like the Sable Java Compiler, emits the correct bytecode), but it'd be more of a JDK issue than a JRE one, if anything.
> It doesn't seem like a violation of the spec to make something behave > with better precision than is promised in the spec. Software might intentionally be using the fact that "a" should contain the rounded value, and would behave incorrectly if they got the higher-precision value.
It seems strange to me that Sun would overlook this, since they spend a large amount of time in the JLS, for example, explaining the concept of "FP-Strict" modes:
<quote> Within an FP-strict expression, all intermediate values must be elements of the float value set or the double value set, implying that the results of all FP-strict expressions must be those predicted by IEEE 754 arithmetic on operands represented using single and double formats. Within an expression that is not FP-strict, some leeway is granted for an implementation to use an extended exponent range to represent intermediate results; the net effect, roughly speaking, is that a calculation might produce "the correct answer" in situations where exclusive use of the float value set or double value set might result in overflow or underflow. </quote>
- Oliver
Monique Y. Mudama - 09 Feb 2006 23:42 GMT >> It doesn't seem like a violation of the spec to make something >> behave with better precision than is promised in the spec. > > Software might intentionally be using the fact that "a" should > contain the rounded value, and would behave incorrectly if they > got the higher-precision value. I'm sorry; somehow I completely glossed over the mixing of double and float in your description. That obviously makes a difference.
 Signature monique
Ask smart questions, get good answers: http://www.catb.org/~esr/faqs/smart-questions.html
Eric Sosman - 09 Feb 2006 20:58 GMT Oliver Wong wrote On 02/09/06 15:22,:
> From the JLS 3rd edition: > [quoted text clipped - 17 lines] > disassembler, so I was wondering if someone could verify whether JavaC and > the JLS really do contradict each other for me. Using javac 1.4.2_04-b05, this source
public class Assign { public static void main(String[] unused) { double d1 = Math.PI; float f; double d2; d2 = f = (float)d1; System.out.println(d2 == d1); } }
... compiles to this bytecode (as shown by javap):
public class Assign extends java.lang.Object{ public Assign(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return
public static void main(java.lang.String[]); Code: 0: ldc2_w #2; //double 3.141592653589793d 3: dstore_1 4: dload_1 5: d2f 6: dup 7: fstore_3 8: f2d 9: dstore 4 11: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream; 14: dload 4 16: dload_1 17: dcmpl 18: ifne 25 21: iconst_1 22: goto 26 25: iconst_0 26: invokevirtual #5; //Method java/io/PrintStream.println:(Z)V 29: return
}
... and produces this output when executed:
false
... so your friend is mistaken, at least for this version.
 Signature Eric.Sosman@sun.com
Chris Uppal - 09 Feb 2006 21:05 GMT > <quote> > a=b=c means a=(b=c), which assigns the value of c to b and then assigns > the value of b to a. > </quote> [...]
> However, a friend of mine said when they disassembled the code > produced by javac essentially says "read c; duplicate; write b; write a;" > which seems to contradict what the JLS claims. The following code will not compile under JDK1.4.2 or 1.5.0. ========== class Abc { static void method() { double a; float b; double c = 27.3;
a = b = c; } }
==========
The compiler won't accept it without a cast of c to float. With the cast it (1.4 and 1.5) produce the bytecode you'd expect (with converstions from double to float and back again). Note, btw, that b takes up 1 stack slot while a and c take up 2 each -- which makes it hard to see how the compiler could "get away" with generating incorect code.
FWIW, the actual disassembly is: ldc2_w 27.3 dstore_3 dload_3 d2f dup fstore_2 f2d dstore_0 return
Perhaps your friend has a more complicated example ?
-- chris
Oliver Wong - 09 Feb 2006 21:12 GMT > Perhaps your friend has a more complicated example ? Yeah, I guess I should just quote the message he wrote:
<quote> I think that the bytecode produced by javac just doesn't follow the given clausule in the language spec, as the value assigned to a is the value directly read from c.
I have no idea whether this means anything (e.g. with volatile variables and multiple writer threads to b in practise. Having e.g. two threads such that thread 1) while(true) { a = b = 1;
if(a == 2) { System.out.println("foobar"); } }
and then there's another thread 2) while(true) { b = 2; }
Under my understanding, using JLS semantics (the variables are volatile..), this 'foobar' would be "sometime" written. Using javac semantics, it is never written. </quote>
- Oliver
Eric Sosman - 09 Feb 2006 22:09 GMT Oliver Wong wrote On 02/09/06 16:12,:
>>Perhaps your friend has a more complicated example ? > [quoted text clipped - 26 lines] > semantics, it is never written. > </quote> Okay, this is a little different from the example in the posting that started the thread. I think your friend is misunderstanding the JLS. Your friend can be forgiven, because the quoted bit of JLS ("assigns the value of c to b and then assigns the value of b to a") is imprecise. Presumably, the JLS authors were trying to make the document more understandable, so they put in little snippets of less formal language to get their points across.
However, the quoted piece comes from a short paragraph describing the right-to-left associativity of assignment, not the values assigned. A little further along in the section we find
"... the result of the assignment expression is the value of the variable after the assignment has occurred."
Even this is a little fuzzy, but I do not believe this can be construed as requiring an actual read of `b' after assigning to it (how long after the assignment should the read occur?), but as a shorthand way to say that the result is the value assigned to the `b'.
Your friend seems to think `a = b = 1;' is equivalent to `b = 1; a = b;', with the possiblity that `b' might be modified between the two assignments. Instead, I think he should read it as `a = (b = 1);', emphasizing that `a' is set to the result of the assignment expression `b = 1', and that this is `1' converted to the type of `b'. So the compiler is justified in producing the same bytecode as for `b = 1; a = 1;', because the value of `b = 1' is 1.
 Signature Eric.Sosman@sun.com
Oliver Wong - 09 Feb 2006 22:47 GMT > Okay, this is a little different from the example > in the posting that started the thread. Yes, I had previously (erroneously) assumed that the two examples illustrated the same issue, but that the one with floats and doubles was easier to understand, which was why I went for that one first.
> I think your > friend is misunderstanding the JLS. Your friend can be [quoted text clipped - 28 lines] > compiler is justified in producing the same bytecode as > for `b = 1; a = 1;', because the value of `b = 1' is 1. I had to re-read your explanation and the appropriate sections of the JLS 3 or 4 times, but I think I got it now, and what you say makes sense. Thanks.
- Oliver
Roedy Green - 10 Feb 2006 04:16 GMT >a=b=c means a=(b=c) that sort of code is begging for trouble. It confuses maintenance programmers and attracts implementation bugs since it is not obvious how it should behave. Only lawyers can decide.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|