Converting a PHP Extension to HHVM07 May 2015
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
*.cppand fixing various typecasting laxness that GCC 4.9.1 complains about when compiling C++
- Creating the
config.cmakefile 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
php_boxwood.cpp(the regular PHP 5 build process would have done this for me.) This is necessary to ensure the
ZEND_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
.phptfiles 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.