Static Hermes is the the next major version of Hermes, still under active development. It enables optional ahead-of-time native compilation of soundly typed JavaScript, using TypeScript or Flow type annotations.
yet, but we have positive indications of performance • This is a work in progress, and we are sharing it early to show you what we’ve been working on and gather community feedback • We want to thank Amazon for adding TypeScript support to Static Hermes.
there are limits on interpreter performance after startup • Writing C++ to improve performance is difficult • RN developers are already accustomed to writing typed JS code • We want to take advantage of this to bridge predictable C performance with JS usability via native AOT compilation.
y) { return x + y; } • We don’t know the type of x and y ahead of time. • All possible types (string, array, number, etc) and combinations need to be supported. • The result is either a size explosion or interpreter-like performance. • Solutions in academia, specifically HopC, by Manuel Serrano, do not meet our goal (not ruling it out in the future) And why is no one doing it?
return x + y; } • No! Because type annotations in TypeScript and Flow are unsound. • The type annotations do not guarantee that types are correct at runtime. • The compiler cannot rely on type annotations for better code.
return x + y; } let a: number[] = [10, 20, 30]; // Uh-oh! Adding undefined + undefined! addXY(a[10], a[11]); Despite the type annotations, both parameters can be non- numbers at runtime.
allow efficient sound typing • The new semantics to improve performance are opt-in on a granular level • New code can coexist and interop with unmodified code • Both TypeScript and Flow are supported
the user wanted • When they wrote x: number, they didn’t intend that x could also be undefined. • Technically that was a bug which cannot be caught at compile time • We are strengthening the existing TypeScript and Flow type systems by enforcing them at runtime. • It should not make a difference for correct code. • It is all opt-in. The standard behavior is available, if you want it.
used in The Computer Language Benchmarks Game, simulating movement of celestial bodies. This is a math heavy benchmark with many property accesses. SH improves runtime from 5511 ms to 565 ms
error prone. It requires switching between languages. 02 Calling existing native APIs requires writing JSI wrappers in C++. 03 Crossing JSI is not practical when we need high frequency interop with JS. The cost of JSI itself starts to dominate performance.
“unsafe” sections of JS code • Explicit distinction between “safe” and “unsafe” code • Native functions and native types are 1st class citizens of the language, enabling no-overhead compilation
C++ required // Open the database res = _sqlite3_open( stringToAsciiz(”file.db"), dbPtrBuffer ); if (res !== 0) throw Error(res); db = _sh_ptr_read_ptr(dbPtrBuffer, 0); // Prepare the SQL statement sqlPtr = stringToAsciiz( "SELECT id, name FROM my_table” ); res = _sqlite3_prepare_v2( db, sqlPtr, -1, dbPtrBuffer, c_null ); if (res !== 0) throw Error(res); stmt = _sh_ptr_read_ptr(dbPtrBuffer, 0); // Loop through all rows in the table let row = 1; while (_sqlite3_step(stmt) === SQLITE_ROW) { const id = _sqlite3_column_int(stmt, 0); const namePtr = _sqlite3_column_text(stmt, 1); const name = asciizToString(namePtr, 1024); print(`row${row++}:`, id, name); }
{throw 0;}); function getenv(name: string): string { "use unsafe"; let name_z = stringToAsciiz(name); try { let val_z = _getenv(name_z); return asciizToString_unsafe(val_z, 2048); } finally { free(name_z); } } print(getenv("PATH")); Convert the name from a JS string to a native C string