@@ -32,9 +32,9 @@ test('fast FFI validates integer argument ranges', () => {
3232
3333 function callU32 ( value ) { return functions . add_u32 ( value , 0 ) ; }
3434
35- function callI64 ( value ) { return functions . add_i64 ( value , 0n ) ; }
35+ function callI64 ( value ) { return functions . add_i64 ( value , 0 ) ; }
3636
37- function callU64 ( value ) { return functions . add_u64 ( value , 0n ) ; }
37+ function callU64 ( value ) { return functions . add_u64 ( value , 0 ) ; }
3838
3939 for ( const [ fn , value ] of [
4040 [ callI8 , 0 ] ,
@@ -43,8 +43,8 @@ test('fast FFI validates integer argument ranges', () => {
4343 [ callU16 , 0 ] ,
4444 [ callI32 , 0 ] ,
4545 [ callU32 , 0 ] ,
46- [ callI64 , 0n ] ,
47- [ callU64 , 0n ] ,
46+ [ callI64 , 0 ] ,
47+ [ callU64 , 0 ] ,
4848 ] ) {
4949 optimize ( fn , value ) ;
5050 }
@@ -62,6 +62,24 @@ test('fast FFI validates integer argument ranges', () => {
6262 assert . throws ( ( ) => callU32 ( - 1 ) , expect ) ;
6363 assert . throws ( ( ) => callU32 ( 1.5 ) , expect ) ;
6464 assert . throws ( ( ) => callU32 ( '1' ) , expect ) ;
65+ assert . strictEqual ( callI64 ( Number . MAX_SAFE_INTEGER ) ,
66+ BigInt ( Number . MAX_SAFE_INTEGER ) ) ;
67+ assert . strictEqual ( callI64 ( Number . MIN_SAFE_INTEGER ) ,
68+ BigInt ( Number . MIN_SAFE_INTEGER ) ) ;
69+ assert . strictEqual ( callU64 ( Number . MAX_SAFE_INTEGER ) ,
70+ BigInt ( Number . MAX_SAFE_INTEGER ) ) ;
71+ assert . strictEqual ( callI64 ( ( 2n ** 63n ) - 1n ) , ( 2n ** 63n ) - 1n ) ;
72+ assert . strictEqual ( callU64 ( ( 2n ** 64n ) - 1n ) , ( 2n ** 64n ) - 1n ) ;
73+ assert . throws ( ( ) => callI64 ( Number . MAX_SAFE_INTEGER + 1 ) , expect ) ;
74+ assert . throws ( ( ) => callI64 ( Number . MIN_SAFE_INTEGER - 1 ) , expect ) ;
75+ assert . throws ( ( ) => callI64 ( 1.5 ) , expect ) ;
76+ assert . throws ( ( ) => callI64 ( Number . NaN ) , expect ) ;
77+ assert . throws ( ( ) => callI64 ( Number . POSITIVE_INFINITY ) , expect ) ;
78+ assert . throws ( ( ) => callU64 ( - 1 ) , expect ) ;
79+ assert . throws ( ( ) => callU64 ( Number . MAX_SAFE_INTEGER + 1 ) , expect ) ;
80+ assert . throws ( ( ) => callU64 ( 1.5 ) , expect ) ;
81+ assert . throws ( ( ) => callU64 ( Number . NaN ) , expect ) ;
82+ assert . throws ( ( ) => callU64 ( Number . POSITIVE_INFINITY ) , expect ) ;
6583 assert . throws ( ( ) => callI64 ( 2n ** 63n ) , expect ) ;
6684 assert . throws ( ( ) => callU64 ( 2n ** 64n ) , expect ) ;
6785 } finally {
@@ -70,6 +88,60 @@ test('fast FFI validates integer argument ranges', () => {
7088 }
7189} ) ;
7290
91+ test ( 'fast FFI converts single i64/u64 Number arguments before and after optimization' , ( ) => {
92+ const { lib, functions } = ffi . dlopen ( libraryPath , {
93+ identity_i64 : { return : 'int64' , arguments : [ 'int64' ] } ,
94+ identity_u64 : { return : 'uint64' , arguments : [ 'uint64' ] } ,
95+ } ) ;
96+
97+ try {
98+ // The native signature must have one argument to exercise the single-argument wrapper.
99+ function callI64 ( value ) { return functions . identity_i64 ( value ) ; }
100+
101+ function callU64 ( value ) { return functions . identity_u64 ( value ) ; }
102+
103+ for ( const optimized of [ false , true ] ) {
104+ if ( optimized ) {
105+ optimize ( callI64 , - 42 ) ;
106+ optimize ( callU64 , 42 ) ;
107+ }
108+
109+ for ( const value of [ 0 , - 0 , 42 , Number . MAX_SAFE_INTEGER , 0n , 42n ] ) {
110+ assert . strictEqual ( callI64 ( value ) , BigInt ( value ) ) ;
111+ assert . strictEqual ( callU64 ( value ) , BigInt ( value ) ) ;
112+ }
113+ for ( const value of [ - 42 , Number . MIN_SAFE_INTEGER ,
114+ - ( 2n ** 63n ) , ( 2n ** 63n ) - 1n ] ) {
115+ assert . strictEqual ( callI64 ( value ) , BigInt ( value ) ) ;
116+ }
117+ assert . strictEqual ( callU64 ( ( 2n ** 64n ) - 1n ) , ( 2n ** 64n ) - 1n ) ;
118+
119+ const signedError = {
120+ code : 'ERR_INVALID_ARG_VALUE' ,
121+ message : 'Argument 0 must be an int64' ,
122+ } ;
123+ const unsignedError = {
124+ code : 'ERR_INVALID_ARG_VALUE' ,
125+ message : 'Argument 0 must be a uint64' ,
126+ } ;
127+ for ( const value of [ Number . MAX_SAFE_INTEGER + 1 , Number . MIN_SAFE_INTEGER - 1 ,
128+ 1.5 , NaN , Infinity , - Infinity , '1' , null , undefined , true , { } ] ) {
129+ assert . throws ( ( ) => callI64 ( value ) , signedError ) ;
130+ assert . throws ( ( ) => callU64 ( value ) , unsignedError ) ;
131+ }
132+ for ( const value of [ - ( 2n ** 63n ) - 1n , 2n ** 63n ] ) {
133+ assert . throws ( ( ) => callI64 ( value ) , signedError ) ;
134+ }
135+ for ( const value of [ - 1 , - 1n , 2n ** 64n ] ) {
136+ assert . throws ( ( ) => callU64 ( value ) , unsignedError ) ;
137+ }
138+ }
139+ } finally {
140+ eval ( '%WaitForBackgroundOptimization()' ) ;
141+ lib . close ( ) ;
142+ }
143+ } ) ;
144+
73145test ( 'fast FFI validates pointer BigInt ranges' , ( ) => {
74146 const lib = new ffi . DynamicLibrary ( libraryPath ) ;
75147 try {
0 commit comments