diff --git a/README.Linux.md b/README.Linux.md index e85c261..9f9afc9 100644 --- a/README.Linux.md +++ b/README.Linux.md @@ -10,7 +10,23 @@ years ago, since Node.js requires such an old version. This means that you usually need to compile v8 on your own before you can start to compile & install v8js itself. -Compile latest v8 +Snapshots +--------- + +V8 has (optional) support for so-called snapshots which speed up startup +performance drastically. Hence they are generally recommended for use. + +There are two flavours of snapshots: internal & external. + +Internal snapshots are built right into the V8 library (libv8.so file), +so there's no need to handle them specially. + +Besides there are external snapshots (which are enabled unless configured +otherwise). If V8 is compiled with these, then V8Js needs to provide two +"binary blobs" to V8, named `natives_blob.bin` and `snapshot_blob.bin`. +In that case copy those two files to `/usr/share/v8/...`. + +Compile latest V8 ----------------- ``` @@ -25,11 +41,15 @@ fetch v8 cd v8 # (optional) If you'd like to build a certain version: -git checkout 3.32.6 +git checkout 4.9.385.28 gclient sync -# Build (disable snapshots for V8 > 4.4.9.1) -make native library=shared snapshot=off -j8 +# use libicu of operating system +export GYP_DEFINES="use_system_icu=1" + +# Build (with internal snapshots) +export GYPFLAGS="-Dv8_use_external_startup_data=0" +make native library=shared snapshot=on -j8 # Install to /usr 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 Then add `extension=v8js.so` to your php.ini file. If you have a separate configuration for CLI, add it there also. -* If the V8 library is newer than 4.4.9.1 you need to pass `snapshot=off` to - `make`, otherwise the V8 library will not be usable - (see V8 [Issue 4192](https://code.google.com/p/v8/issues/detail?id=4192)) * If you don't want to overwrite the system copy of v8, replace `/usr` in the above commands with some other path like `/opt/v8` and then add `--with-v8js=/opt/v8` to the php-v8js `./configure` command below. -* If you do that with a v8 library of 4.2 branch or newer, then you need - to fix the RUNPATH header in the v8js.so library so the libicui18n.so - is found. By default it is set to `$ORIGIN/lib.target/`, however the files - lie side by side. Use `chrpath -r '$ORIGIN' libv8.so` to fix. `libv8_libplatform.a` should not be copied directly since it's a thin archive, i.e. it contains only pointers to the build objects, which @@ -62,7 +75,7 @@ Compile php-v8js itself ``` cd /tmp -git clone https://github.com/preillyme/v8js.git +git clone https://github.com/phpv8/v8js.git cd v8js phpize ./configure diff --git a/README.md b/README.md index d318cf5..fd955cf 100644 --- a/README.md +++ b/README.md @@ -83,13 +83,15 @@ class V8Js /* Methods */ /** - * Initializes and starts V8 engine and Returns new V8Js object with it's own V8 context. + * Initializes and starts V8 engine and returns new V8Js object with it's own V8 context. + * Snapshots are supported by V8 4.3.7 and higher. * @param string $object_name * @param array $variables * @param array $extensions * @param bool $report_uncaught_exceptions + * @param string $snapshot_blob */ - public function __construct($object_name = "PHP", array $variables = NULL, array $extensions = NULL, $report_uncaught_exceptions = TRUE) + public function __construct($object_name = "PHP", array $variables = [], array $extensions = [], $report_uncaught_exceptions = TRUE, $snapshot_blob = NULL) {} /** @@ -195,6 +197,16 @@ class V8Js */ public static function getExtensions() {} + + /** + * Creates a custom V8 heap snapshot with the provided JavaScript source embedded. + * Snapshots are supported by V8 4.3.7 and higher. For older versions of V8 this + * extension doesn't provide this method. + * @param string $embed_source + * @return string|false + */ + public static function createSnapshot($embed_source) + {} } final class V8JsScriptException extends Exception diff --git a/config.m4 b/config.m4 index 5d9e4eb..7ba86d6 100644 --- a/config.m4 +++ b/config.m4 @@ -130,11 +130,6 @@ int main () AC_MSG_ERROR([could not determine libv8 version]) fi - AC_LANG_RESTORE - LIBS=$old_LIBS - LDFLAGS=$old_LDFLAGS - CPPFLAGS=$old_CPPFLAGS - if test "$V8_API_VERSION" -ge 3029036 ; then dnl building for v8 3.29.36 or later, which requires us to dnl initialize and provide a platform; hence we need to @@ -169,10 +164,101 @@ int main () AC_MSG_ERROR([Please provide $static_link_extra_file next to the libv8.so, see README.md for details]) fi - LDFLAGS="$LDFLAGS $static_link_dir/$static_link_extra_file" + LDFLAGS_libplatform="$static_link_dir/$static_link_extra_file" done + + # modify flags for (possibly) succeeding V8 startup check + CPPFLAGS="$CPPFLAGS -I$V8_DIR" + LIBS="$LIBS $LDFLAGS_libplatform" fi + if test "$V8_API_VERSION" -ge 4004010 ; then + dnl building for v8 4.4.10 or later, which requires us to + dnl provide startup data, if V8 wasn't compiled with snapshot=off. + AC_MSG_CHECKING([whether V8 requires startup data]) + AC_TRY_RUN([ + #include + #include + #include + #include + +#if PHP_V8_API_VERSION >= 4004010 +class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { +public: + virtual void* Allocate(size_t length) { + void* data = AllocateUninitialized(length); + return data == NULL ? data : memset(data, 0, length); + } + virtual void* AllocateUninitialized(size_t length) { return malloc(length); } + virtual void Free(void* data, size_t) { free(data); } +}; +#endif + + int main () + { + v8::Platform *v8_platform = v8::platform::CreateDefaultPlatform(); + v8::V8::InitializePlatform(v8_platform); + v8::V8::Initialize(); + +#if PHP_V8_API_VERSION >= 4004044 + static ArrayBufferAllocator array_buffer_allocator; + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = &array_buffer_allocator; + + v8::Isolate::New(create_params); +#else /* PHP_V8_API_VERSION < 4004044 */ + v8::Isolate::New(); +#endif + return 0; + } + ], [ + AC_MSG_RESULT([no]) + ], [ + AC_MSG_RESULT([yes]) + AC_DEFINE([PHP_V8_USE_EXTERNAL_STARTUP_DATA], [1], [Whether V8 requires (and can be provided with custom versions of) external startup data]) + + SEARCH_PATH="$V8_DIR/lib $V8_DIR/share/v8" + + AC_MSG_CHECKING([for natives_blob.bin]) + SEARCH_FOR="natives_blob.bin" + + for i in $SEARCH_PATH ; do + if test -r $i/$SEARCH_FOR; then + AC_MSG_RESULT([found ($i/$SEARCH_FOR)]) + AC_DEFINE_UNQUOTED([PHP_V8_NATIVES_BLOB_PATH], "$i/$SEARCH_FOR", [Full path to natives_blob.bin file]) + native_blob_found=1 + fi + done + + if test -z "$native_blob_found"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Please provide V8 native blob as needed]) + fi + + AC_MSG_CHECKING([for snapshot_blob.bin]) + SEARCH_FOR="snapshot_blob.bin" + + for i in $SEARCH_PATH ; do + if test -r $i/$SEARCH_FOR; then + AC_MSG_RESULT([found ($i/$SEARCH_FOR)]) + AC_DEFINE_UNQUOTED([PHP_V8_SNAPSHOT_BLOB_PATH], "$i/$SEARCH_FOR", [Full path to snapshot_blob.bin file]) + snapshot_blob_found=1 + fi + done + + if test -z "$snapshot_blob_found"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Please provide V8 snapshot blob as needed]) + fi + ]) + fi + + AC_LANG_RESTORE + LIBS=$old_LIBS + LDFLAGS="$old_LDFLAGS $LDFLAGS_libplatform" + CPPFLAGS=$old_CPPFLAGS + + PHP_NEW_EXTENSION(v8js, [ \ v8js_array_access.cc \ v8js.cc \ diff --git a/package.xml b/package.xml index 386df10..5b82722 100644 --- a/package.xml +++ b/package.xml @@ -74,8 +74,8 @@ This release also merges in new features from V8Js 0.4.0, namely - - + + @@ -99,7 +99,8 @@ This release also merges in new features from V8Js 0.4.0, namely - + + @@ -137,6 +138,13 @@ This release also merges in new features from V8Js 0.4.0, namely + + + + + + + @@ -546,5 +554,24 @@ This release also merges in new features from V8Js 0.4.0, namely - V8Js' internal module path normalisation may now be overrode using setModuleNormaliser + + + 0.5.0 + 0.5.0 + + + stable + stable + + 2016-03-05 + The MIT License (MIT) + +- Export public methods on classes derived from \V8Js to V8 +- Support V8 compiled with external snapshots +- Allow to create custom snapshots of V8 heaps +- Allow to create V8 contexts based on custom snapshots generated earlier +- Support V8 5.1 well + + diff --git a/php_v8js_macros.h b/php_v8js_macros.h index acffbc1..b5000d2 100644 --- a/php_v8js_macros.h +++ b/php_v8js_macros.h @@ -79,6 +79,13 @@ extern "C" { #define V8JS_FLAG_FORCE_ARRAY (1<<1) #define V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS (1<<2) + +/* These are not defined by Zend */ +#define ZEND_WAKEUP_FUNC_NAME "__wakeup" +#define ZEND_SLEEP_FUNC_NAME "__sleep" +#define ZEND_SET_STATE_FUNC_NAME "__set_state" + + /* Convert zval into V8 value */ v8::Handle zval_to_v8js(zval *, v8::Isolate * TSRMLS_DC); diff --git a/tests/checkstring.phpt b/tests/checkstring.phpt index b5f2790..9d6ce0e 100644 --- a/tests/checkstring.phpt +++ b/tests/checkstring.phpt @@ -20,5 +20,5 @@ Deprecated: Function V8Js::checkString() is deprecated in %s on line %d bool(true) Deprecated: Function V8Js::checkString() is deprecated in %s on line %d -string(60) "V8Js::checkString():1: SyntaxError: Unexpected token ILLEGAL" +string(%d) "V8Js::checkString():1: SyntaxError: %s" ===EOF=== diff --git a/tests/checkstring_compile.phpt b/tests/checkstring_compile.phpt index 2c9e188..c571e06 100644 --- a/tests/checkstring_compile.phpt +++ b/tests/checkstring_compile.phpt @@ -17,5 +17,5 @@ try { ===EOF=== --EXPECTF-- resource(%d) of type (V8Js script) -string(62) "V8Js::compileString():1: SyntaxError: Unexpected token ILLEGAL" +string(%d) "V8Js::compileString():1: SyntaxError: %s" ===EOF=== diff --git a/tests/create_snapshot_basic.phpt b/tests/create_snapshot_basic.phpt new file mode 100644 index 0000000..731426d --- /dev/null +++ b/tests/create_snapshot_basic.phpt @@ -0,0 +1,32 @@ +--TEST-- +Test V8Js::createSnapshot() : Basic snapshot creation & re-use +--SKIPIF-- + +--FILE-- + 0) { + var_dump("snapshot successfully created"); +} + +$v8 = new V8Js('PHP', array(), array(), true, $snap); +$v8->executeString('var_dump(doublify(23));'); +?> +===EOF=== +--EXPECT-- +string(29) "snapshot successfully created" +int(46) +===EOF=== diff --git a/tests/issue_183_001.phpt b/tests/issue_183_001.phpt new file mode 100644 index 0000000..c22a6d1 --- /dev/null +++ b/tests/issue_183_001.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test V8::executeString() : Method access on derived classes (protected) +--SKIPIF-- + +--FILE-- +executeString($JS); + +?> +===EOF=== +--EXPECTF-- +Fatal error: Uncaught V8JsScriptException: V8Js::compileString():1: TypeError: %s in %s +Stack trace: +#0 %s: V8Js->executeString('PHP.hello();') +#1 {main} + thrown in %s on line 16 diff --git a/tests/issue_183_002.phpt b/tests/issue_183_002.phpt new file mode 100644 index 0000000..c8dcfa7 --- /dev/null +++ b/tests/issue_183_002.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test V8::executeString() : Method access on derived classes (private) +--SKIPIF-- + +--FILE-- +executeString($JS); + +?> +===EOF=== +--EXPECTF-- +Fatal error: Uncaught V8JsScriptException: V8Js::compileString():1: TypeError: %s in %s +Stack trace: +#0 %s: V8Js->executeString('PHP.hello();') +#1 {main} + thrown in %s on line 16 diff --git a/tests/issue_183_003.phpt b/tests/issue_183_003.phpt new file mode 100644 index 0000000..1a96c3f --- /dev/null +++ b/tests/issue_183_003.phpt @@ -0,0 +1,57 @@ +--TEST-- +Test V8::executeString() : Method access on derived classes (V8Js methods) +--SKIPIF-- + +--FILE-- +executeString($JS); + +?> +===EOF=== +--EXPECTF-- +string(8) "function" +string(9) "undefined" +string(9) "undefined" +string(9) "undefined" +string(9) "undefined" +string(9) "undefined" +string(9) "undefined" +string(9) "undefined" +string(9) "undefined" +string(9) "undefined" +string(9) "undefined" +string(9) "undefined" +string(6) "caught" +===EOF=== diff --git a/tests/issue_183_004.phpt b/tests/issue_183_004.phpt new file mode 100644 index 0000000..e4d2f17 --- /dev/null +++ b/tests/issue_183_004.phpt @@ -0,0 +1,44 @@ +--TEST-- +Test V8::executeString() : Method access on derived classes (overridden V8Js methods) +--SKIPIF-- + +--FILE-- +executeString($JS); + +?> +===EOF=== +--EXPECTF-- +string(13) "executeString" +string(8) "function" +string(9) "undefined" +string(6) "caught" +===EOF=== diff --git a/tests/issue_183_005.phpt b/tests/issue_183_005.phpt new file mode 100644 index 0000000..2cff423 --- /dev/null +++ b/tests/issue_183_005.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test V8::executeString() : Method access on derived classes (__sleep) +--SKIPIF-- + +--FILE-- + +===EOF=== +--EXPECTF-- +Fatal error: Cannot override final method V8Js::__sleep() in %s diff --git a/tests/issue_183_006.phpt b/tests/issue_183_006.phpt new file mode 100644 index 0000000..395e905 --- /dev/null +++ b/tests/issue_183_006.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test V8::executeString() : Method access on derived classes (__wakeup) +--SKIPIF-- + +--FILE-- + +===EOF=== +--EXPECTF-- +Fatal error: Cannot override final method V8Js::__wakeup() in %s diff --git a/tests/issue_183_basic.phpt b/tests/issue_183_basic.phpt new file mode 100644 index 0000000..3a0cca5 --- /dev/null +++ b/tests/issue_183_basic.phpt @@ -0,0 +1,27 @@ +--TEST-- +Test V8::executeString() : Method access on derived classes +--SKIPIF-- + +--FILE-- +executeString($JS); + +?> +===EOF=== +--EXPECT-- +Hello World +===EOF=== diff --git a/v8js_class.cc b/v8js_class.cc index 1ed8f57..be4de4a 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -23,6 +23,7 @@ #include "v8js_v8.h" #include "v8js_exceptions.h" #include "v8js_v8object_class.h" +#include "v8js_object_export.h" #include "v8js_timer.h" extern "C" { @@ -45,6 +46,9 @@ static zend_class_entry *php_ce_v8js; static zend_object_handlers v8js_object_handlers; /* }}} */ +/* Forward declare v8js_methods, actually "static" but not possible in C++ */ +extern const zend_function_entry v8js_methods[]; + typedef struct _v8js_script { char *name; v8js_ctx *ctx; @@ -197,6 +201,10 @@ static void v8js_free_storage(zend_object *object TSRMLS_DC) /* {{{ */ c->modules_stack.~vector(); c->modules_base.~vector(); + +#if PHP_V8_API_VERSION >= 4003007 + zval_dtor(&c->zval_snapshot_blob); +#endif } /* }}} */ @@ -311,7 +319,11 @@ static void v8js_fatal_error_handler(const char *location, const char *message) } /* }}} */ -/* {{{ proto void V8Js::__construct([string object_name [, array variables [, array extensions [, bool report_uncaught_exceptions]]]) +#define IS_MAGIC_FUNC(mname) \ + ((ZSTR_LEN(key) == sizeof(mname) - 1) && \ + !strncasecmp(ZSTR_VAL(key), mname, ZSTR_LEN(key))) + +/* {{{ proto void V8Js::__construct([string object_name [, array variables [, array extensions [, bool report_uncaught_exceptions [, string snapshot_blob]]]]]) __construct for V8Js */ static PHP_METHOD(V8Js, __construct) { @@ -320,6 +332,7 @@ static PHP_METHOD(V8Js, __construct) zval *vars_arr = NULL, *exts_arr = NULL; const char **exts = NULL; int exts_count = 0; + zval *snapshot_blob = NULL; v8js_ctx *c = Z_V8JS_CTX_OBJ_P(getThis()) @@ -328,7 +341,7 @@ static PHP_METHOD(V8Js, __construct) return; } - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Saab", &object_name, &vars_arr, &exts_arr, &report_uncaught) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Saabz", &object_name, &vars_arr, &exts_arr, &report_uncaught, &snapshot_blob) == FAILURE) { return; } @@ -340,12 +353,29 @@ static PHP_METHOD(V8Js, __construct) ZVAL_NULL(&c->pending_exception); c->in_execution = 0; +#if PHP_V8_API_VERSION >= 4003007 + new (&c->create_params) v8::Isolate::CreateParams(); + #if PHP_V8_API_VERSION >= 4004044 static ArrayBufferAllocator array_buffer_allocator; - static v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = &array_buffer_allocator; - c->isolate = v8::Isolate::New(create_params); -#else + c->create_params.array_buffer_allocator = &array_buffer_allocator; +#endif + + new (&c->snapshot_blob) v8::StartupData(); + if (snapshot_blob) { + if (Z_TYPE_P(snapshot_blob) == IS_STRING) { + ZVAL_COPY(&c->zval_snapshot_blob, snapshot_blob); + + c->snapshot_blob.data = Z_STRVAL_P(snapshot_blob); + c->snapshot_blob.raw_size = Z_STRLEN_P(snapshot_blob); + c->create_params.snapshot_blob = &c->snapshot_blob; + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument snapshot_blob expected to be of string type"); + } + } + + c->isolate = v8::Isolate::New(c->create_params); +#else /* PHP_V8_API_VERSION < 4003007 */ c->isolate = v8::Isolate::New(); #endif @@ -456,7 +486,72 @@ static PHP_METHOD(V8Js, __construct) } } ZEND_HASH_FOREACH_END(); + /* Add pointer to zend object */ + php_obj->SetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY), v8::External::New(isolate, Z_OBJ_P(getThis()))); + /* Export public methods */ + void *ptr; + zend_string *key; + uint key_len; + + ZEND_HASH_FOREACH_STR_KEY_PTR(&c->std.ce->function_table, key, ptr) { + zend_function *method_ptr = reinterpret_cast(ptr); + + if ((method_ptr->common.fn_flags & ZEND_ACC_PUBLIC) == 0) { + /* Allow only public methods */ + continue; + } + + if ((method_ptr->common.fn_flags & (ZEND_ACC_CTOR|ZEND_ACC_DTOR|ZEND_ACC_CLONE)) != 0) { + /* no __construct, __destruct(), or __clone() functions */ + continue; + } + + /* hide (do not export) other PHP magic functions */ + if (IS_MAGIC_FUNC(ZEND_CALLSTATIC_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_SLEEP_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_WAKEUP_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_SET_STATE_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_GET_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_SET_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_UNSET_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_CALL_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_INVOKE_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_TOSTRING_FUNC_NAME) || + IS_MAGIC_FUNC(ZEND_ISSET_FUNC_NAME)) { + continue; + } + + const zend_function_entry *fe; + for (fe = v8js_methods; fe->fname; fe ++) { + if (strcmp(fe->fname, ZSTR_VAL(method_ptr->common.function_name)) == 0) { + break; + } + } + + if(fe->fname) { + /* Method belongs to \V8Js class itself, never export to V8, even if + * it is overriden in a derived class. */ + continue; + } + + v8::Local method_name = V8JS_ZSTR(method_ptr->common.function_name); + v8::Local ft; + + /*try { + ft = v8::Local::New + (isolate, c->method_tmpls.at(method_ptr)); + } + catch (const std::out_of_range &) */ { + ft = v8::FunctionTemplate::New(isolate, v8js_php_callback, + v8::External::New((isolate), method_ptr)); + // @fixme add/check Signature v8::Signature::New((isolate), tmpl)); + v8js_tmpl_t *persistent_ft = &c->method_tmpls[method_ptr]; + persistent_ft->Reset(isolate, ft); + } + + php_obj->ForceSet(method_name, ft->GetFunction()); + } ZEND_HASH_FOREACH_END(); } /* }}} */ @@ -887,6 +982,10 @@ static int v8js_register_extension(zend_string *name, zend_string *source, zval } /* }}} */ + + +/* ## Static methods ## */ + /* {{{ proto bool V8Js::registerExtension(string ext_name, string script [, array deps [, bool auto_enable]]) */ static PHP_METHOD(V8Js, registerExtension) @@ -910,8 +1009,6 @@ static PHP_METHOD(V8Js, registerExtension) } /* }}} */ -/* ## Static methods ## */ - /* {{{ proto array V8Js::getExtensions() */ static PHP_METHOD(V8Js, getExtensions) @@ -954,12 +1051,47 @@ static PHP_METHOD(V8Js, getExtensions) } /* }}} */ +#if PHP_V8_API_VERSION >= 4003007 +/* {{{ proto string|bool V8Js::createSnapshot(string embed_source) + */ +static PHP_METHOD(V8Js, createSnapshot) +{ + char *script; + int script_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &script, &script_len) == FAILURE) { + return; + } + + if (!script_len) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Script cannot be empty"); + RETURN_FALSE; + } + + /* Initialize V8, if not already done. */ + v8js_v8_init(TSRMLS_C); + + v8::StartupData snapshot_blob = v8::V8::CreateSnapshotDataBlob(script); + + if (!snapshot_blob.data) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create V8 heap snapshot. Check $embed_source for errors."); + RETURN_FALSE; + } + + RETVAL_STRINGL(snapshot_blob.data, snapshot_blob.raw_size); + delete[] snapshot_blob.data; +} +/* }}} */ +#endif /* PHP_V8_API_VERSION >= 4003007 */ + + /* {{{ arginfo */ ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_construct, 0, 0, 0) ZEND_ARG_INFO(0, object_name) ZEND_ARG_INFO(0, variables) ZEND_ARG_INFO(0, extensions) ZEND_ARG_INFO(0, report_uncaught_exceptions) + ZEND_ARG_INFO(0, snapshot_blob) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_v8js_sleep, 0) @@ -1017,6 +1149,12 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_v8js_getextensions, 0) ZEND_END_ARG_INFO() +#if PHP_V8_API_VERSION >= 4003007 +ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_createsnapshot, 0, 0, 1) + ZEND_ARG_INFO(0, script) +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_settimelimit, 0, 0, 1) ZEND_ARG_INFO(0, time_limit) ZEND_END_ARG_INFO() @@ -1026,7 +1164,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_setmemorylimit, 0, 0, 1) ZEND_END_ARG_INFO() -static const zend_function_entry v8js_methods[] = { /* {{{ */ +const zend_function_entry v8js_methods[] = { /* {{{ */ PHP_ME(V8Js, __construct, arginfo_v8js_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(V8Js, __sleep, arginfo_v8js_sleep, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) PHP_ME(V8Js, __wakeup, arginfo_v8js_sleep, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) @@ -1038,10 +1176,14 @@ static const zend_function_entry v8js_methods[] = { /* {{{ */ PHP_ME(V8Js, clearPendingException, arginfo_v8js_clearpendingexception, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setModuleNormaliser, arginfo_v8js_setmodulenormaliser, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setModuleLoader, arginfo_v8js_setmoduleloader, ZEND_ACC_PUBLIC) - PHP_ME(V8Js, registerExtension, arginfo_v8js_registerextension, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(V8Js, getExtensions, arginfo_v8js_getextensions, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(V8Js, setTimeLimit, arginfo_v8js_settimelimit, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setMemoryLimit, arginfo_v8js_setmemorylimit, ZEND_ACC_PUBLIC) + PHP_ME(V8Js, registerExtension, arginfo_v8js_registerextension, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(V8Js, getExtensions, arginfo_v8js_getextensions, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + +#if PHP_V8_API_VERSION >= 4003007 + PHP_ME(V8Js, createSnapshot, arginfo_v8js_createsnapshot, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) +#endif {NULL, NULL, NULL} }; /* }}} */ diff --git a/v8js_class.h b/v8js_class.h index f31a25f..f18cea0 100644 --- a/v8js_class.h +++ b/v8js_class.h @@ -2,12 +2,13 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | http://www.opensource.org/licenses/mit-license.php MIT License | +----------------------------------------------------------------------+ | Author: Jani Taskinen | | Author: Patrick Reilly | + | Author: Stefan Siegl | +----------------------------------------------------------------------+ */ @@ -67,6 +68,13 @@ struct v8js_ctx { std::vector accessor_list; std::vector script_objects; char *tz; + +#if PHP_V8_API_VERSION >= 4003007 + v8::Isolate::CreateParams create_params; + zval zval_snapshot_blob; + v8::StartupData snapshot_blob; +#endif + #ifdef ZTS void ***zts_ctx; #endif diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 85aa33e..305c377 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -167,7 +167,7 @@ failure: /* }}} */ /* Callback for PHP methods and functions */ -static void v8js_php_callback(const v8::FunctionCallbackInfo& info) /* {{{ */ +void v8js_php_callback(const v8::FunctionCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); v8::Local self = info.Holder(); @@ -290,11 +290,6 @@ static void v8js_weak_closure_callback(const v8::WeakCallbackDataweak_closures.erase(persist_tpl_); }; -/* These are not defined by Zend */ -#define ZEND_WAKEUP_FUNC_NAME "__wakeup" -#define ZEND_SLEEP_FUNC_NAME "__sleep" -#define ZEND_SET_STATE_FUNC_NAME "__set_state" - #define IS_MAGIC_FUNC(mname) \ ((ZSTR_LEN(key) == sizeof(mname) - 1) && \ !strncasecmp(ZSTR_VAL(key), mname, ZSTR_LEN(key))) diff --git a/v8js_object_export.h b/v8js_object_export.h index 72c48a7..ea697b4 100644 --- a/v8js_object_export.h +++ b/v8js_object_export.h @@ -30,4 +30,6 @@ v8::Local v8js_named_property_callback(v8::Local property property_op_t callback_type, v8::Local set_value = v8::Local()); +void v8js_php_callback(const v8::FunctionCallbackInfo& info); + #endif /* V8JS_OBJECT_EXPORT_H */ diff --git a/v8js_v8.cc b/v8js_v8.cc index 633f38d..000e6fd 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2015 The PHP Group | + | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | http://www.opensource.org/licenses/mit-license.php MIT License | +----------------------------------------------------------------------+ @@ -33,6 +33,44 @@ extern "C" { #include #endif + +#if defined(PHP_V8_USE_EXTERNAL_STARTUP_DATA) && PHP_V8_API_VERSION < 4006076 +/* Old V8 version, requires startup data but has no + * (internal/API) means to let it be loaded. */ +static v8::StartupData natives_; +static v8::StartupData snapshot_; + +static void v8js_v8_load_startup_data(const char* blob_file, + v8::StartupData* startup_data, + void (*setter_fn)(v8::StartupData*)) { + startup_data->data = NULL; + startup_data->raw_size = 0; + + if (!blob_file) { + return; + } + + FILE* file = fopen(blob_file, "rb"); + if (!file) { + return; + } + + fseek(file, 0, SEEK_END); + startup_data->raw_size = static_cast(ftell(file)); + rewind(file); + + startup_data->data = new char[startup_data->raw_size]; + int read_size = static_cast(fread(const_cast(startup_data->data), + 1, startup_data->raw_size, file)); + fclose(file); + + if (startup_data->raw_size == read_size) { + (*setter_fn)(startup_data); + } +} +#endif + + void v8js_v8_init(TSRMLS_D) /* {{{ */ { /* Run only once; thread-local test first */ @@ -53,6 +91,19 @@ void v8js_v8_init(TSRMLS_D) /* {{{ */ } #endif +#ifdef PHP_V8_USE_EXTERNAL_STARTUP_DATA + /* V8 doesn't work without startup data, load it. */ +#if PHP_V8_API_VERSION >= 4006076 + v8::V8::InitializeExternalStartupData( + PHP_V8_NATIVES_BLOB_PATH, + PHP_V8_SNAPSHOT_BLOB_PATH + ); +#else + v8js_v8_load_startup_data(PHP_V8_NATIVES_BLOB_PATH, &natives_, v8::V8::SetNativesDataBlob); + v8js_v8_load_startup_data(PHP_V8_SNAPSHOT_BLOB_PATH, &snapshot_, v8::V8::SetSnapshotDataBlob); +#endif +#endif + #if PHP_V8_API_VERSION >= 3029036 v8js_process_globals.v8_platform = v8::platform::CreateDefaultPlatform(); v8::V8::InitializePlatform(v8js_process_globals.v8_platform);