How is Dart FFI implemented indeed? Are they as cheap as a normal function call, or do they do heavy lifting under the hood?

200

Dart FFI uses C's dlopen() for platforms other than Windows (non-POSIX). It's a very lightweight interface to shared objects. Compiled shared objects contain a table with symbol names and their memory offset. The shared object is opened with dlopen() then specific contained items are found in memory using dlsym() with their symbol name. This provides a memory address for, say, a function with the name 'testDartFFI()'. The dart runtime can then call this function with the memory address, using the Dart prototype to correctly pass and return values based on C standards. Overhead-wise it's not much different than calling other dynamically linked system libraries.

Share:
200
ch271828n
Author by

ch271828n

Hello, world :)

Updated on January 01, 2023

Comments

  • ch271828n
    ch271828n over 1 year

    I am quite interested in how Dart FFI is implemented. Are they as cheap as a normal function call, or do they do heavy lifting under the hood?

    I have searched through the Internet but cannot find much information. I only find this article talking a bit about the insights of argument passing and ABIs. In addition, I guess it should have some protections because Dart has things like GC while C does not.

    Thanks for any hints!

  • ch271828n
    ch271828n over 2 years
    Thanks for the answer! Overhead-wise it's not much different than calling other dynamically linked system libraries. - When talking about overhead, I wonder the overhead of "Dart to C" compared with things like "Dart to Dart" or "C to C". Could you please elaborate?
  • Pat9RB
    Pat9RB over 2 years
    Executables that include calls to shared objects (.so/.dll) have an external symbol table in them. When the executable is loaded, before main() or similar is called, the linker makes sure the libraries are available and fills in the table with the memory addresses of the symbols. Once the executable starts running, every external it will need has an address. With dlopen(), the library is loaded after main() then the executable has to look up any symbol (function, global, etc) it wants to use. Once the symbols are resolved, arguments and returns would be the same overhead as any libc call.
  • Pat9RB
    Pat9RB over 2 years
    I've just started working with FFI though. (Trying to do C bindings for a C++ lib so I can then do Dart bindings for the C++ lib)
  • ch271828n
    ch271828n over 2 years
    Thanks! Trying to do C bindings for a C++ lib so I can then do Dart bindings for the C++ lib by the way you may be interested in: github.com/fzyzcjy/flutter_rust_bridge