Fast FFI for Node.js
ofrobots@google.com, mattloring@google.com
03/03/17
Objective
Provide a simple, fast, productive, pure JavaScript mechanism for a large subset of native module use cases
Motivation: Native Use Cases
Current Solutions: Direct use of V8 API
Local<Object> TranslateString(Isolate* isolate, char* str) {� EscapableHandleScope handle_scope(isolate);� Local<String> result = String::NewFromUtf8(isolate, str, NewStringType::kNormal).ToLocalChecked();� return handle_scope.Escape(result);�}
Current Solutions: Native Abstractions for Node (NAN)
Local<Object> TranslateString(char* str) {� Nan::EscapableHandleScope handle_scope;� Local<String> result = Nan::New(str).ToLocalChecked();� return handle_scope.Escape(result);�}
Current Solutions: node-ffi
var ffi = require('ffi');�var libm = ffi.Library('libm', { 'ceil': [ 'double', [ 'double' ] ] });�libm.ceil(1.5);
Requirements
Synchronous Translation
FFI Compiler
Function Ptr
DLL Name
JSFunction
Call Function Ptr
FromJS
FromJS
FromJS
ToJS
JS Return Value
JS Arg1
JS Arg2
JS Arg3
Fast FFI Module
dlsym
dlopen
Function Signature
Function Name
sig translation
libfoo.so
void foo();
Synchronous Example
var libadd = ffi.Library('libadd.so');
var plusTwoJS = libadd.getFunction('plusTwo', [ ffi.Int32Type, [ ffi.Int32Type ] ]);
var four = plusTwoJS(2);
int plusTwo(int n);
libadd.so
JSFunction (plusTwoJS)
Call plusTwo
JSNumberToInt32
Int32ToJSNumber
JSNumber
JSNumber
Asynchronous Translation
FFI Compiler
Function Ptr
DLL Name
JSFunction
Function Ptr
FromJS
FromJS
FromJS
JS Callback
JS Arg1
JS Arg2
Fast FFI Module
dlsym
dlopen
Function Signature
Function Name
sig translation
libuv thread
bind
CallNativeFunction
Asynchronous Example
var libadd = ffi.Library('libadd.so');
var plusTwoAsync = libadd.getFunctionAsync('plusTwo', [ ffi.Int32Type, [ ffi.Int32Type ] ]);
plusTwoAsync(2, function(four) { ... });
int plusTwo(int n);
libadd.so
JSFunction (plusTwoJSAsync)
plusTwo
JSNumberToInt32
JSFunctionToC
JSNumber
JSFunction
libuv thread
bind
CallNativeFunction
Design: Function Translation
FromJS
JSFunction
C Function
JSFunction
ToJS
ToJS
ToJS
FromJS
Return Value
Arg1
Arg2
Arg3
JSExitFrame
JSEntryFrame
Status
Design: Type Translations from JS
Input | Conversion | Output |
JSNumber | -> double -> cast | int32, int64, float32, float64 |
JSObject | -> translate fields by value | Struct Pointer |
JSFunction | -> wrap in JS entry logic + type conversion | Function Pointer |
Buffer | -> unbox + copy | TypedArray |
JSForeign | -> unbox | Void Pointer |
Design: Type Translations to JS
Input | Conversion | Output |
int32, int64, float32, float64 | -> to double | JSNumber |
Struct Pointer | -> translate fields by value | JSObject |
Function Pointer | -> ffi | JSFunction |
TypedArray | -> box in buffer | Buffer |
Void Pointer | -> box in foreign | JSForiegn |