United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6442508 Casting yields wrong results
JDK-6442508 : Casting yields wrong results

Details
Type:
Bug
Submit Date:
2006-06-23
Status:
Resolved
Updated Date:
2010-04-02
Project Name:
JDK
Resolved Date:
2006-07-11
Component:
hotspot
OS:
windows_xp
Sub-Component:
compiler
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Duplicate:

Sub Tasks

Description
FULL PRODUCT VERSION :
any 1.6beta client VM

FULL OS VERSION :
WindowsXP ver 2002 SP2

A DESCRIPTION OF THE PROBLEM :
I am working on a Sega Genesis Emulator and after seeing it fail on any 1.6beta client VM, i made some tests and found the first point, where something is going wrong. I use the following code to sign extend 16bit values in my CPU emulator:

for example:
int EffectiveAddress  =  ((short)(memory.fetchOpWord(PC)&0xFFFF));

At a certain time fetchOpWord returns 0xF62A, for example. In any VM except the 1.6client this leads to EffectiveAddress = 0xFFFFF62A, while in the 1.6clients it becomes EffectiveAddress = 0xF62A.
So it doesnt get sign extended.
This always happens at this point and by the behavior i can see during emulation, i am sure the same happens in other locations as well.

It does not happen using the -Xint option, nor in the server VM.

I suspect the reason is "&0xFFFF" gets executed AFTER the cast, because leaving it out leads to the correct result.


THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: No

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected:
 ((short)(0xF000 & 0xFFFF)) = 0xFFFFF000;

Actual:
 ((short)(0xF000 & 0xFFFF)) = 0xF000;
REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
    void test(){
        int i, ea;
        for(i=0; i<=0xFFFF; i++){
            ea = ((short)(i&0xFFFF));
            System.out.println( Integer.toHexString(i) + " : " + Integer.toHexString(ea) );
        }
    }
---------- END SOURCE ----------

                                    

Comments
SUGGESTED FIX

*** /tmp/geta26677	Thu Jun 22 18:09:26 2006
--- c1_Canonicalizer.cpp	Thu Jun 22 17:19:51 2006
***************
*** 483,490 ****
        jint mask = op2->y()->type()->as_IntConstant()->value();
        switch (x->op()) {
          case Bytecodes::_i2b: safebits = 0x7f;   break;
!         case Bytecodes::_i2s: safebits = 0xffff; break;
!         case Bytecodes::_i2c: safebits = 0x7fff; break;
        }
        if (safebits && (mask & ~safebits) == 0) {
          set_canonical(x->value());
--- 483,490 ----
        jint mask = op2->y()->type()->as_IntConstant()->value();
        switch (x->op()) {
          case Bytecodes::_i2b: safebits = 0x7f;   break;
!         case Bytecodes::_i2s: safebits = 0x7fff; break;
!         case Bytecodes::_i2c: safebits = 0xffff; break;
        }
        if (safebits && (mask & ~safebits) == 0) {
          set_canonical(x->value());
                                     
2006-06-23
EVALUATION

The i2s and i2c cases are swapped in one of the identity tranformations.  When anding with a mask that doesn't include the sign bit the sign extending conversions can be elided.  Unfortunately the i2s case was allowing the sign bit to get involved so we ended skipping the sign extension when we shouldn't have.
                                     
2006-06-23
SUGGESTED FIX

http://analemma.sfbay.sun.com/net/prt-archiver.sfbay/data/archived_workspaces/main/c2_baseline/2006/20060626153903.never.sux/workspace/webrevs/webrev-2006.06.26/index.html
                                     
2006-06-27



Hardware and Software, Engineered to Work Together