Un «plan» reutilizable acelera las llamadas de libffi hasta seis veces

Fuentes: Performance improvements in libffi

libffi es un intérprete de convenciones de llamada: en tiempo de ejecución recibe la descripción de la signatura de una función y, sobre la marcha, decide cómo colocar cada argumento y ejecutar la llamada. Esa interpretación se repite en cada invocación, lo que cuesta alrededor de 650 instrucciones para una llamada de tres argumentos en x86-64 y multiplica por 16 el tiempo de una llamada directa.

La mejora propuesta consiste en un «plan»: una lista plana de movimientos (un bytecode mínimo por signatura) que se compila una sola vez a partir del ffi_cif. Cada movimiento indica, por ejemplo, que un puntero va a rdi, que un entero de 32 bits se extiende con signo a rsi o que un doble se deposita en un registro SSE. Cuando todos los argumentos caben en registros de propósito general, el plan se marca como apto para un «thunk» en código máquina que carga los registros directamente desde el array de argumentos, sin pasar por el intérprete.

El plan se expone como una API opcional (ffi_call_plan_alloc, ffi_call_plan_invoke y ffi_call_plan_free) que convive con ffi_call: las signaturas no soportadas por la ruta rápida caen de vuelta al camino tradicional. En pruebas con un Core Ultra 7 255H y -O2, una llamada a una función con tres punteros pasa de 31 ns con ffi_call a 5,1 ns con ffi_call_plan_invoke, frente a 1,9 ns de una llamada directa. El plan es inmutable y seguro para hilos, y al residir los datos en memoria de sololectura evita páginas a la vez escribibles y ejecutables.