Converting a PHP Extension to HHVM
07 May 2015In a previous post I wrote about converting a PHP 5 extension to PHP 7. This article is about converting that same PHP 5 extension to work with HHVM.
The code changes to get things working were not very large – mostly just stylistic tidying to make the C++ compiler happy – but I found the process much more difficult than the PHP 7 conversion just due to unfamiliarity with HHVM and its uneven documentation.
Because building HHVM itself is such a time-consuming beast, I chose to implement my module as a dynamic extension in the style of the DSO test example.
You can see the complete diff here.
The changes boil down to the following:
- Moving all the
*.c
files to*.cpp
and fixing various typecasting laxness that GCC 4.9.1 complains about when compiling C++ - Creating the
config.cmake
file to tell cmake about the extension and its files - Creating the
ext_boxwood.php
“systemlib” file to tell HHVM about the exported files from my extension - Adding an explicit
COMPILE_DL_BOXWOOD
define tophp_boxwood.cpp
(the regular PHP 5 build process would have done this for me.) This is necessary to ensure theZEND_GET_MODULE()
macro gets executed, which causes necessary module metadata to be exported so that HHVM can read it. - Refactor module globals initialization to use the
ZEND_INIT_MODULE_GLOBALS()
macro instead of explicitly initializing globals in the MINIT function. This change is a good practice with standard PHP extensions as well, but it was required here to avoid a crash from a failing assertion in the HHVM version of a TSRM function. - Refactoring all the tests from individual
.phpt
files per test to separate files for each test’s sections – test, expected output, skip condition, etc.
Once I had the module compiling, though, it took me a while to get the code properly running in HHVM. In one of those “confusing at the time but obvious in retrospect” situations, the solution is that for my module (which is both dynamic and making use of the Zend Engine compatibility later, HHVM needs to be run with both the -d hhvm.enable_zend_compat=true
and the DynamicExtensions.0=/path/to/boxwood.so
arguments for the module to be loaded and initialized. With just DynamicExtensions.0=/path/to/boxwood.so
, the module is loaded, but not initialized properly.
Even still, I had trouble getting the built-in test runner to recognize what I thought were the right incantations for per-test-suite configuration options, so I just added my necessary options to the test runner explicitly.
Having figured out the configuration mumbo-jumbo, any future extension conversions to HHVM will go much quicker. However, given the nature of HHVM, I would be curious to see a performance comparison between an in-PHP version of this code benefitting from HHVM’s JIT compilation and the in-C version. Performance was the initial reason for writing this extension in C in the first place so it would be interesting to see if HHVM’s compilation makes that path obsolete.