jsx/JSX

Introduce strict definition of `int`

Closed this issue · 9 comments

Definition of int has been vague in the current implementation ("an integral number between -231 to 231-1, or NaN, or +-Infinity", according to http://jsx.github.io/doc/typeref.html) and the use has not been encouraged in general, based on the understanding that the frequent use of the bitwise-OR operator (to round numbers) would lead to slower code.

But the understanding seems to be wrong. Looking at the design and benchmarks of asm.js, the code would execute faster (or will become faster as the runtimes evolve) if the operator is used appropriately.

So IMO, we should change the definition of int in JSX to the same with asm.js; so that the definition would be more strict and clear thus easier to use, and so that the generated code would run faster.

gfx commented

+1

@kazuho Did you mean change JSX's int not to be nan or infinity?
cf. http://asmjs.org/spec/latest/#int

@wasabiz

It's not only NaNs and infinities. I am sorry to point this out but the JSX spec. referred to from the issue is wrong in the fact that the current implementation allows int to become an integral number out of the 32-bit limit.

For example, following JSX code gets compiled into return x + y (note: see that | 0 is not emitted).

function add(x : int, y : int) : int {
  return x + y;
}

PS. Math.imul is supported by most of the modern browsers on PC and mobile (including Mobile Safari). https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/imul#Browser_compatibility http://jsdo.it/kazuho/hnSK

I created a simple benchmark that compares the performance of functions implementing Fibonacci calculator using loops. Looking at the results, the one enforcing integer arithmetic calculation is much faster (50% faster on Chrome on Android, 240% faster on Mobile Safari).

http://jsperf.com/fib-using-int

I am sorry but the benchmark shown in the previous comment was wrong, in the fact that it was causing lot of overflows in the optimized examples using integer arithmetic (i.e. they were generating different result when compared to the original code).

http://jsperf.com/fib-using-int/4 is a modified version that fixes the overflow. Looking at the results, there seem no need to explicitly request integer arithmetic for the loops, and that the use of int (in general) may or may not cause performance boost depending on the web browser (Firefox runs faster, Chrome may run faster, Safari runs slower).

But IMO the drag (performance decrease) of using int in Safari is marginal. So anyways I propose to introduce more strict definition of int (since it not only causes performance boost on other web browsers but also may have positive effect on futuer versions of Safari as well considering the existence of asm.js, not to mention that the existence of such well-defined integer type would help the users of JSX), and let the users use the type by designating the type explicitly (i.e. numeric literals would continue to be treated as numbers).

Most work has been finished at commit 5ac0e6d in https://github.com/jsx/JSX/tree/kazuho/experiments/32bit-int .

ToDo:

  • update the const-folding optimizer to use strict 32-bit int ops.
  • decide whether or not to change the definitions of int / int and int % int from returning number to returning int

IIRC int / int has been defined as such since the operator in JavaScript may return numbers with fractional part. int % int should have been defined to return int from the first point.

This comment is a clarification of the changes proposed by the issue.

The grammatical definition of int in JSX is as follows.

  • numeric literals in the source code are always considered to be numbers (i.e. 0 in source code is a number, not int)
  • int op int where op is one of +, -, * returns int
  • int op int where op is either / or % returns number
  • bit-wise binary operators return int
  • fused assignment operators and pre/post-increment/decrement operators are defined to match the definitions above
  • type deduction from int is number (e.g. var n = 1 | 0 defines a local variable n of type number)
  • due to the above definition, the only way to define a variable (or constant) of type int is to declare the type explicitly (e.g. var n : int = 0)

The issue (by itself) is not proposing any changes to the grammatical definition, but is proposing to apply 32-bit rounding to the second rule; i.e. int + int, int - int, int * int should always return a 32-bit signed value.

Note: in contrary to my previous comment, I now think that int % int returning a number is a good thing since it would be more sound to return NaN (instead of 0 or any other value that can be represented by int) in case the second operand is 0.