In this talk we'll explore the strategies that we did in Wasmer to make PHP run almost at native speeds, from switching compilers from Cranelift to LLVM, to enable opcache to using WebAssembly Exceptions to bring 10x faster performance.
Exception Handling: “legacy” and “exnref”s (we implemented the “exnref” f lavour) • It resembles the behaviour of C++’s exception handling mechanism • It adds two new types (`tag` and `exnref`) and a number of control- f low instructions to throw and catch exceptions Source: https://webassembly.org/features/
to break control f low when an exception is thrown. (module (tag $e0) (func $check_nz (param i32) (if (i32.eqz (local.get 0) (then (throw $e0)) (else (;do nothing;))))))
(you don’t pay if you don’t throw!) • It is based on the same structure that DWARF uses (sections..) • C++-like exception handling works as result of the cooperation between the runtimes, object formats and libraries like libunwind
of an obscure corner of runtimes — shout out to Nico Brailovsky! • In short: • You have a function • You compile it into an object f ile • The object f ile has a “.eh_frame” • The .eh_frame section shall contain 1 or more Call Frame Information (CFI) records • The number of records present shall be determined by size of the section as contained in the section header • Each CFI record contains a Common Information Entry (CIE) record followed by 1 or more Frame Description Entry (FDE) records • You learn the LEB128 format • You parse the Augmentation String f ield in the CIE • You see if there is anything to check in the LSDA • You quux the zot! Don’t forget to foo the bar! I am rubber, you are glue! This f loor is lovely. Is it parquet?
%pc: • The runtime creates an exception object e. It encodes the type of the exception and the “domain” the exception belongs to; • The runtime calls libunwind which gets the %pc and e and looks at speci f ic sections of the object f ile* to see if the function %pc belongs to has a personality function to call; • The personality function is given %pc, %e and a mechanism to get access to the LSDA, which contains a mapping between PCs and “catch blocks”. • The personality function parses the LSDA and check if there is a catch block that can catch exceptions from that PC. • If there is one, it checks that type of the exception the catch block can catch matches that of %e. • If all works out, execution is restored from that catch block by manually “installing the context”. • If not, returns control to libunwind, which repeats the procedure with the parent function. EH in a nutshell (-nix) Take it with a wheelbarrow’s worth of salt! 🧂
-> LLVM IR -> Native asm) • LLVM has the nifty landingpad intrinsic used to represent exactly C++-style exception handling • Map instances of try_table and catch_* Wasm operators to “that” • Create vm intrinsics to allocate, destroy, throw, and rethrow exceptions • Create the wasmer_eh_personality personality function • Mark each LLVM function we generate with that personality function • ??? • Pro f it! LLVM 🥁