Possible contradiction between JLS and Sun's Java compiler

O

Oliver Wong

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
 
M

Monique Y. Mudama

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.

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.
 
E

Eric Sosman

Oliver Wong wrote On 02/09/06 15:22,:
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.

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.
 
C

Chris Uppal

Oliver said:
<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
 
O

Oliver Wong

Monique Y. Mudama said:
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
 
O

Oliver Wong

Chris Uppal said:
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
 
E

Eric Sosman

Oliver Wong wrote On 02/09/06 16:12,:
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>

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.
 
O

Oliver Wong

Eric Sosman said:
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
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.

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
 
M

Monique Y. Mudama

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.
 
R

Roedy Green

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top