Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/lib/libint53.js
4150 views
1
/**
2
* @license
3
* Copyright 2020 The Emscripten Authors
4
* SPDX-License-Identifier: MIT
5
*/
6
7
addToLibrary({
8
#if ASSERTIONS
9
$writeI53ToI64__deps: ['$readI53FromI64', '$readI53FromU64'
10
#if MINIMAL_RUNTIME
11
, '$warnOnce'
12
#endif
13
],
14
#endif
15
// Writes the given JavaScript Number to the WebAssembly heap as a 64-bit integer variable.
16
// If the given number is not in the range [-2^53, 2^53] (inclusive), then an unexpectedly
17
// rounded or incorrect number can be written to the heap. ("garbage in, garbage out")
18
// Note that unlike the most other function variants in this library, there is no separate
19
// function $writeI53ToU64(): the implementation would be identical, and it is up to the
20
// C/C++ side code to interpret the resulting number as signed or unsigned as is desirable.
21
$writeI53ToI64: (ptr, num) => {
22
{{{ makeSetValue('ptr', 0, 'num', 'u32') }}};
23
var lower = {{{ makeGetValue('ptr', 0, 'u32') }}};
24
{{{ makeSetValue('ptr', 4, '(num - lower)/4294967296', 'u32') }}};
25
#if ASSERTIONS
26
var deserialized = (num >= 0) ? readI53FromU64(ptr) : readI53FromI64(ptr);
27
var offset = {{{ getHeapOffset('ptr', 'u32') }}};
28
if (deserialized != num) warnOnce(`writeI53ToI64() out of range: serialized JS Number ${num} to Wasm heap as bytes lo=${ptrToString(HEAPU32[offset])}, hi=${ptrToString(HEAPU32[offset+1])}, which deserializes back to ${deserialized} instead!`);
29
#endif
30
},
31
32
// Same as writeI53ToI64, but if the double precision number does not fit within the
33
// 64-bit number, the number is clamped to range [-2^63, 2^63-1].
34
$writeI53ToI64Clamped__deps: ['$writeI53ToI64'],
35
$writeI53ToI64Clamped: (ptr, num) => {
36
if (num > 0x7FFFFFFFFFFFFFFF) {
37
{{{ makeSetValue('ptr', 0, 0xFFFFFFFF, 'u32') }}};
38
{{{ makeSetValue('ptr', 4, 0x7FFFFFFF, 'u32') }}};
39
} else if (num < -0x8000000000000000) {
40
{{{ makeSetValue('ptr', 0, 0, 'u32') }}};
41
{{{ makeSetValue('ptr', 4, 0x80000000, 'u32') }}};
42
} else {
43
writeI53ToI64(ptr, num);
44
}
45
},
46
47
// Like writeI53ToI64, but throws if the passed number is out of range of int64.
48
$writeI53ToI64Signaling__deps: ['$writeI53ToI64'],
49
$writeI53ToI64Signaling: (ptr, num) => {
50
if (num > 0x7FFFFFFFFFFFFFFF || num < -0x8000000000000000) {
51
#if ASSERTIONS
52
throw `RangeError in writeI53ToI64Signaling(): input value ${num} is out of range of int64`;
53
#else
54
throw `RangeError: ${num}`;
55
#endif
56
}
57
writeI53ToI64(ptr, num);
58
},
59
60
// Uint64 variant of writeI53ToI64Clamped. Writes the Number to a Uint64 variable on
61
// the heap, clamping out of range values to range [0, 2^64-1].
62
$writeI53ToU64Clamped__deps: ['$writeI53ToI64'],
63
$writeI53ToU64Clamped: (ptr, num) => {
64
if (num > 0xFFFFFFFFFFFFFFFF) {
65
{{{ makeSetValue('ptr', 0, 0xFFFFFFFF, 'u32') }}};
66
{{{ makeSetValue('ptr', 4, 0xFFFFFFFF, 'u32') }}};
67
} else if (num < 0) {
68
{{{ makeSetValue('ptr', 0, 0, 'u32') }}};
69
{{{ makeSetValue('ptr', 4, 0, 'u32') }}};
70
} else {
71
writeI53ToI64(ptr, num);
72
}
73
},
74
75
// Like writeI53ToI64, but throws if the passed number is out of range of uint64.
76
$writeI53ToU64Signaling__deps: ['$writeI53ToI64'],
77
$writeI53ToU64Signaling: (ptr, num) => {
78
if (num < 0 || num > 0xFFFFFFFFFFFFFFFF) {
79
#if ASSERTIONS
80
throw `RangeError in writeI53ToU64Signaling(): input value ${num} is out of range of uint64`;
81
#else
82
throw `RangeError: ${num}`;
83
#endif
84
}
85
writeI53ToI64(ptr, num);
86
},
87
88
// Reads a 64-bit signed integer from the WebAssembly heap and
89
// converts it to a JavaScript Number, which can represent 53 integer bits precisely.
90
// TODO: Add $readI53FromI64Signaling() variant.
91
$readI53FromI64: (ptr) => {
92
return {{{ makeGetValue('ptr', 0, 'u32') }}} + {{{ makeGetValue('ptr', 4, 'i32') }}} * 4294967296;
93
},
94
95
// Reads a 64-bit unsigned integer from the WebAssembly heap and
96
// converts it to a JavaScript Number, which can represent 53 integer bits precisely.
97
// TODO: Add $readI53FromU64Signaling() variant.
98
$readI53FromU64: (ptr) => {
99
return {{{ makeGetValue('ptr', 0, 'u32') }}} + {{{ makeGetValue('ptr', 4, 'u32') }}} * 4294967296;
100
},
101
102
// Converts the given signed 32-bit low-high pair to a JavaScript Number that
103
// can represent 53 bits of precision.
104
$convertI32PairToI53: (lo, hi) => {
105
#if ASSERTIONS
106
// This function should not be getting called with too large unsigned numbers
107
// in high part (if hi >= 0x7FFFFFFFF, one should have been calling
108
// convertU32PairToI53())
109
assert(hi === (hi|0));
110
#endif
111
return (lo >>> 0) + hi * 4294967296;
112
},
113
114
// Converts the given signed 32-bit low-high pair to a JavaScript Number that can
115
// represent 53 bits of precision. Returns a NaN if the number exceeds the safe
116
// integer range representable by a Number (x > 9007199254740992 || x < -9007199254740992)
117
$convertI32PairToI53Checked: (lo, hi) => {
118
#if ASSERTIONS
119
assert(lo == (lo >>> 0) || lo == (lo|0)); // lo should either be a i32 or a u32
120
assert(hi === (hi|0)); // hi should be a i32
121
#endif
122
return ((hi + 0x200000) >>> 0 < 0x400001 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN;
123
},
124
125
// Converts the given unsigned 32-bit low-high pair to a JavaScript Number that can
126
// represent 53 bits of precision.
127
// TODO: Add $convertU32PairToI53Checked() variant.
128
$convertU32PairToI53: (lo, hi) => {
129
return (lo >>> 0) + (hi >>> 0) * 4294967296;
130
},
131
132
#if WASM_BIGINT
133
$INT53_MAX: '{{{ Math.pow(2, 53) }}}',
134
$INT53_MIN: '-{{{ Math.pow(2, 53) }}}',
135
// Counvert a bigint value (usually coming from Wasm->JS call) into an int53
136
// JS Number. This is used when we have an incoming i64 that we know is a
137
// pointer or size_t and is expected to be within the int53 range.
138
// Returns NaN if the incoming bigint is outside the range.
139
$bigintToI53Checked__deps: ['$INT53_MAX', '$INT53_MIN'],
140
$bigintToI53Checked: (num) => (num < INT53_MIN || num > INT53_MAX) ? NaN : Number(num),
141
#endif
142
});
143
144
#if WASM_BIGINT
145
globalThis.i53ConversionDeps = ['$bigintToI53Checked'];
146
#else
147
globalThis.i53ConversionDeps = ['$convertI32PairToI53Checked'];
148
#endif
149
150