Diving into
HHVM Extensions
James Titcumb
PHPNW Conference 2015
James Titcumb
www.jamestitcumb.com
www.roave.com
www.phphants.co.uk
www.phpsouthcoast.co.uk
@asgrim
Who is this guy?
First, some background...
source: Microsoft
How PHP works
PHP code
OpCache
Execute (VM)
Lexer + Parser
Compiler
How HHVM works
PHP code
OpCache
Execute (VM)
Lexer + Parser
Compiler
JIT
Execute (Native)
Hack features
● Return/parameter type hints
● ?nullable
● Collections (Vectors, Sets, Maps, etc.)
● Async functions
● Enums
● Generics
● Lambda expressions ==>
● XHP
● more stuff
The HHVM codebase
The Engine
hphp/parser
The Engine
hphp/parser
hphp/compiler
The Engine
hphp/parser
hphp/compiler
hphp/hhbbc
The Engine
hphp/parser
hphp/compiler
hphp/hhbbc
hphp/hhvm
The Engine
hphp/parser
hphp/compiler
hphp/hhbbc
hphp/hhvm
hphp/runtime/vm
The Engine
hphp/parser
hphp/compiler
hphp/hhbbc
hphp/hhvm
hphp/runtime/vm
hphp/runtime/vm/jit
The Extensions
hphp/runtime/ext
The Extensions
hphp/runtime/ext
hphp/system/php
Compile HHVM?
source: https://xkcd.com/303/
My First HHVM Extension™
config.cmake
HHVM_EXTENSION(calc ext_calc.cpp)
ext_calc.cpp
#include "hphp/runtime/ext/extension.h"
namespace HPHP {
static class CalcExtension : public Extension {
public:
CalcExtension(): Extension("calc") {}
virtual void moduleInit() {}
} s_calc_extension;
HHVM_GET_MODULE(calc);
} // namespace HPHP
ext_calc.cpp
#include "hphp/runtime/ext/extension.h"
namespace HPHP {
static class CalcExtension : public Extension {
public:
CalcExtension(): Extension("calc") {}
virtual void moduleInit() {}
} s_calc_extension;
HHVM_GET_MODULE(calc);
} // namespace HPHP
ext_calc.cpp
#include "hphp/runtime/ext/extension.h"
namespace HPHP {
static class CalcExtension : public Extension {
public:
CalcExtension(): Extension("calc") {}
virtual void moduleInit() {}
} s_calc_extension;
HHVM_GET_MODULE(calc);
} // namespace HPHP
ext_calc.cpp
#include "hphp/runtime/ext/extension.h"
namespace HPHP {
static class CalcExtension : public Extension {
public:
CalcExtension(): Extension("calc") {}
virtual void moduleInit() {}
} s_calc_extension;
HHVM_GET_MODULE(calc);
} // namespace HPHP
ext_calc.cpp
#include "hphp/runtime/ext/extension.h"
namespace HPHP {
static class CalcExtension : public Extension {
public:
CalcExtension(): Extension("calc") {}
virtual void moduleInit() {}
} s_calc_extension;
HHVM_GET_MODULE(calc);
} // namespace HPHP
… that’s it.
<?php
var_dump(extension_loaded('calc'));
test.php
Compile it.
(waaaat?!)
Compile & run the test
#!/bin/bash
hphpize
cmake . && make
/usr/bin/hhvm 
-d extension_dir=. 
-d hhvm.extensions[]=calc.so 
test.php
Compile & run the test
$ ./build.sh
bool(true)
$
Hack it!
source: http://goo.gl/kUAxBI
config.cmake
HHVM_EXTENSION(calc ext_calc.cpp)
HHVM_SYSTEMLIB(calc ext_calc.php)
ext_calc.cpp
#include "hphp/runtime/ext/extension.h"
namespace HPHP {
static class CalcExtension : public Extension {
public:
CalcExtension(): Extension("calc") {}
virtual void moduleInit() {
loadSystemlib();
}
} s_calc_extension;
HHVM_GET_MODULE(calc);
} // namespace HPHP
ext_calc.php
<?hh
function calc_sub(int $a, int $b): int {
return $a - $b;
}
… that’s it.
<?php
var_dump(extension_loaded('calc'));
var_dump(calc_sub(5, 3));
test.php
Compile & run the test
$ ./build.sh
bool(true)
int(2)
$
Sprinkle some C++ in
for good measure
ext_calc.cpp
// ... SNIP ...
virtual void moduleInit() {
HHVM_FE(calc_add);
loadSystemlib();
}
// ... SNIP ...
ext_calc.cpp
// ... SNIP ...
static int64_t HHVM_FUNCTION(calc_add, int64_t a, int64_t b) {
return a + b;
}
// ... SNIP ...
in php extensions...
PHP_FUNCTION(calc_add)
{
// ... SNIP ...
#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &a, &b) == FAILURE) {
return;
}
#else
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_LONG(a)
Z_PARAM_LONG(b)
ZEND_PARSE_PARAMETERS_END();
#endif
// ... SNIP ...
ext_calc.php
<?hh
<<__Native>>
function calc_add(int $a, int $b): int;
function calc_sub(int $a, int $b): int {
return $a - $b;
}
… that’s it.
<?php
var_dump(extension_loaded('calc'));
var_dump(calc_sub(5, 3));
var_dump(calc_add(5, 3));
test.php
Compile & run the test
$ ./build.sh
bool(true)
int(2)
int(8)
$
Debugging?!
source: http://www.gnu.org/software/gdb/
Add debug mode
#!/bin/bash
hphpize
cmake 
-DCMAKE_C_FLAGS="-O0 -ggdb3" 
-DCMAKE_CXX_FLAGS="-O0 -ggdb3" 
-DCMAKE_BUILD_TYPE=Debug 
.
make
# ... SNIP ...
Run with gdb
$ gdb --args 
/usr/bin/hhvm 
-d extension_dir=. 
-d hhvm.extensions[]=calc.so 
test.php
GNU gdb (Ubuntu 7.9-1ubuntu1) 7.9
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.
org/licenses/gpl.html>
--- snip ---
Reading symbols from /usr/bin/hhvm...done.
(gdb)
Breakpoints
(gdb) b ext_calc.cpp:6
No source file named ext_calc.cpp.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (ext_calc.cpp:6) pending.
(gdb)
Running
(gdb) r
Starting program: /usr/bin/hhvm -d extension_dir=. -d hhvm.extensions[]
=calc.so smoke.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 2, HPHP::f_calc_add (a=5, b=3) at /home/james/workspace/hhvm-
calc/ext_calc.cpp:6
6 return a + b;
(gdb) p a
$1 = 5
(gdb) p b
$2 = 3
(gdb)
Handy commands
c continue / step out
n step over
s step into
p x print the value of a variable (x)
set x = y set a variable (x) to value (y)
bt print backtrace
q quit :)
When NOT to write extensions
When to write extensions
BUCKLE UP.
source: https://goo.gl/x7Srhe
Integrating OpenGL
into an HHVM extension
Don’t try this in
production!
srsly.
Extension
Browser
What I did
huh?!
Make it OOOOOOO
ext_foo.php
<?hh
<<__NativeData("Foo")>>
class Foo {
<<__Native>>
public function bar(): int;
}
C++ object
!==
PHP object
source: http://goo.gl/HORwLQ
HHVM Universe
<?php
$o = new Foo();
$o->bar();
PHP Land
class Foo {
public:
Foo() {}
~Foo() {}
int value = 5;
}
Planet C++
int64_t HHVM_METHOD(Foo,bar)
{
auto data =
Native::data<Foo>(this_);
return data->value;
}
Time Vortex!?!?!
C++ object !== PHP object
HHVM Universe
<?php
$o = new Foo();
$o->bar();
PHP Land
class Foo {
public:
Foo() {}
~Foo() {}
int value = 5;
}
Planet C++
int64_t HHVM_METHOD(Foo,bar)
{
auto data =
Native::data<Foo>(this_);
return data->value;
}
Time Vortex!?!?!
C++ object !== PHP object
HHVM Universe
<?php
$o = new Foo();
$o->bar();
PHP Land
class Foo {
public:
Foo() {}
~Foo() {}
int value = 5;
}
Planet C++
int64_t HHVM_METHOD(Foo,bar)
{
auto data =
Native::data<Foo>(this_);
return data->value;
}
Time Vortex!?!?!
C++ object !== PHP object
HHVM Universe
<?php
$o = new Foo();
$o->bar();
PHP Land
class Foo {
public:
Foo() {}
~Foo() {}
int value = 5;
}
Planet C++
int64_t HHVM_METHOD(Foo,bar)
{
auto data =
Native::data<Foo>(this_);
return data->value;
}
Time Vortex!?!?!
C++ object !== PHP object
this slide is intentionally left blank
ext_foo.php
<?hh
class Foo {
private int $value
public function bar(): int
{
return $this->value;
}
}
Demo?
source: http://goo.gl/7gWfNz
Resources
● OpenGL Tutorial
○ http://www.opengl-tutorial.org/
● HHVM Example Extension
○ https://github.com/hhvm/extension-example
● Sara Golemon - HHVM extension blog series
○ http://blog.golemon.com/2015/01/hhvm-extension-writing-part-iii.html
● Derick Rethans’ extension API cookbook
○ https://github.com/derickr/hhvm-hni-cookbook
● The official API documentation
○ https://github.com/facebook/hhvm/wiki/Extension%20API
● Journey of a Thousand Bytecodes
○ http://hhvm.com/blog/6323/the-journey-of-a-thousand-bytecodes
Any questions? :)
https://joind.in/15434
James Titcumb @asgrim

Diving into HHVM Extensions (PHPNW Conference 2015)