diff --git a/lib/ffi.js b/lib/ffi.js index d91b6d4521e679..f35ebae3e312ab 100644 --- a/lib/ffi.js +++ b/lib/ffi.js @@ -80,8 +80,10 @@ function makeSignature(argumentTypes, returnType) { }; } -function wrapFFIFunction(rawFn, argumentTypes, returnType, owner) { - if (argumentTypes === undefined && rawFn !== undefined && rawFn !== null) { +function wrapFFIFunction(rawFn, owner) { + let argumentTypes; + let returnType; + if (rawFn !== undefined && rawFn !== null) { const sbArguments = rawFn[kSbArguments]; argumentTypes = sbArguments ?? rawFn[kFastArguments]; if (sbArguments !== undefined) { @@ -103,7 +105,7 @@ const rawGetFunctions = DynamicLibrary.prototype.getFunctions; DynamicLibrary.prototype.getFunction = function getFunction(name, signature) { const raw = FunctionPrototypeCall(rawGetFunction, this, name, signature); - return wrapFFIFunction(raw, signature.arguments, signature.return, this); + return wrapFFIFunction(raw, this); }; DynamicLibrary.prototype.getFunctions = function getFunctions(definitions) { @@ -115,13 +117,7 @@ DynamicLibrary.prototype.getFunctions = function getFunctions(definitions) { const out = { __proto__: null }; for (let i = 0; i < keys.length; i++) { const name = keys[i]; - if (definitions === undefined) { - out[name] = wrapFFIFunction(raw[name], undefined, undefined, this); - } else { - const signature = definitions[name]; - out[name] = wrapFFIFunction( - raw[name], signature.arguments, signature.return, this); - } + out[name] = wrapFFIFunction(raw[name], this); } return out; }; @@ -145,7 +141,7 @@ DynamicLibrary.prototype.getFunctions = function getFunctions(definitions) { const keys = ObjectKeys(raw); for (let i = 0; i < keys.length; i++) { const name = keys[i]; - wrapped[name] = wrapFFIFunction(raw[name], undefined, undefined, this); + wrapped[name] = wrapFFIFunction(raw[name], this); } return wrapped; }, diff --git a/test/ffi/test-ffi-dynamic-library.js b/test/ffi/test-ffi-dynamic-library.js index ba0f8a383ffd8b..88897be6eaec74 100644 --- a/test/ffi/test-ffi-dynamic-library.js +++ b/test/ffi/test-ffi-dynamic-library.js @@ -103,6 +103,60 @@ test('DynamicLibrary exposes functions and symbols', () => { } }); +test('DynamicLibrary evaluates function signatures once', () => { + function makeChangingSignature() { + const reads = { arguments: 0, return: 0 }; + return { + reads, + signature: { + get arguments() { + reads.arguments++; + return reads.arguments === 1 ? + Array(8).fill('i32') : ['i32']; + }, + get return() { + reads.return++; + return 'i32'; + }, + }, + }; + } + + { + const lib = new ffi.DynamicLibrary(libraryPath); + const { reads, signature } = makeChangingSignature(); + + try { + const fn = lib.getFunction('sum_8_i32', signature); + assert.strictEqual(fn(1, 2, 3, 4, 5, 6, 7, 8), 36); + assert.deepStrictEqual(reads, { arguments: 1, return: 1 }); + } finally { + lib.close(); + } + } + + { + const lib = new ffi.DynamicLibrary(libraryPath); + const { reads, signature } = makeChangingSignature(); + let definitionReads = 0; + const definitions = { + get sum_8_i32() { + definitionReads++; + return signature; + }, + }; + + try { + const { sum_8_i32: fn } = lib.getFunctions(definitions); + assert.strictEqual(fn(1, 2, 3, 4, 5, 6, 7, 8), 36); + assert.strictEqual(definitionReads, 1); + assert.deepStrictEqual(reads, { arguments: 1, return: 1 }); + } finally { + lib.close(); + } + } +}); + test('getFunction caches signatures consistently', () => { const lib = new ffi.DynamicLibrary(libraryPath);