thlorenz / v8-perf

⏱️ Notes and resources related to v8 and thus Node.js performance
2.2k stars 112 forks source link

Representation of int64 within JS #3

Closed thlorenz closed 6 years ago

thlorenz commented 10 years ago

From discussion on irc -- we need links:

petkaantonov commented 10 years ago

V8 integer sizes:

Outside these ranges, numbers are represented as boxed doubles (in special case like locals of optimized code, pure float arrays, doubles are stored immediately)

Test could be like

var assert = require("assert");

function IsInteger(val) {
  return %_IsSmi(val);
}

var is64Bit = /64/.test(process.arch);

var min, max;
if (is64Bit) {
  min = -2147483648;
  max = 2147483647;
} else {
  min = -1073741824;
  max = 1073741823;
}

assert(IsInteger(min));
assert(IsInteger(max));
assert(!IsInteger(min - 1));
assert(!IsInteger(max + 1));
thlorenz commented 10 years ago

Thanks @petkaantonov, will add this as a test tomorrow.

The origin of the discussion however was how do you get a unsigned long long from the C++ layer to the JavaScript layer since I ran into that problem.

Seems like the verdict is to use a string in the situations where the number value exceeds a long (32-bit) and thus cannot be represented as a floating point number on the JS side. But if it's small enough just convert it to unit32_t.

thlorenz commented 10 years ago

@petkaantonov I added the test along with some explanation about how the min and max values come about.

I'm a bit confused regarding the min/max values on a 64-bit architecture though. I was under the impression that SMIs would be represented the same way no matter what the architecture (with 31-bits + 1 bit for the tag). However if they are represented differently I'd expect the following:

64-bit slot separation to hold a signed integer:

 - 1 bit to tag it as value
 - 1 bit for sign
 -  62 bits for actual value

However 2147483647 is just the max of a signed 31-bit value (just one bit more than on a 32-bit architecture).

I would have expected it to be much larger:

pad > Math.pow(2, 62)
4611686018427388000

Could you explain why that is so?

mraleph commented 10 years ago

On x64 Smis are 32-bit signed integers represented at higher half of 64bit value: tagged(x) = x << 32, untag(y) = y >> 32.

This was one of the things I wanted to leave a comment on, but my hands did not get to it.

Also in JS you don't have any use for 63-bit integer values because numeric type is double which has 53-bit of integer precision.

thlorenz commented 10 years ago

@mraleph thanks for the info, I'll add that to the comments in the test.

thlorenz commented 10 years ago

Also in JS you don't have any use for 63-bit integer values because numeric type is double which has 53-bit of integer precision.

I need to add this kind of info to the data-types section. Do you have any links to some resource that explains this in detail @mraleph?

mraleph commented 10 years ago

I doubt there is anything beyond some comments in V8, like this (somewhat confusing, I must admit) one from objects.h

// Smi represents integer Numbers that can be stored in 31 bits.
// Smis are immediate which means they are NOT allocated in the heap.
// The this pointer has the following format: [31 bit signed int] 0
// For long smis it has the following format:
//     [32 bit signed int] [31 bits zero padding] 0
// Smi stands for small integer.
thlorenz commented 10 years ago

Thanks. I guess I could also glean some more JavaScript specific info from the ECMA Spec.

mraleph commented 10 years ago

Ah I misunderstood the question. If you were tallking about number type in JavaScript then ECMA-262 is indeed what you should read, though there is not much there except definition 4.3.12 that defined number as "primitive value corresponding to a double-precision 64-bit binary format IEEE 754 value."

The rest follows from the way doubles work and the size of mantissa (53-bits).

thlorenz commented 10 years ago

@mraleph totally fine the other info was useful as well and has been added to the test. I'll read up on the spec to get the JS limits specific info.