Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 7 additions & 11 deletions lib/ffi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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;
};
Expand All @@ -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;
},
Expand Down
54 changes: 54 additions & 0 deletions test/ffi/test-ffi-dynamic-library.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Loading