Skip to content

Commit 87b2974

Browse files
committed
Merge pull request #207 from stesie/custom-snapshots
Handle V8 heap snapshots well + allow custom snapshot generation
2 parents 9fd25e6 + f49d3b7 commit 87b2974

File tree

7 files changed

+305
-32
lines changed

7 files changed

+305
-32
lines changed

README.Linux.md

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,23 @@ years ago, since Node.js requires such an old version.
1010
This means that you usually need to compile v8 on your own before
1111
you can start to compile & install v8js itself.
1212

13-
Compile latest v8
13+
Snapshots
14+
---------
15+
16+
V8 has (optional) support for so-called snapshots which speed up startup
17+
performance drastically. Hence they are generally recommended for use.
18+
19+
There are two flavours of snapshots: internal & external.
20+
21+
Internal snapshots are built right into the V8 library (libv8.so file),
22+
so there's no need to handle them specially.
23+
24+
Besides there are external snapshots (which are enabled unless configured
25+
otherwise). If V8 is compiled with these, then V8Js needs to provide two
26+
"binary blobs" to V8, named `natives_blob.bin` and `snapshot_blob.bin`.
27+
In that case copy those two files to `/usr/share/v8/...`.
28+
29+
Compile latest V8
1430
-----------------
1531

1632
```
@@ -25,11 +41,15 @@ fetch v8
2541
cd v8
2642
2743
# (optional) If you'd like to build a certain version:
28-
git checkout 3.32.6
44+
git checkout 4.9.385.28
2945
gclient sync
3046
31-
# Build (disable snapshots for V8 > 4.4.9.1)
32-
make native library=shared snapshot=off -j8
47+
# use libicu of operating system
48+
export GYP_DEFINES="use_system_icu=1"
49+
50+
# Build (with internal snapshots)
51+
export GYPFLAGS="-Dv8_use_external_startup_data=0"
52+
make native library=shared snapshot=on -j8
3353
3454
# Install to /usr
3555
sudo mkdir -p /usr/lib /usr/include
@@ -40,16 +60,9 @@ echo -e "create /usr/lib/libv8_libplatform.a\naddlib out/native/obj.target/tools
4060

4161
Then add `extension=v8js.so` to your php.ini file. If you have a separate configuration for CLI, add it there also.
4262

43-
* If the V8 library is newer than 4.4.9.1 you need to pass `snapshot=off` to
44-
`make`, otherwise the V8 library will not be usable
45-
(see V8 [Issue 4192](https://code.google.com/p/v8/issues/detail?id=4192))
4663
* If you don't want to overwrite the system copy of v8, replace `/usr` in
4764
the above commands with some other path like `/opt/v8` and then add
4865
`--with-v8js=/opt/v8` to the php-v8js `./configure` command below.
49-
* If you do that with a v8 library of 4.2 branch or newer, then you need
50-
to fix the RUNPATH header in the v8js.so library so the libicui18n.so
51-
is found. By default it is set to `$ORIGIN/lib.target/`, however the files
52-
lie side by side. Use `chrpath -r '$ORIGIN' libv8.so` to fix.
5366

5467
`libv8_libplatform.a` should not be copied directly since it's a thin
5568
archive, i.e. it contains only pointers to the build objects, which
@@ -62,7 +75,7 @@ Compile php-v8js itself
6275

6376
```
6477
cd /tmp
65-
git clone https://github.com/preillyme/v8js.git
78+
git clone https://github.com/phpv8/v8js.git
6679
cd v8js
6780
phpize
6881
./configure

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,15 @@ class V8Js
6262
/* Methods */
6363

6464
/**
65-
* Initializes and starts V8 engine and Returns new V8Js object with it's own V8 context.
65+
* Initializes and starts V8 engine and returns new V8Js object with it's own V8 context.
66+
* Snapshots are supported by V8 4.3.7 and higher.
6667
* @param string $object_name
6768
* @param array $variables
6869
* @param array $extensions
6970
* @param bool $report_uncaught_exceptions
71+
* @param string $snapshot_blob
7072
*/
71-
public function __construct($object_name = "PHP", array $variables = NULL, array $extensions = NULL, $report_uncaught_exceptions = TRUE)
73+
public function __construct($object_name = "PHP", array $variables = [], array $extensions = [], $report_uncaught_exceptions = TRUE, $snapshot_blob = NULL)
7274
{}
7375

7476
/**
@@ -174,6 +176,16 @@ class V8Js
174176
*/
175177
public static function getExtensions()
176178
{}
179+
180+
/**
181+
* Creates a custom V8 heap snapshot with the provided JavaScript source embedded.
182+
* Snapshots are supported by V8 4.3.7 and higher. For older versions of V8 this
183+
* extension doesn't provide this method.
184+
* @param string $embed_source
185+
* @return string|false
186+
*/
187+
public static function createSnapshot($embed_source)
188+
{}
177189
}
178190

179191
final class V8JsScriptException extends Exception

config.m4

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,6 @@ int main ()
130130
AC_MSG_ERROR([could not determine libv8 version])
131131
fi
132132

133-
AC_LANG_RESTORE
134-
LIBS=$old_LIBS
135-
LDFLAGS=$old_LDFLAGS
136-
CPPFLAGS=$old_CPPFLAGS
137-
138133
if test "$V8_API_VERSION" -ge 3029036 ; then
139134
dnl building for v8 3.29.36 or later, which requires us to
140135
dnl initialize and provide a platform; hence we need to
@@ -169,10 +164,101 @@ int main ()
169164
AC_MSG_ERROR([Please provide $static_link_extra_file next to the libv8.so, see README.md for details])
170165
fi
171166

172-
LDFLAGS="$LDFLAGS $static_link_dir/$static_link_extra_file"
167+
LDFLAGS_libplatform="$static_link_dir/$static_link_extra_file"
173168
done
169+
170+
# modify flags for (possibly) succeeding V8 startup check
171+
CPPFLAGS="$CPPFLAGS -I$V8_DIR"
172+
LIBS="$LIBS $LDFLAGS_libplatform"
174173
fi
175174

175+
if test "$V8_API_VERSION" -ge 4004010 ; then
176+
dnl building for v8 4.4.10 or later, which requires us to
177+
dnl provide startup data, if V8 wasn't compiled with snapshot=off.
178+
AC_MSG_CHECKING([whether V8 requires startup data])
179+
AC_TRY_RUN([
180+
#include <v8.h>
181+
#include <libplatform/libplatform.h>
182+
#include <stdlib.h>
183+
#include <string.h>
184+
185+
#if PHP_V8_API_VERSION >= 4004010
186+
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
187+
public:
188+
virtual void* Allocate(size_t length) {
189+
void* data = AllocateUninitialized(length);
190+
return data == NULL ? data : memset(data, 0, length);
191+
}
192+
virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
193+
virtual void Free(void* data, size_t) { free(data); }
194+
};
195+
#endif
196+
197+
int main ()
198+
{
199+
v8::Platform *v8_platform = v8::platform::CreateDefaultPlatform();
200+
v8::V8::InitializePlatform(v8_platform);
201+
v8::V8::Initialize();
202+
203+
#if PHP_V8_API_VERSION >= 4004044
204+
static ArrayBufferAllocator array_buffer_allocator;
205+
v8::Isolate::CreateParams create_params;
206+
create_params.array_buffer_allocator = &array_buffer_allocator;
207+
208+
v8::Isolate::New(create_params);
209+
#else /* PHP_V8_API_VERSION < 4004044 */
210+
v8::Isolate::New();
211+
#endif
212+
return 0;
213+
}
214+
], [
215+
AC_MSG_RESULT([no])
216+
], [
217+
AC_MSG_RESULT([yes])
218+
AC_DEFINE([PHP_V8_USE_EXTERNAL_STARTUP_DATA], [1], [Whether V8 requires (and can be provided with custom versions of) external startup data])
219+
220+
SEARCH_PATH="$V8_DIR/lib $V8_DIR/share/v8"
221+
222+
AC_MSG_CHECKING([for natives_blob.bin])
223+
SEARCH_FOR="natives_blob.bin"
224+
225+
for i in $SEARCH_PATH ; do
226+
if test -r $i/$SEARCH_FOR; then
227+
AC_MSG_RESULT([found ($i/$SEARCH_FOR)])
228+
AC_DEFINE_UNQUOTED([PHP_V8_NATIVES_BLOB_PATH], "$i/$SEARCH_FOR", [Full path to natives_blob.bin file])
229+
native_blob_found=1
230+
fi
231+
done
232+
233+
if test -z "$native_blob_found"; then
234+
AC_MSG_RESULT([not found])
235+
AC_MSG_ERROR([Please provide V8 native blob as needed])
236+
fi
237+
238+
AC_MSG_CHECKING([for snapshot_blob.bin])
239+
SEARCH_FOR="snapshot_blob.bin"
240+
241+
for i in $SEARCH_PATH ; do
242+
if test -r $i/$SEARCH_FOR; then
243+
AC_MSG_RESULT([found ($i/$SEARCH_FOR)])
244+
AC_DEFINE_UNQUOTED([PHP_V8_SNAPSHOT_BLOB_PATH], "$i/$SEARCH_FOR", [Full path to snapshot_blob.bin file])
245+
snapshot_blob_found=1
246+
fi
247+
done
248+
249+
if test -z "$snapshot_blob_found"; then
250+
AC_MSG_RESULT([not found])
251+
AC_MSG_ERROR([Please provide V8 snapshot blob as needed])
252+
fi
253+
])
254+
fi
255+
256+
AC_LANG_RESTORE
257+
LIBS=$old_LIBS
258+
LDFLAGS="$old_LDFLAGS $LDFLAGS_libplatform"
259+
CPPFLAGS=$old_CPPFLAGS
260+
261+
176262
PHP_NEW_EXTENSION(v8js, [ \
177263
v8js_array_access.cc \
178264
v8js.cc \

tests/create_snapshot_basic.phpt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
Test V8Js::createSnapshot() : Basic snapshot creation & re-use
3+
--SKIPIF--
4+
<?php
5+
require_once(dirname(__FILE__) . '/skipif.inc');
6+
7+
if (!method_exists('V8Js', 'createSnapshot')) {
8+
die('SKIP V8Js::createSnapshot not supported');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
$doublifySource = <<<EOJS
14+
function doublify(x) {
15+
return 2 * x;
16+
}
17+
EOJS;
18+
19+
$snap = V8Js::createSnapshot($doublifySource);
20+
21+
if (strlen($snap) > 0) {
22+
var_dump("snapshot successfully created");
23+
}
24+
25+
$v8 = new V8Js('PHP', array(), array(), true, $snap);
26+
$v8->executeString('var_dump(doublify(23));');
27+
?>
28+
===EOF===
29+
--EXPECT--
30+
string(29) "snapshot successfully created"
31+
int(46)
32+
===EOF===

0 commit comments

Comments
 (0)