gwtproject / gwt

GWT Open Source Project
http://www.gwtproject.org
1.52k stars 374 forks source link

Regression with long emulation #9714

Open yoseph-phillips opened 3 years ago

yoseph-phillips commented 3 years ago

GWT version: 2.9 Browser (with version): Chrome 86.0.4240.193 Operating System: Windows

Description

The following snippet now enters an infinite loop. This was most likely caused by performance enhancements in 2.8. This was working in 2.5.1. It seems to now be treating longs as 44 bit numbers instead of a pair of 32 bit ints. On about the 44th iteration it is now calculating lastReturned = unseen & -unseen; incorrectly.

long unseen = -1;
long lastReturned = 0;
while (unseen != 0) {
  lastReturned = unseen & -unseen;
  unseen -= lastReturned;
}
Steps to reproduce

Run the code above.

yoseph-phillips commented 3 years ago

It looks like the bug is in LongLib.toBigLong(SmallLong longValue). When it attempts to convert a double with value 2 ^ 44 it is forgetting about the high bits.

Adding an else section such as:

private static BigLong toBigLong(SmallLong longValue) {
    double value = asDouble(longValue);
    int a3 = 0;
    if (value < 0) {
      // Convert to a positive number that will have the exact same first 44 bits
      value += BigLongLibBase.TWO_PWR_44_DBL;
      a3 = BigLongLib.MASK_2;
    } else {
      a3 = (int) (value / BigLongLibBase.TWO_PWR_44_DBL);
      value -= a3 * BigLongLibBase.TWO_PWR_44_DBL;
    }
    int a1 = (int) (value / BigLongLibBase.TWO_PWR_22_DBL);
    int a0 = (int) (value - a1 * BigLongLibBase.TWO_PWR_22_DBL);
    return BigLongLibBase.create(a0, a1, a3);
  }

will probably solve this issue.