I’m doing ZigZag encoding on 32bit integers with Dart. This is the source code that I’m using:
int _encodeZigZag(int instance) => (instance << 1) ^ (instance >> 31); int _decodeZigZag(int instance) => (instance >> 1) ^ (-(instance & 1));
The code works as expected in the DartVM.
But in dart2js the
_decodeZigZag function is returning invalid results if I input negativ numbers. For example
-10 is encoded to
19 and should be decoded back to
-10, but it is decoded to
4294967286. If I run
return ($.JSNumber_methods.$shr(instance, 1) ^ -(instance & 1)) >>> 0;
Why does Dart2Js adds a usinged right shift by 0 to the function? Without the shift, the result would be as expected.
Or is my Dart code wrong?
PS: Also tested splitting up the XOR into other operations, but Dart2Js is still adding the right shift:
final a = -(instance & 1); final b = (instance >> 1); return (a & -b) | (-a & b);
a = -(instance & 1); b = $.JSNumber_methods.$shr(instance, 1); return (a & -b | -a & b) >>> 0;
For efficiency reasons dart2js compiles Dart numbers to JS numbers. JS, however, only provides one number type: doubles. Furthermore bit-operations in JS are always truncated to 32 bits.
In many cases (like cryptography) it is easier to deal with unsigned 32 bits, so dart2js compiles bit-operations so that their result is an unsigned 32 bit number.
Neither choice (signed or unsigned) is perfect. Initially dart2js compiled to signed 32 bits, and was only changed when we tripped over it too frequently. As your code demonstrate, this doesn’t remove the problem, just shifts it to different (hopefully less frequent) use-cases.
Non-compliant number semantics have been a long-standing bug in dart2js, but fixing it will take time and potentially slow down the resulting code. In the short-term future Dart developers (compiling to JS) need to know about this restriction and work around it.
Answered By – Florian Loitsch
Answer Checked By – Terry (FlutterFixes Volunteer)