-
Notifications
You must be signed in to change notification settings - Fork 1.7k
dart2js: bitwise operators truncated to 32 bits #8298
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This is actually working as intended for now. The bitwise operations are truncated to 32-bit unsigned values because JavaScript's bitwise operations only work on 32-bit (signed or unsigned) values. It makes a lot of sense to strive for making Dart compiled to JavaScript deal nicely with 32-bit numbers and bitwise operations. Are you being burnt by the fact that we always produce unsigned results? If you have an example of an algorithm written in JS that use 32-bit numbers and manipulate them with bitwise operations that's hard to port to Dart, I would be very interested in taking a look. Added Area-Dart2JS, NeedsInfo labels. |
Added this to the Later milestone. |
This comment was originally written by [email protected] Here's an example, gzip: https://github.com/beatgammit/gzip-js On line 84 of lib/gzip.js, I have to a nasty hack to get a 64-bit long (mtime) from a file. Here's a link to that specific line: https://github.com/beatgammit/gzip-js/blob/master/lib/gzip.js#L84 The problem is, some operations are signed, some are unsigned. The logical | appears to be signed, which makes absolutely no sense to me. The same applies to left shift (<<) and right shift (>>), which are both signed. There's no unsigned left shift that I've found. For example, in JS: 0xffffffff | 0 == -1 And in Dart: 0xffffffff | 0 == 4294967295 I couldn't find any documentation in the Dart spec about signed vs unsigned numbers. I also couldn't find anything specific about whether the | is supposed to be signed in EcmaScript, but it appears to be implemented that way in every implementation I've tried. |
FWIW, the only bitwise operation in JS that gives an unsigned 32-bit result is >>>. All the others give you a signed 32-bit result. In Dart, we've decided to keep the result of all bitwise operations unsigned 32-bit values when compiling to JavaScript. The intent was to make it easier to make your code work on both the Dart VM and using dart2js. |
This comment was originally written by [email protected] After further investigation, my contrived example that lead me to complain was shifting by more than 32 bits and back again. The Dart2js implementation only allows shifts of up to 31 bits, which makes sense for a 32-bit limit. I haven't been able to break it again since, so it seems that the implementation is correct for 32 bits. It would be nice to have support for larger integers but I personally don't have a need yet. I'm removing my star because my intent for this issue was actually a misunderstanding. |
Thanks for the extra information! Updating bug summary to "truncated to 32 bits" and marking this "as designed" for now. Added AsDesigned label. |
This may be how dart2js is currently designed, but I'm not sure this is how Dart is designed. Shouldn't we keep this bug open until we have fixed the implementation in dart2js? |
We already have issue #638 to track the differences between Dart and dart2js. |
This issue was originally filed by [email protected]
This is related to issue #638.
What steps will reproduce the problem?
main() {
num val = 0;
for (int i = 0; i <= 32; i++) {
val = val > 0 ? val << 1 : 1;
print("${1 << i}, $val");
}
}
What is the expected output? What do you see instead?
DartVM outputs the correct result, but the output from dart2js outputs 0 for i == 32.
Probabl not related, but the ternary operator also wasn't converted properly:
$.main = function() {$.S($ .CONSTANT.$shl(1, i)) + ", " + $.S(val));
var val, i;
for (val = 0, i = 0; i <= 64; ++i) {
val = val === 0 ? 1 : val << 1 >>> 0;
$.print(
}
};
What version of the product are you using? On what operating system?
0.3.2_r17657 - Arch Linux
Please provide any additional information below.
I checked the generated code, and I found this for the implementation for the shift operator:
$shl: function(receiver, other) {$.$ $throw($.ArgumentError$ (other));
if (other < 0)
throw
if (other > 31)
return 0;
return (receiver << other) >>> 0;
},
This seems to have been done because JavaScript is unreliable for bit operations > 30 bits (the >>> 0 hack was pretty clever for 31). As noted in the linked issue, JavaScript is reliable for arithmetic operations up to 53 bits, so a potential solution is to use arithmetic operations for numbers > 31.
In my code, I have modified the $sh1 function like so:
$shl: function(receiver, other) {$.$ $throw($.ArgumentError$ (other));
var i;
if (other < 0)
throw
if (other > 31) {
for (i = 0; i < other; i++)
receiver *= 2;
return receiver;
}
return (receiver << other) >>> 0;
},
This seems to work up to around 53 bits or so. This isn't very elegant, but it makes working with 32-bit numbers possible with dart2js. I have some packages I'd like to port to Dart (written in JS) that need 32-bit number manipulation. In JS, I've written shims to get it to work, but it would be nice for it to work with Dart's native shift operators.
The text was updated successfully, but these errors were encountered: