From 12903ca269c84ab82a4e08658c2a0cb5d20f2557 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Tue, 8 Mar 2016 09:28:16 +0100 Subject: [PATCH 01/30] add V8Js::setAverageObjectSize method --- README.md | 8 ++++++++ tests/set_average_object_size_basic.phpt | 16 +++++++++++++++ v8js_class.cc | 25 +++++++++++++++++++++++- v8js_class.h | 1 + v8js_object_export.cc | 4 ++-- 5 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 tests/set_average_object_size_basic.phpt diff --git a/README.md b/README.md index c4a54b6..e409173 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,14 @@ class V8Js public function setMemoryLimit($limit) {} + /** + * Set the average object size (in bytes) for this V8Js object. + * V8's "amount of external memory" is adjusted by this value for every exported object. V8 triggers a garbage collection once this totals to 192 MB. + * @param int $average_object_size + */ + public function setAverageObjectSize($average_object_size) + {} + /** * Returns uncaught pending exception or null if there is no pending exception. * @return V8JsScriptException|null diff --git a/tests/set_average_object_size_basic.phpt b/tests/set_average_object_size_basic.phpt new file mode 100644 index 0000000..8247ef1 --- /dev/null +++ b/tests/set_average_object_size_basic.phpt @@ -0,0 +1,16 @@ +--TEST-- +Test V8::setAverageObjectSize() : Average object size can be set on V8Js object +--SKIPIF-- + +--FILE-- +setAverageObjectSize(32768); + +// there's no API to query the currently announced external memory allocation, +// hence not much we can do here... + +?> +===EOF=== +--EXPECT-- +===EOF=== diff --git a/v8js_class.cc b/v8js_class.cc index f10725f..65c4993 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -158,7 +158,7 @@ static void v8js_free_storage(void *object TSRMLS_DC) /* {{{ */ it != c->weak_objects.end(); ++it) { zval *value = it->first; zval_ptr_dtor(&value); - c->isolate->AdjustAmountOfExternalAllocatedMemory(-1024); + c->isolate->AdjustAmountOfExternalAllocatedMemory(-c->average_object_size); it->second.Reset(); } c->weak_objects.~map(); @@ -254,6 +254,8 @@ static zend_object_value v8js_new(zend_class_entry *ce TSRMLS_DC) /* {{{ */ new(&c->v8js_v8objects) std::list(); new(&c->script_objects) std::vector(); + c->average_object_size = 1024; + retval.handle = zend_objects_store_put(c, NULL, (zend_objects_free_object_storage_t) v8js_free_storage, NULL TSRMLS_CC); retval.handlers = &v8js_object_handlers; @@ -899,6 +901,22 @@ static PHP_METHOD(V8Js, setMemoryLimit) } /* }}} */ +/* {{{ proto void V8Js::setAverageObjectSize(average_object_size) + */ +static PHP_METHOD(V8Js, setAverageObjectSize) +{ + v8js_ctx *c; + long average_object_size = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &average_object_size) == FAILURE) { + return; + } + + c = (v8js_ctx *) zend_object_store_get_object(getThis() TSRMLS_CC); + c->average_object_size = average_object_size; +} +/* }}} */ + static void v8js_persistent_zval_ctor(zval **p) /* {{{ */ { zval *orig_ptr = *p; @@ -1178,6 +1196,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_setmoduleloader, 0, 0, 1) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_setaverageobjectsize, 0, 0, 1) + ZEND_ARG_INFO(0, average_object_size) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_registerextension, 0, 0, 2) ZEND_ARG_INFO(0, extension_name) ZEND_ARG_INFO(0, script) @@ -1217,6 +1239,7 @@ const zend_function_entry v8js_methods[] = { /* {{{ */ PHP_ME(V8Js, setModuleLoader, arginfo_v8js_setmoduleloader, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setTimeLimit, arginfo_v8js_settimelimit, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setMemoryLimit, arginfo_v8js_setmemorylimit, ZEND_ACC_PUBLIC) + PHP_ME(V8Js, setAverageObjectSize, arginfo_v8js_setaverageobjectsize, 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) diff --git a/v8js_class.h b/v8js_class.h index 0e91243..f4edeb5 100644 --- a/v8js_class.h +++ b/v8js_class.h @@ -47,6 +47,7 @@ struct v8js_ctx { bool time_limit_hit; long memory_limit; bool memory_limit_hit; + long average_object_size; v8js_tmpl_t global_template; v8js_tmpl_t array_tmpl; diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 949888f..9562178 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -259,7 +259,7 @@ static void v8js_construct_callback(const v8::FunctionCallbackInfo& i // Just tell v8 that we're allocating some external memory // (for the moment we just always tell 1k instead of trying to find out actual values) - isolate->AdjustAmountOfExternalAllocatedMemory(1024); + isolate->AdjustAmountOfExternalAllocatedMemory(ctx->average_object_size); } /* }}} */ @@ -275,7 +275,7 @@ static void v8js_weak_object_callback(const v8::WeakCallbackDataweak_objects.at(value).Reset(); ctx->weak_objects.erase(value); - isolate->AdjustAmountOfExternalAllocatedMemory(-1024); + isolate->AdjustAmountOfExternalAllocatedMemory(-ctx->average_object_size); } static void v8js_weak_closure_callback(const v8::WeakCallbackData &data) { From 4c548e60f240ee47862d6965eafffce05c04732d Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Tue, 8 Mar 2016 18:11:29 +0100 Subject: [PATCH 02/30] Bump version to 0.6.0 --- package.xml | 40 ++++++++++++++++++++++++++-------------- php_v8js_macros.h | 2 +- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/package.xml b/package.xml index 53a6dd0..9b81a2b 100644 --- a/package.xml +++ b/package.xml @@ -16,11 +16,11 @@ stesie@php.net yes - 2016-03-05 - + 2016-03-08 + - 0.5.0 - 0.5.0 + 0.6.0 + 0.6.0 stable @@ -28,11 +28,7 @@ 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 +- Allow to adjust the considered "amount of external memory" by objects exported to V8 @@ -176,6 +172,7 @@ + @@ -199,25 +196,25 @@ - + - + - - + + - + @@ -518,5 +515,20 @@ - Support V8 5.1 well + + + 0.6.0 + 0.6.0 + + + stable + stable + + 2016-03-08 + The MIT License (MIT) + +- Allow to adjust the considered "amount of external memory" by objects exported to V8 + + diff --git a/php_v8js_macros.h b/php_v8js_macros.h index d0a4760..8969e90 100644 --- a/php_v8js_macros.h +++ b/php_v8js_macros.h @@ -53,7 +53,7 @@ extern "C" { #endif /* V8Js Version */ -#define PHP_V8JS_VERSION "0.5.0" +#define PHP_V8JS_VERSION "0.6.0" /* Hidden field name used to link JS wrappers with underlying PHP object */ #define PHPJS_OBJECT_KEY "phpjs::object" From 468d9e109056f843f7b7550fb5de459836fa7ee7 Mon Sep 17 00:00:00 2001 From: Jan Ehrhardt Date: Tue, 8 Mar 2016 22:12:51 +0100 Subject: [PATCH 03/30] Windows: Autodetect V8 API & V8 Engine Compiled Version --- config.w32 | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/config.w32 b/config.w32 index df85c80..24c0fd2 100644 --- a/config.w32 +++ b/config.w32 @@ -10,8 +10,36 @@ if (PHP_V8JS != "no") { ADD_FLAG("CFLAGS_V8JS", "/D ZEND_WIN32_FORCE_INLINE"); ADD_FLAG("CFLAGS_V8JS", "/D __STDC_LIMIT_MACROS"); - AC_DEFINE("PHP_V8_API_VERSION", "3017015", "", false); - AC_DEFINE("PHP_V8_VERSION", "3.17.15", "", true); + // defaults + var v8major = 4; + var v8minor = 7; + var v8build = 75; + var v8patch = 0; + var v8pinc = search_paths("v8-version.h", php_usual_include_suspects, null); + if (typeof(v8pinc) == "string") { + var v8versionh = file_get_contents(v8pinc + '\\v8-version.h'); + if (v8versionh.match(/#define V8_MAJOR_VERSION ([0-9]*)/i)) { + v8major = RegExp.$1; + } + if (v8versionh.match(/#define V8_MINOR_VERSION ([0-9]*)/i)) { + v8minor = RegExp.$1; + } + if (v8versionh.match(/#define V8_BUILD_NUMBER ([0-9]*)/i)) { + v8build = RegExp.$1; + } + if (v8versionh.match(/#define V8_PATCH_LEVEL ([0-9]*)/i)) { + v8patch = RegExp.$1; + } + } else { + WARNING("Could not parse v8-version.h"); + } + var v8api = v8major + v8js_zeroPad(v8minor,2) + v8js_zeroPad(v8build,2) + v8js_zeroPad(v8patch,2); + var v8ver = v8major+"."+v8minor+"."+v8build+"."+v8patch; + //WARNING("v8api = " + v8api + ", v8ver = " + v8ver); + AC_DEFINE("PHP_V8_API_VERSION", v8api, "", false); + AC_DEFINE("PHP_V8_VERSION", v8ver, "", true); + //AC_DEFINE("PHP_V8_API_VERSION", "4007075", "", false); + //AC_DEFINE("PHP_V8_VERSION", "4.7.75", "", true); EXTENSION("v8js", "v8js_array_access.cc v8js.cc v8js_class.cc v8js_commonjs.cc v8js_convert.cc v8js_exceptions.cc v8js_methods.cc v8js_object_export.cc v8js_timer.cc v8js_v8.cc v8js_v8object_class.cc v8js_variables.cc", "yes"); From 8575dc0e554f369d9c48ca698c3c72e0a098286b Mon Sep 17 00:00:00 2001 From: Jan Ehrhardt Date: Tue, 8 Mar 2016 22:46:32 +0100 Subject: [PATCH 04/30] #210 Windows: Autodetect V8 API & V8 Engine Compiled Version - v8js_zeroPad --- config.w32 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config.w32 b/config.w32 index 24c0fd2..4f4c737 100644 --- a/config.w32 +++ b/config.w32 @@ -1,6 +1,11 @@ ARG_WITH("v8js", "for V8 Javascript Engine", "no"); +function v8js_zeroPad(num, places) { + var zero = places - num.toString().length + 1; + return Array(+(zero > 0 && zero)).join("0") + num; +} + if (PHP_V8JS != "no") { if (CHECK_LIB("v8.lib", "v8js") && CHECK_HEADER_ADD_INCLUDE("v8.h", "CFLAGS_V8JS")) { From dd2ad914520343bb177476c58ae1c80ae931d4cc Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Wed, 9 Mar 2016 11:42:14 +0100 Subject: [PATCH 05/30] config.w32: fix v8api version generation, refs #210 --- config.w32 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/config.w32 b/config.w32 index 4f4c737..43492b8 100644 --- a/config.w32 +++ b/config.w32 @@ -38,13 +38,12 @@ if (PHP_V8JS != "no") { } else { WARNING("Could not parse v8-version.h"); } - var v8api = v8major + v8js_zeroPad(v8minor,2) + v8js_zeroPad(v8build,2) + v8js_zeroPad(v8patch,2); - var v8ver = v8major+"."+v8minor+"."+v8build+"."+v8patch; - //WARNING("v8api = " + v8api + ", v8ver = " + v8ver); + + var v8api = v8major + v8js_zeroPad(v8minor, 3) + v8js_zeroPad(v8build, 3); + var v8ver = v8major + "." + v8minor + "." + v8build + "." + v8patch; + AC_DEFINE("PHP_V8_API_VERSION", v8api, "", false); AC_DEFINE("PHP_V8_VERSION", v8ver, "", true); - //AC_DEFINE("PHP_V8_API_VERSION", "4007075", "", false); - //AC_DEFINE("PHP_V8_VERSION", "4.7.75", "", true); EXTENSION("v8js", "v8js_array_access.cc v8js.cc v8js_class.cc v8js_commonjs.cc v8js_convert.cc v8js_exceptions.cc v8js_methods.cc v8js_object_export.cc v8js_timer.cc v8js_v8.cc v8js_v8object_class.cc v8js_variables.cc", "yes"); From 2f5db5d9ef2647cc092a1a7a31efa588b9854dcb Mon Sep 17 00:00:00 2001 From: Tieme van Veen Date: Thu, 10 Mar 2016 10:58:53 +0100 Subject: [PATCH 06/30] Linux guide - Move adding extension to php.ini to bottom --- README.Linux.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.Linux.md b/README.Linux.md index 9f9afc9..5bb44df 100644 --- a/README.Linux.md +++ b/README.Linux.md @@ -58,8 +58,6 @@ sudo cp -R include/* /usr/include echo -e "create /usr/lib/libv8_libplatform.a\naddlib out/native/obj.target/tools/gyp/libv8_libplatform.a\nsave\nend" | sudo ar -M ``` -Then add `extension=v8js.so` to your php.ini file. If you have a separate configuration for CLI, add it there also. - * 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. @@ -83,3 +81,5 @@ make make test sudo make install ``` + +Then add `extension=v8js.so` to your php.ini file. If you have a separate configuration for CLI, add it there also. From 28a5832f230fb2f03a3533ff68ea1d42f2e9857b Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Wed, 23 Mar 2016 10:24:50 +0100 Subject: [PATCH 07/30] Fix configuration on MacOS platform --- config.m4 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.m4 b/config.m4 index f721165..63a86f4 100644 --- a/config.m4 +++ b/config.m4 @@ -145,6 +145,7 @@ int main () ;; esac + LDFLAGS_libplatform="" for static_link_extra_file in $static_link_extra; do AC_MSG_CHECKING([for $static_link_extra_file]) @@ -164,7 +165,7 @@ int main () AC_MSG_ERROR([Please provide $static_link_extra_file next to the libv8.so, see README.md for details]) fi - LDFLAGS_libplatform="$static_link_dir/$static_link_extra_file" + LDFLAGS_libplatform="$LDFLAGS_libplatform $static_link_dir/$static_link_extra_file" done # modify flags for (possibly) succeeding V8 startup check From 90b2b2b0b1c011b4f43794d2a0e712debc35d3dd Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Thu, 24 Mar 2016 12:28:00 +0100 Subject: [PATCH 08/30] Bump version to 0.6.1 --- package.xml | 33 ++++++++++++++++++++++++--------- php_v8js_macros.h | 2 +- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/package.xml b/package.xml index 9b81a2b..da6b2f9 100644 --- a/package.xml +++ b/package.xml @@ -16,11 +16,11 @@ stesie@php.net yes - 2016-03-08 - + 2016-03-24 + - 0.6.0 - 0.6.0 + 0.6.1 + 0.6.1 stable @@ -28,7 +28,7 @@ The MIT License (MIT) -- Allow to adjust the considered "amount of external memory" by objects exported to V8 +- Fix configuration on MacOS platform @@ -189,15 +189,15 @@ - - + + - - + + @@ -530,5 +530,20 @@ - Allow to adjust the considered "amount of external memory" by objects exported to V8 + + + 0.6.1 + 0.6.1 + + + stable + stable + + 2016-03-24 + The MIT License (MIT) + +- Fix configuration on MacOS platform + + diff --git a/php_v8js_macros.h b/php_v8js_macros.h index 8969e90..50c0c79 100644 --- a/php_v8js_macros.h +++ b/php_v8js_macros.h @@ -53,7 +53,7 @@ extern "C" { #endif /* V8Js Version */ -#define PHP_V8JS_VERSION "0.6.0" +#define PHP_V8JS_VERSION "0.6.1" /* Hidden field name used to link JS wrappers with underlying PHP object */ #define PHPJS_OBJECT_KEY "phpjs::object" From d6394301b2c90ea3279a703e32beb552704ff298 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 25 Mar 2016 17:40:23 +0100 Subject: [PATCH 09/30] Pass back V8Object instances, don't re-wrap --- tests/object_passback_002.phpt | 20 ++++++++++++++++++++ v8js_object_export.cc | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/object_passback_002.phpt diff --git a/tests/object_passback_002.phpt b/tests/object_passback_002.phpt new file mode 100644 index 0000000..35b6917 --- /dev/null +++ b/tests/object_passback_002.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test V8::executeString() : Object passing JS > PHP > JS +--SKIPIF-- + +--FILE-- +theApiCall = function() use ($v8) { + return $v8->executeString('({ foo: 23 })'); +}; + +$v8->executeString('var_dump(PHP.theApiCall().constructor.name);'); + +?> +===EOF=== +--EXPECT-- +string(6) "Object" +===EOF=== diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 9562178..34ab680 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -988,7 +988,7 @@ v8::Handle v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate TSRML } /* Special case, passing back object originating from JS to JS */ - if (ce == php_ce_v8function) { + if (ce == php_ce_v8function || ce == php_ce_v8object) { v8js_v8object *c = (v8js_v8object *) zend_object_store_get_object(value TSRMLS_CC); if(isolate != c->ctx->isolate) { From d44592910d9e400317ba81ea280e1bc12c928ee5 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 25 Mar 2016 19:15:25 +0100 Subject: [PATCH 10/30] Retain object indentity on 'return $this' --- tests/return_this_basic.phpt | 50 ++++++++++++++++++++++++++++++++++++ v8js_object_export.cc | 3 +++ 2 files changed, 53 insertions(+) create mode 100644 tests/return_this_basic.phpt diff --git a/tests/return_this_basic.phpt b/tests/return_this_basic.phpt new file mode 100644 index 0000000..127d9ea --- /dev/null +++ b/tests/return_this_basic.phpt @@ -0,0 +1,50 @@ +--TEST-- +Test V8::executeString() : return $this (aka fluent setters) +--SKIPIF-- + +--FILE-- +foo = $value; + return $this; + } + + public function setBar($value) + { + $this->bar = $value; + return $this; + } +} + +$v8 = new V8Js(); +$v8->theFoo = new Foo(); + +$v8->executeString(<<theFoo); + +?> +===EOF=== +--EXPECTF-- +bool(true) +bool(true) +object(Foo)#%d (2) { + ["foo":"Foo":private]=> + int(23) + ["bar":"Foo":private]=> + int(42) +} +===EOF=== diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 34ab680..aea7438 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -156,6 +156,9 @@ failure: } else { v8js_terminate_execution(isolate); } + } else if (retval_ptr == value) { + // special case: "return $this" + return_value = info.Holder(); } else if (retval_ptr != NULL) { return_value = zval_to_v8js(retval_ptr, isolate TSRMLS_CC); } From 93b1118fe842a1a06e2dbc42b02515baf28a8c97 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 25 Mar 2016 22:15:05 +0100 Subject: [PATCH 11/30] Retain object identity on JS-side 'return this' --- tests/return_this_001.phpt | 44 ++++++++++++++++++++++++++++++++++++++ v8js_v8object_class.cc | 12 +++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/return_this_001.phpt diff --git a/tests/return_this_001.phpt b/tests/return_this_001.phpt new file mode 100644 index 0000000..93ff987 --- /dev/null +++ b/tests/return_this_001.phpt @@ -0,0 +1,44 @@ +--TEST-- +Test V8::executeString() : return this (aka fluent setters, JS-side) +--SKIPIF-- + +--FILE-- +executeString($js); + +$ret = $bar->setFoo(23)->setBar(42); +var_dump($bar === $ret); + +$v8->executeString('var_dump(theBar);'); + +?> +===EOF=== +--EXPECTF-- +bool(true) +object(Bar)#%d (2) { + ["foo"] => + int(23) + ["bar"] => + int(42) +} +===EOF=== diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index 20f01dc..8f5a126 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -297,7 +297,7 @@ static int v8js_v8object_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) zend_get_parameters_array_ex(argc, argv); } - std::function< v8::Local(v8::Isolate *) > v8_call = [obj, method, argc, argv TSRMLS_CC](v8::Isolate *isolate) { + std::function< v8::Local(v8::Isolate *) > v8_call = [obj, method, argc, argv, object, &return_value TSRMLS_CC](v8::Isolate *isolate) { int i = 0; v8::Local method_name = V8JS_SYML(method, strlen(method)); @@ -328,7 +328,15 @@ static int v8js_v8object_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) jsArgv[i] = v8::Local::New(isolate, zval_to_v8js(*argv[i], isolate TSRMLS_CC)); } - return cb->Call(thisObj, argc, jsArgv); + v8::Local result = cb->Call(thisObj, argc, jsArgv); + + if (obj->std.ce == php_ce_v8object && result->StrictEquals(thisObj)) { + /* JS code did "return this", retain object identity */ + RETVAL_ZVAL(object, 1, 0); + result.Clear(); + } + + return result; }; v8js_v8_call(obj->ctx, &return_value, obj->flags, obj->ctx->time_limit, obj->ctx->memory_limit, v8_call TSRMLS_CC); From 5595c3bbd7b6738a7dfc6d5e86d9ed99905c5209 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 25 Mar 2016 22:55:11 +0100 Subject: [PATCH 12/30] Fix compilation with PHP 5.5 --- v8js_v8object_class.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index 8f5a126..dd90662 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -332,7 +332,8 @@ static int v8js_v8object_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) if (obj->std.ce == php_ce_v8object && result->StrictEquals(thisObj)) { /* JS code did "return this", retain object identity */ - RETVAL_ZVAL(object, 1, 0); + ZVAL_COPY_VALUE(return_value, object); + zval_copy_ctor(return_value); result.Clear(); } From da89fa257b26cef7395ad789d2e792fce7f849bd Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 25 Mar 2016 23:25:23 +0100 Subject: [PATCH 13/30] Bump version to 0.6.2 --- package.xml | 38 ++++++++++++++++++++++++++++++-------- php_v8js_macros.h | 2 +- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/package.xml b/package.xml index da6b2f9..e39856c 100644 --- a/package.xml +++ b/package.xml @@ -16,11 +16,11 @@ stesie@php.net yes - 2016-03-24 - + 2016-03-25 + - 0.6.1 - 0.6.1 + 0.6.2 + 0.6.2 stable @@ -28,7 +28,9 @@ The MIT License (MIT) -- Fix configuration on MacOS platform +- Pass back V8Object instances, don't re-wrap +- Retain object identity on 'return $this' +- Retain object identity on JS-side 'return this' @@ -149,6 +151,7 @@ + @@ -168,6 +171,8 @@ + + @@ -196,7 +201,7 @@ - + @@ -214,13 +219,13 @@ - + - + @@ -545,5 +550,22 @@ - Fix configuration on MacOS platform + + + 0.6.2 + 0.6.2 + + + stable + stable + + 2016-03-25 + The MIT License (MIT) + +- Pass back V8Object instances, don't re-wrap +- Retain object identity on 'return $this' +- Retain object identity on JS-side 'return this' + + diff --git a/php_v8js_macros.h b/php_v8js_macros.h index 50c0c79..a965651 100644 --- a/php_v8js_macros.h +++ b/php_v8js_macros.h @@ -53,7 +53,7 @@ extern "C" { #endif /* V8Js Version */ -#define PHP_V8JS_VERSION "0.6.1" +#define PHP_V8JS_VERSION "0.6.2" /* Hidden field name used to link JS wrappers with underlying PHP object */ #define PHPJS_OBJECT_KEY "phpjs::object" From 2b4d41abb1db38fb2d148199b12e3950edc49bab Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 25 Mar 2016 23:48:26 +0100 Subject: [PATCH 14/30] Remove old-age test.php & samples files These date back to the initial checkin and mostly haven't been updated ever since. Besides the provided code samples aren't really suitable as a getting started guide. --- Makefile.frag | 11 - TODO | 6 - js/json-template.js | 839 ------------------------------------ js/jstparser.js | 339 --------------- package.xml | 18 +- samples/dlopen.supp | 15 - samples/test_call.php | 75 ---- samples/test_callback.php | 32 -- samples/test_closure.php | 11 - samples/test_crash.php | 5 - samples/test_date.php | 9 - samples/test_dumper.php | 59 --- samples/test_exception.php | 26 -- samples/test_exception2.php | 34 -- samples/test_extend.php | 23 - samples/test_extension.php | 9 - samples/test_method.php | 48 --- test.php | 173 -------- 18 files changed, 1 insertion(+), 1731 deletions(-) delete mode 100644 TODO delete mode 100644 js/json-template.js delete mode 100644 js/jstparser.js delete mode 100644 samples/dlopen.supp delete mode 100644 samples/test_call.php delete mode 100644 samples/test_callback.php delete mode 100644 samples/test_closure.php delete mode 100644 samples/test_crash.php delete mode 100644 samples/test_date.php delete mode 100644 samples/test_dumper.php delete mode 100644 samples/test_exception.php delete mode 100644 samples/test_exception2.php delete mode 100644 samples/test_extend.php delete mode 100644 samples/test_extension.php delete mode 100644 samples/test_method.php delete mode 100644 test.php diff --git a/Makefile.frag b/Makefile.frag index 93abcdc..873fc0f 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -7,14 +7,3 @@ endif ifneq (,$(realpath $(EXTENSION_DIR)/pthreads.so)) PHP_TEST_SHARED_EXTENSIONS+=-d extension=$(EXTENSION_DIR)/pthreads.so endif - -testv8: all - $(PHP_EXECUTABLE) -n -d extension_dir=./modules -d extension=v8js.so test.php - -debugv8: all - gdb --arg $(PHP_EXECUTABLE) -n -d extension_dir=./modules -d extension=v8js.so test.php - -valgrindv8: all - USE_ZEND_ALLOC=0 valgrind --leak-check=full --show-reachable=yes --track-origins=yes $(PHP_EXECUTABLE) -n -d extension_dir=./modules -d extension=v8js.so test.php 2> valgrind.dump - - diff --git a/TODO b/TODO deleted file mode 100644 index 9001c1f..0000000 --- a/TODO +++ /dev/null @@ -1,6 +0,0 @@ -- Feature: Extension registering from php.ini -- Feature: Thread safety -- Missing: Indexed property handlers -- Missing: static properties of PHP objects (on instance.constructor?) -- Bug: exception propagation fails when property getter is set -- Bug: method_exists() leaks when used with V8 objects diff --git a/js/json-template.js b/js/json-template.js deleted file mode 100644 index f9af696..0000000 --- a/js/json-template.js +++ /dev/null @@ -1,839 +0,0 @@ -// Copyright (C) 2009 Andy Chu -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// $Id$ - -// -// JavaScript implementation of json-template. -// - -// This is predefined in tests, shouldn't be defined anywhere else. TODO: Do -// something nicer. -var log = log || function() {}; -var repr = repr || function() {}; - - -// The "module" exported by this script is called "jsontemplate": - -var jsontemplate = function() { - - -// Regex escaping for metacharacters -function EscapeMeta(meta) { - return meta.replace(/([\{\}\(\)\[\]\|\^\$\-\+\?])/g, '\\$1'); -} - -var token_re_cache = {}; - -function _MakeTokenRegex(meta_left, meta_right) { - var key = meta_left + meta_right; - var regex = token_re_cache[key]; - if (regex === undefined) { - var str = '(' + EscapeMeta(meta_left) + '.*?' + EscapeMeta(meta_right) + - '\n?)'; - regex = new RegExp(str, 'g'); - } - return regex; -} - -// -// Formatters -// - -function HtmlEscape(s) { - return s.replace(/&/g,'&'). - replace(/>/g,'>'). - replace(//g,'>'). - replace(/ 1) ? p : s; -} - -function _Cycle(value, unused_context, args) { - // Cycle between various values on consecutive integers. - // @index starts from 1, so use 1-based indexing. - return args[(value - 1) % args.length]; -} - -var DEFAULT_FORMATTERS = { - 'html': HtmlEscape, - 'htmltag': HtmlTagEscape, - 'html-attr-value': HtmlTagEscape, - 'str': ToString, - 'raw': function(x) { return x; }, - 'AbsUrl': function(value, context) { - // TODO: Normalize leading/trailing slashes - return context.get('base-url') + '/' + value; - } -}; - -var DEFAULT_PREDICATES = { - 'singular?': function(x) { return x == 1; }, - 'plural?': function(x) { return x > 1; }, - 'Debug?': function(unused, context) { - try { - return context.get('debug'); - } catch(err) { - if (err.name == 'UndefinedVariable') { - return false; - } else { - throw err; - } - } - } -}; - -var FunctionRegistry = function() { - return { - lookup: function(user_str) { - return [null, null]; - } - }; -}; - -var SimpleRegistry = function(obj) { - return { - lookup: function(user_str) { - var func = obj[user_str] || null; - return [func, null]; - } - }; -}; - -var CallableRegistry = function(callable) { - return { - lookup: function(user_str) { - var func = callable(user_str); - return [func, null]; - } - }; -}; - -// Default formatters which can't be expressed in DEFAULT_FORMATTERS -var PrefixRegistry = function(functions) { - return { - lookup: function(user_str) { - for (var i = 0; i < functions.length; i++) { - var name = functions[i].name, func = functions[i].func; - if (user_str.slice(0, name.length) == name) { - // Delimiter is usually a space, but could be something else - var args; - var splitchar = user_str.charAt(name.length); - if (splitchar === '') { - args = []; // No arguments - } else { - args = user_str.split(splitchar).slice(1); - } - return [func, args]; - } - } - return [null, null]; // No formatter - } - }; -}; - -var ChainedRegistry = function(registries) { - return { - lookup: function(user_str) { - for (var i=0; i 1) { - for (var i=1; i 0) { - // TODO: check that items is an array; apparently this is hard in JavaScript - //if type(items) is not list: - // raise EvaluationError('Expected a list; got %s' % type(items)) - - // Execute the statements in the block for every item in the list. - // Execute the alternate block on every iteration except the last. Each - // item could be an atom (string, integer, etc.) or a dictionary. - - var last_index = items.length - 1; - var statements = block.Statements(); - var alt_statements = block.Statements('alternate'); - - for (var i=0; context.next() !== undefined; i++) { - _Execute(statements, context, callback); - if (i != last_index) { - _Execute(alt_statements, context, callback); - } - } - } else { - _Execute(block.Statements('or'), context, callback); - } - - context.Pop(); -} - - -var _SECTION_RE = /(repeated)?\s*(section)\s+(\S+)?/; -var _OR_RE = /or(?:\s+(.+))?/; -var _IF_RE = /if(?:\s+(.+))?/; - - -// Turn a object literal, function, or Registry into a Registry -function MakeRegistry(obj) { - if (!obj) { - // if null/undefined, use a totally empty FunctionRegistry - return new FunctionRegistry(); - } else if (typeof obj === 'function') { - return new CallableRegistry(obj); - } else if (obj.lookup !== undefined) { - // TODO: Is this a good pattern? There is a namespace conflict where get - // could be either a formatter or a method on a FunctionRegistry. - // instanceof might be more robust. - return obj; - } else if (typeof obj === 'object') { - return new SimpleRegistry(obj); - } -} - -// TODO: The compile function could be in a different module, in case we want to -// compile on the server side. -function _Compile(template_str, options) { - var more_formatters = MakeRegistry(options.more_formatters); - - // default formatters with arguments - var default_formatters = PrefixRegistry([ - {name: 'pluralize', func: _Pluralize}, - {name: 'cycle', func: _Cycle} - ]); - var all_formatters = new ChainedRegistry([ - more_formatters, - SimpleRegistry(DEFAULT_FORMATTERS), - default_formatters - ]); - - var more_predicates = MakeRegistry(options.more_predicates); - - // TODO: Add defaults - var all_predicates = new ChainedRegistry([ - more_predicates, SimpleRegistry(DEFAULT_PREDICATES) - ]); - - // We want to allow an explicit null value for default_formatter, which means - // that an error is raised if no formatter is specified. - var default_formatter; - if (options.default_formatter === undefined) { - default_formatter = 'str'; - } else { - default_formatter = options.default_formatter; - } - - function GetFormatter(format_str) { - var pair = all_formatters.lookup(format_str); - if (!pair[0]) { - throw { - name: 'BadFormatter', - message: format_str + ' is not a valid formatter' - }; - } - return pair; - } - - function GetPredicate(pred_str) { - var pair = all_predicates.lookup(pred_str); - if (!pair[0]) { - throw { - name: 'BadPredicate', - message: pred_str + ' is not a valid predicate' - }; - } - return pair; - } - - var format_char = options.format_char || '|'; - if (format_char != ':' && format_char != '|') { - throw { - name: 'ConfigurationError', - message: 'Only format characters : and | are accepted' - }; - } - - var meta = options.meta || '{}'; - var n = meta.length; - if (n % 2 == 1) { - throw { - name: 'ConfigurationError', - message: meta + ' has an odd number of metacharacters' - }; - } - var meta_left = meta.substring(0, n/2); - var meta_right = meta.substring(n/2, n); - - var token_re = _MakeTokenRegex(meta_left, meta_right); - var current_block = _Section({}); - var stack = [current_block]; - - var strip_num = meta_left.length; // assume they're the same length - - var token_match; - var last_index = 0; - - while (true) { - token_match = token_re.exec(template_str); - if (token_match === null) { - break; - } else { - var token = token_match[0]; - } - - // Add the previous literal to the program - if (token_match.index > last_index) { - var tok = template_str.slice(last_index, token_match.index); - current_block.Append(tok); - } - last_index = token_re.lastIndex; - - var had_newline = false; - if (token.slice(-1) == '\n') { - token = token.slice(null, -1); - had_newline = true; - } - - token = token.slice(strip_num, -strip_num); - - if (token.charAt(0) == '#') { - continue; // comment - } - - if (token.charAt(0) == '.') { // Keyword - token = token.substring(1, token.length); - - var literal = { - 'meta-left': meta_left, - 'meta-right': meta_right, - 'space': ' ', - 'tab': '\t', - 'newline': '\n' - }[token]; - - if (literal !== undefined) { - current_block.Append(literal); - continue; - } - - var new_block, func; - - var section_match = token.match(_SECTION_RE); - if (section_match) { - var repeated = section_match[1]; - var section_name = section_match[3]; - - if (repeated) { - func = _DoRepeatedSection; - new_block = _RepeatedSection({section_name: section_name}); - } else { - func = _DoSection; - new_block = _Section({section_name: section_name}); - } - current_block.Append([func, new_block]); - stack.push(new_block); - current_block = new_block; - continue; - } - - var pred_str, pred; - - // Check {.or pred?} before {.pred?} - var or_match = token.match(_OR_RE); - if (or_match) { - pred_str = or_match[1]; - pred = pred_str ? GetPredicate(pred_str) : null; - current_block.NewOrClause(pred); - continue; - } - - // Match either {.pred?} or {.if pred?} - var matched = false; - - var if_match = token.match(_IF_RE); - if (if_match) { - pred_str = if_match[1]; - matched = true; - } else if (token.charAt(token.length-1) == '?') { - pred_str = token; - matched = true; - } - if (matched) { - pred = pred_str ? GetPredicate(pred_str) : null; - new_block = _PredicateSection(); - new_block.NewOrClause(pred); - current_block.Append([_DoPredicates, new_block]); - stack.push(new_block); - current_block = new_block; - continue; - } - - if (token == 'alternates with') { - current_block.AlternatesWith(); - continue; - } - - if (token == 'end') { - // End the block - stack.pop(); - if (stack.length > 0) { - current_block = stack[stack.length-1]; - } else { - throw { - name: 'TemplateSyntaxError', - message: 'Got too many {end} statements' - }; - } - continue; - } - } - - // A variable substitution - var parts = token.split(format_char); - var formatters; - var name; - if (parts.length == 1) { - if (default_formatter === null) { - throw { - name: 'MissingFormatter', - message: 'This template requires explicit formatters.' - }; - } - // If no formatter is specified, use the default. - formatters = [GetFormatter(default_formatter)]; - name = token; - } else { - formatters = []; - for (var j=1; j 0) { - return true; - } else { - return false; - } - }; - - for (i = str.length; i >= 0; i -= 1) { - this.characters.push(str.charAt(i)); - } - } - - function StringWriter() { - this.str = ""; - this.write = function write(s) { - this.str += s; - }; - this.toString = function toString() { - return this.str; - }; - } - - function parseScriptlet(stack) { - var fragment = new StringWriter(); - var c; // character - - while (stack.hasMore()) { - if (stack.peek() == '%') { //possible end delimiter - c = stack.pop(); - if (stack.peek() == '>') { //end delimiter - // pop > so that it is not available to main parse loop - stack.pop(); - if (stack.peek() == '\n') { - fragment.write(stack.pop()); - } - break; - } else { - fragment.write(c); - } - } else { - fragment.write(stack.pop()); - } - } - return fragment.toString(); - } - - function isOpeningDelimiter(c) { - if (c == "<" || c == "%lt;") { - return true; - } else { - return false; - } - } - - function isClosingDelimiter(c) { - if (c == ">" || c == "%gt;") { - return true; - } else { - return false; - } - } - - function appendExpressionFragment(writer, fragment, jstWriter) { - var i,j; - var c; - - // check to be sure quotes are on both ends of a string literal - if (fragment.startsWith("\"") && !fragment.endsWith("\"")) { - //some scriptlets end with \n, especially if the script ends the file - if (fragment.endsWith("\n") && fragment.charAt(fragment.length - 2) == '"') { - //we're ok... - } else { - throw { "message":"'" + fragment + "' is not properly quoted"}; - } - } - - if (!fragment.startsWith("\"") && fragment.endsWith("\"")) { - throw { "message":"'" + fragment + "' is not properly quoted"}; - } - - // print or println? - if (fragment.endsWith("\n")) { - writer.write(jstWriter + "ln("); - //strip the newline - fragment = fragment.substring(0, fragment.length - 1); - } else { - writer.write(jstWriter + "("); - } - - if (fragment.startsWith("\"") && fragment.endsWith("\"")) { - //strip the quotes - fragment = fragment.substring(1, fragment.length - 1); - writer.write("\""); - for (i = 0; i < fragment.length; i += 1) { - c = fragment.charAt(i); - if (c == '"') { - writer.write("\\"); - writer.write(c); - } - } - writer.write("\""); - } else { - for (j = 0; j < fragment.length; j += 1) { - writer.write(fragment.charAt(j)); - } - } - - writer.write(");"); - } - - function appendTextFragment(writer, fragment) { - var i; - var c; - - if (fragment.endsWith("\n")) { - writer.write("writeln(\""); - } else { - writer.write("write(\""); - } - - for (i = 0; i < fragment.length; i += 1) { - c = fragment.charAt(i); - if (c == '"') { - writer.write("\\"); - } - // we took care of the line break with print vs. println - if (c != '\n' && c != '\r') { - writer.write(c); - } - } - - writer.write("\");"); - } - - function parseExpression(stack) { - var fragment = new StringWriter(); - var c; - - while (stack.hasMore()) { - if (stack.peek() == '%') { //possible end delimiter - c = stack.pop(); - if (isClosingDelimiter(stack.peek())) { //end delimiter - //pop > so that it is not available to main parse loop - stack.pop(); - if (stack.peek() == '\n') { - fragment.write(stack.pop()); - } - break; - } else { - fragment.write("%"); - } - } else { - fragment.write(stack.pop()); - } - } - - return fragment.toString(); - } - - function parseText(stack) { - var fragment = new StringWriter(); - var c,d; - - while (stack.hasMore()) { - if (isOpeningDelimiter(stack.peek())) { //possible delimiter - c = stack.pop(); - if (stack.peek() == '%') { // delimiter! - // push c onto the stack to be used in main parse loop - stack.push(c); - break; - } else { - fragment.write(c); - } - } else { - d = stack.pop(); - fragment.write(d); - if (d == '\n') { //done with this fragment. println it. - break; - } - } - } - return fragment.toString(); - } - - function safeWrite(s) { - s = s.toString(); - s = s.replaceAll('&', '&'); - s = s.replaceAll('"', '"'); - s = s.replaceAll('<', '<'); - s = s.replaceAll('>', '>'); - html += s; - } - - function safeWriteln(s) { - safeWrite(s + "\n"); - } - - function write(s) { - html += s; - } - - function writeln(s) { - write(s + "\n"); - } - - that = { - // public methods: - // pre-compile a template for quicker rendering. save the return value and - // pass it to evaluate. - compile: function (src) { - var stack = new CharacterStack(src); - var writer = new StringWriter(); - - var c; - var fragment; - while (stack.hasMore()) { - if (isOpeningDelimiter(stack.peek())) { //possible delimiter - c = stack.pop(); - if (stack.peek() == '%') { //delimiter! - c = stack.pop(); - if (stack.peek() == "=") { - // expression, escape all html - stack.pop(); - fragment = parseExpression(stack); - appendExpressionFragment(writer, fragment, - "safeWrite"); - } else if (stack.peek() == "+") { - // expression, don't escape html - stack.pop(); - fragment = parseExpression(stack); - appendExpressionFragment(writer, fragment, - "write"); - } else { - fragment = parseScriptlet(stack); - writer.write(fragment); - } - } else { //not a delimiter - stack.push(c); - fragment = parseText(stack); - appendTextFragment(writer, fragment); - } - } else { - fragment = parseText(stack); - appendTextFragment(writer, fragment); - } - } - return writer.toString(); - }, - - // evaluate a pre-compiled script. recommended approach - evaluate: function (script, args) { - with(args) { - html = ""; - eval(script); - return html; - } - }, - - // if you're lazy, you can use this - evaluateSingleShot: function (src, args) { - return this.evaluate(this.compile(src), args); - } - }; - return that; -}(); diff --git a/package.xml b/package.xml index e39856c..63fa620 100644 --- a/package.xml +++ b/package.xml @@ -17,7 +17,7 @@ yes 2016-03-25 - + 0.6.2 0.6.2 @@ -34,20 +34,6 @@ - - - - - - - - - - - - - - @@ -206,8 +192,6 @@ - - diff --git a/samples/dlopen.supp b/samples/dlopen.supp deleted file mode 100644 index 5460ea6..0000000 --- a/samples/dlopen.supp +++ /dev/null @@ -1,15 +0,0 @@ -{ - Ignore dlopen bug #1. - Memcheck:Leak - ... - fun:_dl_open - ... -} - -{ - Ignore dlopen bug #2. - Memcheck:Leak - ... - fun:_dl_close - ... -} diff --git a/samples/test_call.php b/samples/test_call.php deleted file mode 100644 index 2df24b8..0000000 --- a/samples/test_call.php +++ /dev/null @@ -1,75 +0,0 @@ -bar; - } -} - -$blaa = new V8Js(); -$blaa->obj = new Foo; - -try { - echo "__invoke()\n"; - $blaa->executeString("var_dump(PHP.obj('arg1','arg2','arg3'));", "invoke_test1 #1.js"); - echo "------------\n"; - - echo " __invoke() with new\n"; - $blaa->executeString("myobj = new PHP.obj('arg1','arg2','arg3'); var_dump(myobj);", "invoke_test2 #2.js"); - echo "------------\n"; - - echo " __tostring()\n"; - $blaa->executeString('print(PHP.obj + "\n");', "tostring_test #3.js"); - echo "------------\n"; - - echo " __isset() not called with existing property\n"; - $blaa->executeString('if ("bar" in PHP.obj) print("bar exists\n");', "isset_test1 #4.js"); - echo "------------\n"; - - echo " __isset() with non-existing property\n"; - $blaa->executeString('if (!("foobar" in PHP.obj)) print("foobar does not exist\n"); else print("We called __isset and it said yes!\n");', "isset_test2 #5.js"); - echo "------------\n"; - - echo " __get() not called with existing property\n"; - $blaa->executeString('var_dump(PHP.obj.bar);', "get_test1 #6.js"); - echo "------------\n"; - - echo " __get() with non-existing property\n"; - $blaa->executeString('var_dump(PHP.obj.foo);', "get_test2 #7.js"); - echo "------------\n"; - - echo " __call()\n"; - $blaa->executeString('PHP.obj.foo(1,2,3);', "call_test1 #8.js"); - echo "------------\n"; - -} catch (V8JsScriptException $e) { - echo $e->getMessage(), "\n"; -} diff --git a/samples/test_callback.php b/samples/test_callback.php deleted file mode 100644 index 6309125..0000000 --- a/samples/test_callback.php +++ /dev/null @@ -1,32 +0,0 @@ -test = function ($params) { return (method_exists($params, 'cb1')) ? $params->cb1("hello") : false; }; -$ret = $a->executeString('PHP.test(function (foo) { return foo + " world"; });'); -var_dump(__LINE__, $ret); - -// Test is_a() -$a->test = function ($params) { return (is_a($params, 'V8Object')) ? $params->cb1("hello") : false; }; -$ret = $a->executeString('PHP.test({ "cb1" : function (foo) { return foo + " world"; } });'); -var_dump(__LINE__, $ret); - -// Test is_a() -$a->test = function ($params) { return (is_a($params, 'V8Function')) ? $params("hello") : false; }; -$ret = $a->executeString('PHP.test(function (foo) { return foo + " world"; });'); -var_dump(__LINE__, $ret); - -// Should not work with object -$a->test = function ($params) { return (is_a($params, 'Closure')) ? $params("hello") : false; }; -$ret = $a->executeString('PHP.test({ "cb1" : function (foo) { return foo + " world"; } });'); -var_dump(__LINE__, $ret); - -$a->test = function ($params) { var_dump($params); return $params->cb1("hello"); }; -$ret = $a->executeString('PHP.test({ "cb1" : function (foo) { return foo + " world"; } });'); -var_dump(__LINE__, $ret); - -// FIX! method_exists() Leaks! -$a->test = function ($params) { var_dump($params, method_exists($params, 'cb1'), $params->cb1); }; -$ret = $a->executeString('PHP.test({ "cb1" : function (foo) { return foo + " world"; } });'); - diff --git a/samples/test_closure.php b/samples/test_closure.php deleted file mode 100644 index 89c89a2..0000000 --- a/samples/test_closure.php +++ /dev/null @@ -1,11 +0,0 @@ -func = function ($a) { echo "Closure..\n"; }; - -try { - $a->executeString("print(PHP.func); PHP.func(1);", "closure_test.js"); - $a->executeString("print(PHP.func); PHP.func(1);", "closure_test.js"); -} catch (V8JsScriptException $e) { - echo $e->getMessage(), "\n"; -} diff --git a/samples/test_crash.php b/samples/test_crash.php deleted file mode 100644 index aa1b9ef..0000000 --- a/samples/test_crash.php +++ /dev/null @@ -1,5 +0,0 @@ -executeString('Jst.write = function(s) { html += "EI TOIMI"; };' ."\n" .' Jst.evaluate("lol testi <%= 1 %>", {});')); -} diff --git a/samples/test_date.php b/samples/test_date.php deleted file mode 100644 index 995ca31..0000000 --- a/samples/test_date.php +++ /dev/null @@ -1,9 +0,0 @@ -executeString("date = new Date('September 8, 1975 09:00:00'); print(date + '\\n'); date;", "test.js")); -} catch (V8JsScriptException $e) { - echo $e->getMessage(), "\n"; -} diff --git a/samples/test_dumper.php b/samples/test_dumper.php deleted file mode 100644 index d1365c1..0000000 --- a/samples/test_dumper.php +++ /dev/null @@ -1,59 +0,0 @@ - 42, "foo" => "bar"); - function __set($name, $value) - { - echo "I'm setter!\n"; - var_dump($name, $value); - } - function __get($name) - { - echo "I'm getter!\n"; - var_dump($name); - } - function __call($name, $args) - { - echo "I'm caller!\n"; - var_dump($name, $args); - } -} - -$a = new V8Js(); -$obj = new Foo; -$a->arr = array("foobar" => $obj); - -$JS = <<< 'EOF' - var example = new Object; - example.foo = function () { - print("this is foo"); - } - example.bar = function () { - print("this is bar"); - } - example.__noSuchMethod__ = function (id, args) { - print("tried to handle unknown method " + id); - if (args.length != 0) - print("it had arguments: " + args); - } - example.foo(); // alerts "this is foo" - example.bar(); // alerts "this is bar" - example.grill(); // alerts "tried to handle unknown method grill" - example.ding("dong"); // alerts "tried to handle unknown method ding" -EOF; - -try { - $a->executeString("var myarr = new Array(); myarr[0] = 'foo'; myarr[1] = 'bar'; var_dump(myarr); var_dump(new Date('September 8, 1975 09:00:00'))", "call_test1.js"); - $a->executeString("var_dump(PHP.arr.foobar.bar);", "call_test2.js"); - $a->executeString("var_dump(PHP.arr.foobar.bar[0]);", "call_test3.js"); - $a->executeString("var_dump(var_dump(PHP.arr));", "call_test4.js"); - $a->executeString("var patt1=/[^a-h]/g; var_dump(patt1);", "call_test5.js"); - $a->executeString("var_dump(Math.PI, Infinity, null, undefined);", "call_test6.js"); -// $a->executeString($JS); -} catch (V8JsScriptException $e) { - echo $e->getMessage(), "\n"; -} diff --git a/samples/test_exception.php b/samples/test_exception.php deleted file mode 100644 index c7742eb..0000000 --- a/samples/test_exception.php +++ /dev/null @@ -1,26 +0,0 @@ -v8 = new V8Js(); - $this->v8->foo = $this; - var_dump($this->v8->executeString('throw 1; PHP.foo.bar();', 'trycatch1')); - var_dump($this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print("catched!\n"); }', 'trycatch2')); - } - - public function bar() - { - echo "To Bar!\n"; - var_dump($this->v8->executeString('throw new Error();', 'throw')); - } - } - - try { - $foo = new Foo(); - } catch (V8JsScriptException $e) { - echo "PHP Exception: ", $e->getMessage(), "\n"; //var_dump($e); - } - -} diff --git a/samples/test_exception2.php b/samples/test_exception2.php deleted file mode 100644 index 7870091..0000000 --- a/samples/test_exception2.php +++ /dev/null @@ -1,34 +0,0 @@ -v8 = new V8Js(null, array(), false); - $this->v8->foo = $this; -// $this->v8->executeString('asdasda< / sd', 'trycatch0'); -// $this->v8->executeString('blahnothere', 'trycatch1'); -// $this->v8->executeString('throw new SyntaxError();', 'throw'); -// $this->v8->executeString('function foo() {throw new SyntaxError();}', 'trycatch2'); -// $this->v8->executeString('try { foo(); } catch (e) { print(e + " catched by pure JS!\n"); }', 'trycatch3'); -// $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " catched via PHP callback!\n"); }', 'trycatch4'); -// $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print("catched!\n"); }', 'trycatch5'); -// $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print("catched!\n"); }', 'trycatch5'); - var_dump($this->v8->getPendingException()); - } - - public function bar() - { -// $this->v8->executeString('asdasda< / sd', 'trycatch0'); -// $this->v8->executeString('blahnothere', 'trycatch1'); - $this->v8->executeString('throw new Error();', 'throw'); - } - } - - try { - $foo = new Foo(); - } catch (V8JsScriptException $e) { - echo "PHP Exception: ", $e->getMessage(), "\n"; - } - -} diff --git a/samples/test_extend.php b/samples/test_extend.php deleted file mode 100644 index e18065b..0000000 --- a/samples/test_extend.php +++ /dev/null @@ -1,23 +0,0 @@ -executeString("PHP.mytest(PHP.foo, PHP.my_private, PHP.my_protected);", "test7.js"); -} catch (V8JsScriptException $e) { - var_dump($e); -} diff --git a/samples/test_extension.php b/samples/test_extension.php deleted file mode 100644 index 0a557c0..0000000 --- a/samples/test_extension.php +++ /dev/null @@ -1,9 +0,0 @@ -myobj = new Testing(); - -$a->executeString("PHP.myobj.mytest('arg1', 'arg2');", "test1.js"); -$a->executeString("PHP.myobj.mytest(true, false, 1234567890);", "test2.js"); -$a->executeString("PHP.myobj.mytest(3.14, 42, null);", "test3.js"); - -// Invalid parameters -try { - $a->executeString("PHP.myobj.mytest();", "test4.js"); -} catch (V8JsScriptException $e) { - echo $e->getMessage(), "\n"; -} - -try { - $a->executeString("PHP.myobj.mytest('arg1', 'arg2', 'arg3', 'extra_arg');", "test5.js"); -} catch (V8JsScriptException $e) { - echo $e->getMessage(), "\n"; -} - -// Array / Object -try { -// date_default_timezone_set("UTC"); - $a->executeString("date = new Date('September 8, 1975 09:00:00'); PHP.print(date); PHP.myobj.mytest(date, PHP.myobj, new Array(1,2,3));", "test6.js"); -} catch (V8JsScriptException $e) { - var_dump($e); -} - -try { - $a->executeString("PHP.myobj.mytest(PHP.myobj, new Array(1,2,3), new Array('foo', 'bar', PHP.myobj));", "test7.js"); -} catch (V8JsScriptException $e) { - var_dump($e); -} diff --git a/test.php b/test.php deleted file mode 100644 index 93f6d90..0000000 --- a/test.php +++ /dev/null @@ -1,173 +0,0 @@ -func = function ($a) { return var_export(func_get_args(), TRUE); }; -$v8->executeString("PHP.func();", "arg_test1.js"); -exit; -*/ - -var_dump(V8Js::registerExtension('myparser.js', 'function foo() { print("foobar!\n"}', array('jstparser.js', 'json-template.js'), false)); -var_dump(V8Js::registerExtension('myparser.js', 'function foo() { print("foobar!\n"}', array('jstparser.js', 'json-template.js'), false)); -var_dump(V8Js::registerExtension('jstparser.js', file_get_contents('js/jstparser.js'), array(), false)); -//V8Js::registerExtension('json-template.js', file_get_contents('js/json-template.js'), array(), false); - -var_dump(V8JS::getExtensions()); - -$a = new V8Js('myobj', array(), array('jstparser.js')); - -$jstparser = <<< 'EOT' -var template = 'Gold & Hot Rod Red, as seen in the new Iron Man trailer!' + "\n" + -'' + "\n" + -' <% for(var i = 0; i < 10; i++){ %> ' + "\n" + -' ' + "\n" + -' ' + "\n" + -' ' + "\n" + -' <% } %>' + "\n" + -'
' + "\n" + -' Hi, <%=name%>! i is <%= i %>' + "\n" + -'
' + "\n" + -'Note that name is HTML escaped by default. Here it is without escaping:'+ -'<%+ name %>'; -Jst.evaluateSingleShot(template, {"name":"foobar"}); -EOT; - -echo($a->executeString($jstparser, "ext_test1.js")), "\n"; - -$a->_SERVER = $_SERVER; -$a->func = function ($a) { echo "Closure..\n"; }; - -$a->executeString("print(myobj._SERVER['HOSTNAME']);", "test1.js"); -$a->executeString("print(myobj.func); myobj.func(1);", "closure_test.js"); - -$JS = <<<'EOT' -function dump(a) -{ - for (var i in a) { - var val = a[i]; - print(i + ' => ' + val + "\n"); - } -} -function foo() -{ - var bar = 'bar'; - var foo = 'foo'; - return foo + bar; -} -function test() -{ - var a = 'PHP version: ' + PHP.phpver; - phpver = 'changed in JS!'; - return a; -} -function loop() -{ - var foo = 'foo'; - while(true) - { - foo + 'bar'; - } -} -function output() -{ - while(true) - { - print("output:foo\n"); - sleep(5); - exit(); - } -}; -function simplearray() -{ - print(myarray.a + "\n"); - print(myarray.b + "\n"); - print(myarray.c + "\n"); - print(myarray.d + "\n"); -} -function bigarray() -{ - print(PHP.$_SERVER['HOSTNAME'] + "\n"); - print(PHP.$_SERVER.argv + "\n"); -} -EOT; - -$jsontemplate = <<< EOT -var t = jsontemplate.Template("{# This is a comment and will be removed from the output.}{.section songs}

Songs in '{playlist-name}'

{.repeated section @}{.end}
Play{title}{artist}
{.or}

(No page content matches)

{.end}"); -t.expand({ -"url-base": "http://example.com/music/", -"playlist-name": "Epic Playlist", -"songs": [ -{ -"url": "1.mp3", -"artist": "Grayceon", -"title": "Sounds Like Thunder" -}, -{ -"url": "2.mp3", -"artist": "Thou", -"title": "Their Hooves Carve Craters in the Earth" -}]}); -EOT; - -class tester -{ - public $foo = 'bar'; - private $my_private = 'arf'; - protected $my_protected = 'argh'; - - function mytest() { echo 'Here be monsters..', "\n"; } -} - -$a = new V8Js(); -$a->obj = new tester(); -$a->phpver = phpversion(); -$a->argv = $_SERVER['argv']; -$a->integer = 1; -$a->float = 3.14; -$a->{'$'._SERVER} = $_SERVER; -$a->GLOBALS = $GLOBALS; -$a->myarray = array( - 'a' => 'Array value for key A', - 'b' => 'Array value for key B', - 'c' => 'Array value for key C', - 'd' => 'Array value for key D', -); -$a->arr = array("first", "second", "third"); - -$a->executeString($JS, "test1.js"); -$a->executeString("bigarray()", "test1.js"); - -try { - echo($a->executeString($jstparser, "test2.js")), "\n"; - var_dump($a->executeString($jsontemplate, "test1.js")); -} catch (V8JsScriptException $e) { - echo $e->getMessage(); -} - -// Test for context handling - -$a->executeString($JS, "test1.js"); -$a->executeString("bigarray();"); - -echo '$a->obj: ', "\n"; $a->executeString("dump(PHP.obj);"); -echo '$a->arr: ', "\n"; $a->executeString("dump(PHP.arr);"); -echo '$a->argv: ', "\n"; $a->executeString("dump(PHP.argv);"); - -var_dump($a->argv); -var_dump($a->executeString("test();")); -var_dump($a->executeString("test();")); - -$b = new V8Js(); - -var_dump($a->phpver, $a->executeString("test();")); - -$b->executeString($JS, "test2.js"); -var_dump($b->executeString("test();")); -var_dump($b->executeString("print('foobar\\n');")); - -// Exception methods - -try { - $b->executeString("foobar; foo();", "extest.js"); -} catch (V8JsScriptException $e) { - var_dump($e, $e->getJsFileName(), $e->getJsLineNumber(), $e->getJsSourceLine(), $e->getJsTrace()); -} From 4faab8842cab50b18f87b4a8381a476646b8e680 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 26 Mar 2016 00:37:53 +0100 Subject: [PATCH 15/30] Re-check memory limit, refs #217 --- v8js_v8.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/v8js_v8.cc b/v8js_v8.cc index 8091429..0b4b766 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -204,6 +204,16 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value, return; } + if (memory_limit && !c->memory_limit_hit) { + // Re-check memory limit (very short executions might never be hit by timer thread) + v8::HeapStatistics hs; + isolate->GetHeapStatistics(&hs); + + if (hs.used_heap_size() > memory_limit) { + c->memory_limit_hit = true; + } + } + if (c->memory_limit_hit) { // Execution has been terminated due to memory limit sprintf(exception_string, "Script memory limit of %lu bytes exceeded", memory_limit); From b2eb89e49e0ca30cfe561633f361dae652cca55e Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 26 Mar 2016 00:53:52 +0100 Subject: [PATCH 16/30] send LowMemoryNotification before imposing memory limit, fixes #217 --- v8js_timer.cc | 49 ++++++++++++++++++++++++++++++++----------------- v8js_v8.cc | 7 ++++++- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/v8js_timer.cc b/v8js_timer.cc index d556716..36c9f81 100644 --- a/v8js_timer.cc +++ b/v8js_timer.cc @@ -40,27 +40,42 @@ static void v8js_timer_interrupt_handler(v8::Isolate *isolate, void *data) { /* v8::Locker locker(isolate); v8::HeapStatistics hs; - isolate->GetHeapStatistics(&hs); + bool send_notification, has_sent_notification; - V8JSG(timer_mutex).lock(); - - for (std::deque< v8js_timer_ctx* >::iterator it = V8JSG(timer_stack).begin(); - it != V8JSG(timer_stack).end(); it ++) { - v8js_timer_ctx *timer_ctx = *it; - v8js_ctx *c = timer_ctx->ctx; - - if(c->isolate != isolate || timer_ctx->killed) { - continue; + do { + if (send_notification) { + isolate->LowMemoryNotification(); + has_sent_notification = true; } - if (timer_ctx->memory_limit > 0 && hs.used_heap_size() > timer_ctx->memory_limit) { - timer_ctx->killed = true; - v8::V8::TerminateExecution(c->isolate); - c->memory_limit_hit = true; - } - } + isolate->GetHeapStatistics(&hs); - V8JSG(timer_mutex).unlock(); + V8JSG(timer_mutex).lock(); + + for (std::deque< v8js_timer_ctx* >::iterator it = V8JSG(timer_stack).begin(); + it != V8JSG(timer_stack).end(); it ++) { + v8js_timer_ctx *timer_ctx = *it; + v8js_ctx *c = timer_ctx->ctx; + + if(c->isolate != isolate || timer_ctx->killed) { + continue; + } + + if (timer_ctx->memory_limit > 0 && hs.used_heap_size() > timer_ctx->memory_limit) { + if (has_sent_notification) { + timer_ctx->killed = true; + v8::V8::TerminateExecution(c->isolate); + c->memory_limit_hit = true; + } else { + // force garbage collection, then check again + send_notification = true; + break; + } + } + } + + V8JSG(timer_mutex).unlock(); + } while(send_notification != has_sent_notification); } /* }}} */ diff --git a/v8js_v8.cc b/v8js_v8.cc index 0b4b766..1ab13ab 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -210,7 +210,12 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value, isolate->GetHeapStatistics(&hs); if (hs.used_heap_size() > memory_limit) { - c->memory_limit_hit = true; + isolate->LowMemoryNotification(); + isolate->GetHeapStatistics(&hs); + + if (hs.used_heap_size() > memory_limit) { + c->memory_limit_hit = true; + } } } From 3d5f16389919d06109aa62af58aced75ea6d428e Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 26 Mar 2016 11:47:58 +0100 Subject: [PATCH 17/30] skip time/memory limit tests on SKIP_SLOW_TESTS --- tests/memory_limit.phpt | 8 +++++++- tests/set_memory_limit_001.phpt | 8 +++++++- tests/set_memory_limit_003.phpt | 8 +++++++- tests/set_memory_limit_basic.phpt | 8 +++++++- tests/set_time_limit_001.phpt | 8 +++++++- tests/set_time_limit_002.phpt | 8 +++++++- tests/set_time_limit_003.phpt | 8 +++++++- tests/set_time_limit_004.phpt | 8 +++++++- tests/set_time_limit_basic.phpt | 8 +++++++- tests/time_limit.phpt | 8 +++++++- 10 files changed, 70 insertions(+), 10 deletions(-) diff --git a/tests/memory_limit.phpt b/tests/memory_limit.phpt index 20e2b31..33621ad 100644 --- a/tests/memory_limit.phpt +++ b/tests/memory_limit.phpt @@ -1,7 +1,13 @@ --TEST-- Test V8::executeString() : Memory limit --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- Date: Sat, 26 Mar 2016 12:10:32 +0100 Subject: [PATCH 18/30] fix: initialize variables --- v8js_timer.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/v8js_timer.cc b/v8js_timer.cc index 36c9f81..a3ae679 100644 --- a/v8js_timer.cc +++ b/v8js_timer.cc @@ -40,7 +40,8 @@ static void v8js_timer_interrupt_handler(v8::Isolate *isolate, void *data) { /* v8::Locker locker(isolate); v8::HeapStatistics hs; - bool send_notification, has_sent_notification; + bool send_notification = false; + bool has_sent_notification = false; do { if (send_notification) { From c804b16e4c6b423d23d51db222df1c7f8c466b9f Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 26 Mar 2016 12:11:11 +0100 Subject: [PATCH 19/30] fix compiler warnings --- v8js_class.cc | 2 +- v8js_exceptions.cc | 6 +++--- v8js_methods.cc | 4 ++-- v8js_v8object_class.cc | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/v8js_class.cc b/v8js_class.cc index 65c4993..4d8a638 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -671,7 +671,7 @@ static void v8js_execute_script(zval *this_ptr, v8js_script *res, long flags, lo */ static PHP_METHOD(V8Js, executeString) { - char *str = NULL, *identifier = NULL, *tz = NULL; + char *str = NULL, *identifier = NULL; int str_len = 0, identifier_len = 0; long flags = V8JS_FLAG_NONE, time_limit = 0, memory_limit = 0; v8js_script *res = NULL; diff --git a/v8js_exceptions.cc b/v8js_exceptions.cc index 4ee35fd..d0745c7 100644 --- a/v8js_exceptions.cc +++ b/v8js_exceptions.cc @@ -46,7 +46,7 @@ void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8:: v8::Handle tc_message = try_catch->Message(); const char *filename_string, *sourceline_string; char *message_string; - int linenum, start_col, end_col, message_len; + int linenum, start_col, end_col; object_init_ex(return_value, php_ce_v8js_script_exception); @@ -54,7 +54,7 @@ void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8:: zend_update_property##type(php_ce_v8js_script_exception, return_value, #name, sizeof(#name) - 1, value TSRMLS_CC); if (tc_message.IsEmpty()) { - message_len = spprintf(&message_string, 0, "%s", exception_string); + spprintf(&message_string, 0, "%s", exception_string); } else { @@ -75,7 +75,7 @@ void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8:: end_col = tc_message->GetEndColumn(); PHPV8_EXPROP(_long, JsEndColumn, end_col); - message_len = spprintf(&message_string, 0, "%s:%d: %s", filename_string, linenum, exception_string); + spprintf(&message_string, 0, "%s:%d: %s", filename_string, linenum, exception_string); v8::String::Utf8Value stacktrace(try_catch->StackTrace()); if (stacktrace.length() > 0) { diff --git a/v8js_methods.cc b/v8js_methods.cc index 9cde0cf..0719b72 100644 --- a/v8js_methods.cc +++ b/v8js_methods.cc @@ -112,7 +112,7 @@ static void v8js_dumper(v8::Isolate *isolate, v8::Local var, int leve if (var->IsString()) { - php_printf("string(%zu) \"", valstr_len, valstr); + php_printf("string(%zu) \"", valstr_len); PHPWRITE(valstr, valstr_len); php_printf("\"\n"); } @@ -464,7 +464,7 @@ V8JS_METHOD(require) c->modules_base.push_back(normalised_path); // Run script - v8::Local result = script->Run(); + script->Run(); // Remove this module and path from the stack c->modules_stack.pop_back(); diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index dd90662..6ae5315 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -194,7 +194,6 @@ static void v8js_v8object_unset_property(zval *object, zval *member ZEND_HASH_KE static HashTable *v8js_v8object_get_properties(zval *object TSRMLS_DC) /* {{{ */ { v8js_v8object *obj = (v8js_v8object *) zend_object_store_get_object(object TSRMLS_CC); - HashTable *retval; if (obj->properties == NULL) { if (GC_G(gc_active)) { From 3dca462e9d0279f0dedbb0fb8e20f761f64465e4 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 26 Mar 2016 14:11:20 +0100 Subject: [PATCH 20/30] Use V8::LowMemoryNotification on V8 < 3.28.36 --- v8js_timer.cc | 4 ++++ v8js_v8.cc | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/v8js_timer.cc b/v8js_timer.cc index a3ae679..cb678f1 100644 --- a/v8js_timer.cc +++ b/v8js_timer.cc @@ -45,7 +45,11 @@ static void v8js_timer_interrupt_handler(v8::Isolate *isolate, void *data) { /* do { if (send_notification) { +#if PHP_V8_API_VERSION >= 3028036 isolate->LowMemoryNotification(); +#else + v8::V8::LowMemoryNotification(); +#endif has_sent_notification = true; } diff --git a/v8js_v8.cc b/v8js_v8.cc index 1ab13ab..8d53665 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -210,7 +210,11 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value, isolate->GetHeapStatistics(&hs); if (hs.used_heap_size() > memory_limit) { +#if PHP_V8_API_VERSION >= 3028036 isolate->LowMemoryNotification(); +#else + v8::V8::LowMemoryNotification(); +#endif isolate->GetHeapStatistics(&hs); if (hs.used_heap_size() > memory_limit) { From 4fea8f4fb95d8ed535258030d03e932e7f3d4169 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Wed, 11 May 2016 16:50:37 +0200 Subject: [PATCH 21/30] Require V8 4.6.76 or higher ... and hence remove all #ifdef hell. Those versions didn't have security support by Google anyhow, and it helps to drastically shrink the test matrix. --- README.md | 3 +- config.m4 | 195 ++++++++++++++++++++++------------------------ php_v8js_macros.h | 2 - v8js.cc | 2 - v8js_class.cc | 23 +----- v8js_class.h | 2 - v8js_v8.cc | 46 +---------- 7 files changed, 96 insertions(+), 177 deletions(-) diff --git a/README.md b/README.md index e409173..e096bd5 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ Minimum requirements V8 is Google's open source Javascript engine. V8 is written in C++ and is used in Google Chrome, the open source browser from Google. V8 implements ECMAScript as specified in ECMA-262, 5th edition. - This extension makes use of V8 isolates to ensure separation between multiple V8Js instances and uses the new isolate-based mechanism to throw exceptions, hence the need for 3.24.6 or above. + + This extension requires V8 4.6.76 or higher. V8 releases are published rather quickly and the V8 team usually provides security support for the version line shipped with the Chrome browser (stable channel) and newer (only). diff --git a/config.m4 b/config.m4 index 63a86f4..bcd35c8 100644 --- a/config.m4 +++ b/config.m4 @@ -121,8 +121,8 @@ int main () set $ac_cv_v8_version IFS=$ac_IFS V8_API_VERSION=`expr [$]1 \* 1000000 + [$]2 \* 1000 + [$]3` - if test "$V8_API_VERSION" -lt 3024006 ; then - AC_MSG_ERROR([libv8 must be version 3.24.6 or greater]) + if test "$V8_API_VERSION" -lt 4006076 ; then + AC_MSG_ERROR([libv8 must be version 4.6.76 or greater]) fi AC_DEFINE_UNQUOTED([PHP_V8_API_VERSION], $V8_API_VERSION, [ ]) AC_DEFINE_UNQUOTED([PHP_V8_VERSION], "$ac_cv_v8_version", [ ]) @@ -130,129 +130,116 @@ int main () AC_MSG_ERROR([could not determine libv8 version]) fi - 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 - dnl link in libplatform to make our life easier. - PHP_ADD_INCLUDE($V8_DIR) + PHP_ADD_INCLUDE($V8_DIR) - case $host_os in - darwin* ) - static_link_extra="libv8_libplatform.a libv8_libbase.a" - ;; - * ) - static_link_extra="libv8_libplatform.a" - ;; - esac + case $host_os in + darwin* ) + static_link_extra="libv8_libplatform.a libv8_libbase.a" + ;; + * ) + static_link_extra="libv8_libplatform.a" + ;; + esac - LDFLAGS_libplatform="" - for static_link_extra_file in $static_link_extra; do - AC_MSG_CHECKING([for $static_link_extra_file]) + LDFLAGS_libplatform="" + for static_link_extra_file in $static_link_extra; do + AC_MSG_CHECKING([for $static_link_extra_file]) - for i in $PHP_V8JS $SEARCH_PATH ; do - if test -r $i/lib64/$static_link_extra_file; then - static_link_dir=$i/lib64 - AC_MSG_RESULT(found in $i) - fi - if test -r $i/lib/$static_link_extra_file; then - static_link_dir=$i/lib - AC_MSG_RESULT(found in $i) - fi - done + for i in $PHP_V8JS $SEARCH_PATH ; do + if test -r $i/lib64/$static_link_extra_file; then + static_link_dir=$i/lib64 + AC_MSG_RESULT(found in $i) + fi + if test -r $i/lib/$static_link_extra_file; then + static_link_dir=$i/lib + AC_MSG_RESULT(found in $i) + fi + done - if test -z "$static_link_dir"; then - AC_MSG_RESULT([not found]) - AC_MSG_ERROR([Please provide $static_link_extra_file next to the libv8.so, see README.md for details]) - fi + if test -z "$static_link_dir"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Please provide $static_link_extra_file next to the libv8.so, see README.md for details]) + fi - LDFLAGS_libplatform="$LDFLAGS_libplatform $static_link_dir/$static_link_extra_file" - done + LDFLAGS_libplatform="$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 + # modify flags for (possibly) succeeding V8 startup check + CPPFLAGS="$CPPFLAGS -I$V8_DIR" + LIBS="$LIBS $LDFLAGS_libplatform" - 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 + 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); } + 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(); + 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; + 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]) + v8::Isolate::New(create_params); + 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" + SEARCH_PATH="$V8_DIR/lib $V8_DIR/share/v8" - AC_MSG_CHECKING([for natives_blob.bin]) - SEARCH_FOR="natives_blob.bin" + 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 + 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 + 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" + 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 + 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 + if test -z "$snapshot_blob_found"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Please provide V8 snapshot blob as needed]) + fi + ]) AC_LANG_RESTORE LIBS=$old_LIBS diff --git a/php_v8js_macros.h b/php_v8js_macros.h index a965651..3910149 100644 --- a/php_v8js_macros.h +++ b/php_v8js_macros.h @@ -167,9 +167,7 @@ struct _v8js_process_globals { /* V8 command line flags */ char *v8_flags; -#if !defined(_WIN32) && PHP_V8_API_VERSION >= 3029036 v8::Platform *v8_platform; -#endif }; extern struct _v8js_process_globals v8js_process_globals; diff --git a/v8js.cc b/v8js.cc index 272ce87..4b6302d 100755 --- a/v8js.cc +++ b/v8js.cc @@ -150,11 +150,9 @@ static PHP_MSHUTDOWN_FUNCTION(v8js) if(v8_initialized) { v8::V8::Dispose(); -#if !defined(_WIN32) && PHP_V8_API_VERSION >= 3029036 v8::V8::ShutdownPlatform(); // @fixme call virtual destructor somehow //delete v8js_process_globals.v8_platform; -#endif } if (v8js_process_globals.v8_flags) { diff --git a/v8js_class.cc b/v8js_class.cc index 4d8a638..2a620ef 100644 --- a/v8js_class.cc +++ b/v8js_class.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 | +----------------------------------------------------------------------+ @@ -71,7 +71,6 @@ struct v8js_jsext { }; /* }}} */ -#if PHP_V8_API_VERSION >= 4004010 class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: virtual void* Allocate(size_t length) { @@ -81,7 +80,6 @@ public: virtual void* AllocateUninitialized(size_t length) { return malloc(length); } virtual void Free(void* data, size_t) { free(data); } }; -#endif static void v8js_free_storage(void *object TSRMLS_DC) /* {{{ */ { @@ -207,11 +205,9 @@ static void v8js_free_storage(void *object TSRMLS_DC) /* {{{ */ c->modules_stack.~vector(); c->modules_base.~vector(); -#if PHP_V8_API_VERSION >= 4003007 if (c->zval_snapshot_blob) { zval_ptr_dtor(&c->zval_snapshot_blob); } -#endif efree(object); } @@ -367,13 +363,10 @@ static PHP_METHOD(V8Js, __construct) c->pending_exception = NULL; 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; c->create_params.array_buffer_allocator = &array_buffer_allocator; -#endif new (&c->snapshot_blob) v8::StartupData(); if (snapshot_blob) { @@ -390,10 +383,6 @@ static PHP_METHOD(V8Js, __construct) } c->isolate = v8::Isolate::New(c->create_params); -#else /* PHP_V8_API_VERSION < 4003007 */ - c->isolate = v8::Isolate::New(); -#endif - c->isolate->SetData(0, c); c->time_limit = 0; @@ -1108,7 +1097,7 @@ static PHP_METHOD(V8Js, getExtensions) } /* }}} */ -#if PHP_V8_API_VERSION >= 4003007 + /* {{{ proto string|bool V8Js::createSnapshot(string embed_source) */ static PHP_METHOD(V8Js, createSnapshot) @@ -1139,7 +1128,6 @@ static PHP_METHOD(V8Js, createSnapshot) delete[] snapshot_blob.data; } /* }}} */ -#endif /* PHP_V8_API_VERSION >= 4003007 */ /* {{{ arginfo */ @@ -1210,11 +1198,9 @@ 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) @@ -1242,10 +1228,7 @@ const zend_function_entry v8js_methods[] = { /* {{{ */ PHP_ME(V8Js, setAverageObjectSize, arginfo_v8js_setaverageobjectsize, 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} }; /* }}} */ @@ -1314,10 +1297,8 @@ PHP_MINIT_FUNCTION(v8js_class) /* {{{ */ le_v8js_script = zend_register_list_destructors_ex(v8js_script_dtor, NULL, PHP_V8JS_SCRIPT_RES_NAME, module_number); -#if PHP_V8_API_VERSION >= 4004010 && PHP_V8_API_VERSION < 4004044 static ArrayBufferAllocator array_buffer_allocator; v8::V8::SetArrayBufferAllocator(&array_buffer_allocator); -#endif return SUCCESS; } /* }}} */ diff --git a/v8js_class.h b/v8js_class.h index f4edeb5..00f4539 100644 --- a/v8js_class.h +++ b/v8js_class.h @@ -70,11 +70,9 @@ struct v8js_ctx { 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; diff --git a/v8js_v8.cc b/v8js_v8.cc index 8d53665..2baa16e 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -25,7 +25,7 @@ extern "C" { #include "zend_exceptions.h" } -#if !defined(_WIN32) && PHP_V8_API_VERSION >= 3029036 +#if !defined(_WIN32) #include #endif @@ -34,43 +34,6 @@ extern "C" { #include "v8js_timer.h" #include "v8js_exceptions.h" -#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 */ @@ -93,21 +56,14 @@ void v8js_v8_init(TSRMLS_D) /* {{{ */ #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 !defined(_WIN32) && PHP_V8_API_VERSION >= 3029036 v8js_process_globals.v8_platform = v8::platform::CreateDefaultPlatform(); v8::V8::InitializePlatform(v8js_process_globals.v8_platform); -#endif /* Set V8 command line flags (must be done before V8::Initialize()!) */ if (v8js_process_globals.v8_flags) { From 663c675fe8e4d45440de3e7773cd72dba2e925d5 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 22 May 2016 12:40:09 +0200 Subject: [PATCH 22/30] Update build path of libv8_libplatform.a, refs #230 --- README.Linux.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.Linux.md b/README.Linux.md index 5bb44df..f68c349 100644 --- a/README.Linux.md +++ b/README.Linux.md @@ -55,6 +55,11 @@ make native library=shared snapshot=on -j8 sudo mkdir -p /usr/lib /usr/include sudo cp out/native/lib.target/lib*.so /usr/lib/ sudo cp -R include/* /usr/include + +# Install libv8_libplatform.a (V8 >= 5.2.51) +echo -e "create /usr/lib/libv8_libplatform.a\naddlib out/native/obj.target/src/libv8_libplatform.a\nsave\nend" | sudo ar -M + +# ... same for V8 < 5.2.51, libv8_libplatform.a is built in tools/gyp directory echo -e "create /usr/lib/libv8_libplatform.a\naddlib out/native/obj.target/tools/gyp/libv8_libplatform.a\nsave\nend" | sudo ar -M ``` From 1d46741ced71acfac6fc861d3867126f3e15f630 Mon Sep 17 00:00:00 2001 From: Alex Masterov Date: Wed, 20 Apr 2016 09:47:32 +0300 Subject: [PATCH 23/30] Force to use the system-wide binutils during compilation v8 --- README.Linux.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.Linux.md b/README.Linux.md index f68c349..994dda5 100644 --- a/README.Linux.md +++ b/README.Linux.md @@ -49,6 +49,10 @@ export GYP_DEFINES="use_system_icu=1" # Build (with internal snapshots) export GYPFLAGS="-Dv8_use_external_startup_data=0" + +# Force gyp to use system-wide ld.gold +export GYPFLAGS="${GYPFLAGS} -Dlinux_use_bundled_gold=0" + make native library=shared snapshot=on -j8 # Install to /usr From 5fa653da2374e02f1371e28cd24e9842c712efc4 Mon Sep 17 00:00:00 2001 From: Tieme van Veen Date: Thu, 7 Apr 2016 14:10:43 +0200 Subject: [PATCH 24/30] Added libicu-dev dependency --- README.Linux.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.Linux.md b/README.Linux.md index 994dda5..5cbb37e 100644 --- a/README.Linux.md +++ b/README.Linux.md @@ -29,7 +29,11 @@ In that case copy those two files to `/usr/share/v8/...`. Compile latest V8 ----------------- + ``` +# Install `libicu-dev` if you haven't already: +sudo apt-get install libicu-dev + cd /tmp # Install depot_tools first (needed for source checkout) From b21ba328d072650555fe532eb14135fb39472913 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 22 May 2016 13:27:48 +0200 Subject: [PATCH 25/30] Don't call ObjectTemplate.Set with Object instances, fixes #230 This works fine with V8 < 5.2.50 somehow, but is now (properly) detected and causing V8 to bail out. Fixed by always setting templates on other templates and finally use Global-Proxy on context to get the actually created object instances. --- v8js_methods.cc | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/v8js_methods.cc b/v8js_methods.cc index 0719b72..166788f 100644 --- a/v8js_methods.cc +++ b/v8js_methods.cc @@ -208,7 +208,7 @@ V8JS_METHOD(require) V8JS_TSRMLS_FETCH(); // Get the extension context - v8::Handle data = v8::Handle::Cast(info.Data()); + v8::Local data = v8::Local::Cast(info.Data()); v8js_ctx *c = static_cast(data->Value()); // Check that we have a module loader @@ -411,25 +411,23 @@ V8JS_METHOD(require) } // Create a template for the global object and set the built-in global functions - v8::Handle global = v8::ObjectTemplate::New(); - global->Set(V8JS_SYM("print"), v8::FunctionTemplate::New(isolate, V8JS_MN(print)), v8::ReadOnly); - global->Set(V8JS_SYM("var_dump"), v8::FunctionTemplate::New(isolate, V8JS_MN(var_dump)), v8::ReadOnly); - global->Set(V8JS_SYM("sleep"), v8::FunctionTemplate::New(isolate, V8JS_MN(sleep)), v8::ReadOnly); - global->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(isolate, V8JS_MN(require), v8::External::New(isolate, c)), v8::ReadOnly); + v8::Local global_template = v8::ObjectTemplate::New(); + global_template->Set(V8JS_SYM("print"), v8::FunctionTemplate::New(isolate, V8JS_MN(print)), v8::ReadOnly); + global_template->Set(V8JS_SYM("var_dump"), v8::FunctionTemplate::New(isolate, V8JS_MN(var_dump)), v8::ReadOnly); + global_template->Set(V8JS_SYM("sleep"), v8::FunctionTemplate::New(isolate, V8JS_MN(sleep)), v8::ReadOnly); + global_template->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(isolate, V8JS_MN(require), v8::External::New(isolate, c)), v8::ReadOnly); // Add the exports object in which the module can return its API v8::Local exports_template = v8::ObjectTemplate::New(); - v8::Local exports = exports_template->NewInstance(); - global->Set(V8JS_SYM("exports"), exports); + global_template->Set(V8JS_SYM("exports"), exports_template); // Add the module object in which the module can have more fine-grained control over what it can return - v8::Handle module_template = v8::ObjectTemplate::New(); - v8::Handle module = module_template->NewInstance(); - module->Set(V8JS_SYM("id"), V8JS_STR(normalised_module_id)); - global->Set(V8JS_SYM("module"), module); + v8::Local module_template = v8::ObjectTemplate::New(); + module_template->Set(V8JS_SYM("id"), V8JS_STR(normalised_module_id)); + global_template->Set(V8JS_SYM("module"), module_template); // Each module gets its own context so different modules do not affect each other - v8::Local context = v8::Local::New(isolate, v8::Context::New(isolate, NULL, global)); + v8::Local context = v8::Local::New(isolate, v8::Context::New(isolate, NULL, global_template)); // Catch JS exceptions v8::TryCatch try_catch; @@ -487,16 +485,19 @@ V8JS_METHOD(require) return; } - v8::Handle newobj; + v8::Local newobj; // Cache the module so it doesn't need to be compiled and run again // Ensure compatibility with CommonJS implementations such as NodeJS by playing nicely with module.exports and exports - if (module->Has(V8JS_SYM("exports")) && !module->Get(V8JS_SYM("exports"))->IsUndefined()) { + if (context->Global()->Has(V8JS_SYM("module")) + && context->Global()->Get(V8JS_SYM("module"))->IsObject() + && context->Global()->Get(V8JS_SYM("module"))->ToObject()->Has(V8JS_SYM("exports")) + && context->Global()->Get(V8JS_SYM("module"))->ToObject()->Get(V8JS_SYM("exports"))->IsObject()) { // If module.exports has been set then we cache this arbitrary value... - newobj = module->Get(V8JS_SYM("exports"))->ToObject(); + newobj = context->Global()->Get(V8JS_SYM("module"))->ToObject()->Get(V8JS_SYM("exports"))->ToObject(); } else { // ...otherwise we cache the exports object itself - newobj = exports; + newobj = context->Global()->Get(V8JS_SYM("exports"))->ToObject(); } c->modules_loaded[normalised_module_id].Reset(isolate, newobj); From ed8e88e11d35e7bd3571c46a8797c2e93232b9ed Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 22 May 2016 15:11:35 +0200 Subject: [PATCH 26/30] Search libv8_libplatform.a in V8_DIR only Otherwise config.m4 will find another libv8_libplatform.a (e.g. in /usr/lib) as well ... and then use the wrong one. --- config.m4 | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/config.m4 b/config.m4 index bcd35c8..694fca9 100644 --- a/config.m4 +++ b/config.m4 @@ -145,16 +145,15 @@ int main () for static_link_extra_file in $static_link_extra; do AC_MSG_CHECKING([for $static_link_extra_file]) - for i in $PHP_V8JS $SEARCH_PATH ; do - if test -r $i/lib64/$static_link_extra_file; then - static_link_dir=$i/lib64 - AC_MSG_RESULT(found in $i) - fi - if test -r $i/lib/$static_link_extra_file; then - static_link_dir=$i/lib - AC_MSG_RESULT(found in $i) - fi - done + if test -r $V8_DIR/lib64/$static_link_extra_file; then + static_link_dir=$V8_DIR/lib64 + AC_MSG_RESULT(found in $V8_DIR/lib64) + fi + + if test -r $V8_DIR/lib/$static_link_extra_file; then + static_link_dir=$V8_DIR/lib + AC_MSG_RESULT(found in $V8_DIR/lib) + fi if test -z "$static_link_dir"; then AC_MSG_RESULT([not found]) From d4d8ccc4f6ee7db37286f8deb71681d14d82f0a0 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 22 May 2016 15:20:05 +0200 Subject: [PATCH 27/30] Fix #ifdef change, don't call SetArrayBufferAllocator --- v8js_class.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/v8js_class.cc b/v8js_class.cc index 2a620ef..8c34981 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -1297,9 +1297,6 @@ PHP_MINIT_FUNCTION(v8js_class) /* {{{ */ le_v8js_script = zend_register_list_destructors_ex(v8js_script_dtor, NULL, PHP_V8JS_SCRIPT_RES_NAME, module_number); - static ArrayBufferAllocator array_buffer_allocator; - v8::V8::SetArrayBufferAllocator(&array_buffer_allocator); - return SUCCESS; } /* }}} */ From 05b96a96b8d44d9d859b12c557d5eddd0b34beba Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 22 May 2016 15:12:44 +0200 Subject: [PATCH 28/30] Use internal fields instead of GetHiddenValue/SetHiddenValue The latter were deprecated and removed in V8 5.2 --- php_v8js_macros.h | 3 --- v8js_array_access.cc | 20 +++++++------------- v8js_class.cc | 3 ++- v8js_convert.cc | 12 +++++++----- v8js_exceptions.cc | 19 +++++++------------ v8js_object_export.cc | 30 ++++++++++++------------------ v8js_v8.cc | 9 ++------- 7 files changed, 37 insertions(+), 59 deletions(-) diff --git a/php_v8js_macros.h b/php_v8js_macros.h index 3910149..6345df4 100644 --- a/php_v8js_macros.h +++ b/php_v8js_macros.h @@ -55,9 +55,6 @@ extern "C" { /* V8Js Version */ #define PHP_V8JS_VERSION "0.6.2" -/* Hidden field name used to link JS wrappers with underlying PHP object */ -#define PHPJS_OBJECT_KEY "phpjs::object" - /* Helper macros */ #define V8JS_GET_CLASS_NAME(var, obj) \ v8::String::Utf8Value var(obj->GetConstructorName()); diff --git a/v8js_array_access.cc b/v8js_array_access.cc index b55a313..d92b8a7 100644 --- a/v8js_array_access.cc +++ b/v8js_array_access.cc @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | 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 | +----------------------------------------------------------------------+ @@ -73,8 +73,7 @@ void v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo php_object = self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); - zval *object = reinterpret_cast(v8::External::Cast(*php_object)->Value()); + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); zval *php_value = v8js_array_access_dispatch(object, "offsetGet", 1, index, NULL TSRMLS_CC); v8::Local ret_value = zval_to_v8js(php_value, isolate TSRMLS_CC); @@ -92,8 +91,7 @@ void v8js_array_access_setter(uint32_t index, v8::Local value, V8JS_TSRMLS_FETCH(); - v8::Local php_object = self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); - zval *object = reinterpret_cast(v8::External::Cast(*php_object)->Value()); + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); zval *zvalue_ptr; MAKE_STD_ZVAL(zvalue_ptr); @@ -156,8 +154,7 @@ static void v8js_array_access_length(v8::Local property, const v8::P V8JS_TSRMLS_FETCH(); - v8::Local php_object = self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); - zval *object = reinterpret_cast(v8::External::Cast(*php_object)->Value()); + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); int length = v8js_array_access_get_count_result(object TSRMLS_CC); info.GetReturnValue().Set(V8JS_INT(length)); @@ -171,8 +168,7 @@ void v8js_array_access_deleter(uint32_t index, const v8::PropertyCallbackInfo php_object = self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); - zval *object = reinterpret_cast(v8::External::Cast(*php_object)->Value()); + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); zval *php_value = v8js_array_access_dispatch(object, "offsetUnset", 1, index, NULL TSRMLS_CC); zval_ptr_dtor(&php_value); @@ -188,8 +184,7 @@ void v8js_array_access_query(uint32_t index, const v8::PropertyCallbackInfo php_object = self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); - zval *object = reinterpret_cast(v8::External::Cast(*php_object)->Value()); + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); /* If index is set, then return an integer encoding a v8::PropertyAttribute; * otherwise we're expected to return an empty handle. */ @@ -207,8 +202,7 @@ void v8js_array_access_enumerator(const v8::PropertyCallbackInfo& inf V8JS_TSRMLS_FETCH(); - v8::Local php_object = self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); - zval *object = reinterpret_cast(v8::External::Cast(*php_object)->Value()); + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); int length = v8js_array_access_get_count_result(object TSRMLS_CC); v8::Local result = v8::Array::New(isolate, length); diff --git a/v8js_class.cc b/v8js_class.cc index 8c34981..77d0857 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -475,6 +475,7 @@ static PHP_METHOD(V8Js, __construct) c->object_name.Reset(isolate, object_name_js); /* Add the PHP object into global object */ + php_obj_t->InstanceTemplate()->SetInternalFieldCount(2); v8::Local php_obj = php_obj_t->InstanceTemplate()->NewInstance(); V8JS_GLOBAL(isolate)->ForceSet(object_name_js, php_obj, v8::ReadOnly); @@ -505,7 +506,7 @@ static PHP_METHOD(V8Js, __construct) } /* Add pointer to zend object */ - php_obj->SetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY), v8::External::New(isolate, getThis())); + php_obj->SetAlignedPointerInInternalField(1, getThis()); /* Export public methods */ zend_function *method_ptr; diff --git a/v8js_convert.cc b/v8js_convert.cc index 9f824bf..67988e4 100644 --- a/v8js_convert.cc +++ b/v8js_convert.cc @@ -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 | +----------------------------------------------------------------------+ */ @@ -236,14 +237,15 @@ int v8js_to_zval(v8::Handle jsValue, zval *return_value, int flags, v } else if (jsValue->IsObject()) { - v8::Handle self = v8::Handle::Cast(jsValue); + v8::Local self = jsValue->ToObject(); + // if this is a wrapped PHP object, then just unwrap it. - v8::Local php_object = self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); - if (!php_object.IsEmpty()) { - zval *object = reinterpret_cast(v8::External::Cast(*php_object)->Value()); + if (self->InternalFieldCount()) { + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); RETVAL_ZVAL(object, 1, 0); return SUCCESS; } + if ((flags & V8JS_FLAG_FORCE_ARRAY && !jsValue->IsFunction()) || jsValue->IsArray()) { array_init(return_value); return v8js_get_properties_hash(jsValue, Z_ARRVAL_P(return_value), flags, isolate TSRMLS_CC); diff --git a/v8js_exceptions.cc b/v8js_exceptions.cc index d0745c7..b376f49 100644 --- a/v8js_exceptions.cc +++ b/v8js_exceptions.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 | +----------------------------------------------------------------------+ @@ -83,18 +83,13 @@ void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8:: PHPV8_EXPROP(_string, JsTrace, stacktrace_string); } - if(try_catch->Exception()->IsObject()) { - v8::Local php_ref = try_catch->Exception()->ToObject()->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); + if(try_catch->Exception()->IsObject() && try_catch->Exception()->ToObject()->InternalFieldCount()) { + zval *php_exception = reinterpret_cast(try_catch->Exception()->ToObject()->GetAlignedPointerFromInternalField(1)); - if(!php_ref.IsEmpty()) { - assert(php_ref->IsExternal()); - zval *php_exception = reinterpret_cast(v8::External::Cast(*php_ref)->Value()); - - zend_class_entry *exception_ce = zend_exception_get_default(TSRMLS_C); - if (Z_TYPE_P(php_exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(php_exception), exception_ce TSRMLS_CC)) { - Z_ADDREF_P(php_exception); - zend_exception_set_previous(return_value, php_exception TSRMLS_CC); - } + zend_class_entry *exception_ce = zend_exception_get_default(TSRMLS_C); + if (Z_TYPE_P(php_exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(php_exception), exception_ce TSRMLS_CC)) { + Z_ADDREF_P(php_exception); + zend_exception_set_previous(return_value, php_exception TSRMLS_CC); } } diff --git a/v8js_object_export.cc b/v8js_object_export.cc index aea7438..5d7c6e2 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -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 | +----------------------------------------------------------------------+ */ @@ -88,13 +89,9 @@ static void v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function fci.params = (zval ***) safe_emalloc(argc, sizeof(zval **), 0); argv = (zval **) safe_emalloc(argc, sizeof(zval *), 0); for (i = 0; i < argc; i++) { - v8::Local php_object; - if (info[i]->IsObject()) { - php_object = v8::Local::Cast(info[i])->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); - } - if (!php_object.IsEmpty()) { + if (info[i]->IsObject() && info[i]->ToObject()->InternalFieldCount()) { /* This is a PHP object, passed to JS and back. */ - argv[i] = reinterpret_cast(v8::External::Cast(*php_object)->Value()); + argv[i] = reinterpret_cast(info[i]->ToObject()->GetAlignedPointerFromInternalField(1)); Z_ADDREF_P(argv[i]); } else { MAKE_STD_ZVAL(argv[i]); @@ -178,7 +175,7 @@ void v8js_php_callback(const v8::FunctionCallbackInfo& info) /* {{{ * v8::Local self = info.Holder(); V8JS_TSRMLS_FETCH(); - zval *value = reinterpret_cast(v8::External::Cast(*self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)))->Value()); + zval *value = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); zend_function *method_ptr; zend_class_entry *ce = Z_OBJCE_P(value); @@ -198,9 +195,7 @@ static void v8js_construct_callback(const v8::FunctionCallbackInfo& i v8::Isolate *isolate = info.GetIsolate(); info.GetReturnValue().Set(V8JS_UNDEFINED); - // @todo assert constructor call v8::Handle newobj = info.This(); - v8::Local php_object; zval *value; if (!info.IsConstructCall()) { @@ -215,14 +210,14 @@ static void v8js_construct_callback(const v8::FunctionCallbackInfo& i if (info[0]->IsExternal()) { // Object created by v8js in v8js_hash_to_jsobj, PHP object passed as v8::External. - php_object = v8::Local::Cast(info[0]); + v8::Local php_object = v8::Local::Cast(info[0]); value = reinterpret_cast(php_object->Value()); if(ctx->weak_objects.count(value)) { // We already exported this object, hence no need to add another // ref, v8 won't give us a second weak-object callback anyways. newobj->SetAlignedPointerInInternalField(0, ext_tmpl->Value()); - newobj->SetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY), php_object); + newobj->SetAlignedPointerInInternalField(1, value); return; } @@ -248,11 +243,10 @@ static void v8js_construct_callback(const v8::FunctionCallbackInfo& i if (ctor_ptr != NULL) { v8js_call_php_func(value, ce, ctor_ptr, isolate, info TSRMLS_CC); } - php_object = v8::External::New(isolate, value); } newobj->SetAlignedPointerInInternalField(0, ext_tmpl->Value()); - newobj->SetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY), php_object); + newobj->SetAlignedPointerInInternalField(1, value); // Since we got to decrease the reference count again, in case v8 garbage collector // decides to dispose the JS object, we add a weak persistent handle and register @@ -319,7 +313,7 @@ static void v8js_named_property_enumerator(const v8::PropertyCallbackInfo(v8::External::Cast(*self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)))->Value()); + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); ce = Z_OBJCE_P(object); /* enumerate all methods */ @@ -449,7 +443,7 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo& info) V8JS_TSRMLS_FETCH(); zend_class_entry *ce; - zval *object = reinterpret_cast(v8::External::Cast(*self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)))->Value()); + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); ce = Z_OBJCE_P(object); // first arg is method name, second arg is array of args. @@ -541,7 +535,7 @@ inline v8::Local v8js_named_property_callback(v8::Local p zend_function *method_ptr = NULL; zval *php_value; - zval *object = reinterpret_cast(v8::External::Cast(*self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)))->Value()); + zval *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); v8js_tmpl_t *tmpl_ptr = reinterpret_cast(self->GetAlignedPointerFromInternalField(0)); v8::Local tmpl = v8::Local::New(isolate, *tmpl_ptr); ce = scope = Z_OBJCE_P(object); @@ -809,7 +803,7 @@ static v8::Handle v8js_wrap_object(v8::Isolate *isolate, zend_class_ new_tpl = v8::FunctionTemplate::New(isolate, 0); new_tpl->SetClassName(V8JS_STRL(ce->name, ce->name_length)); - new_tpl->InstanceTemplate()->SetInternalFieldCount(1); + new_tpl->InstanceTemplate()->SetInternalFieldCount(2); if (ce == zend_ce_closure) { /* Got a closure, mustn't cache ... */ diff --git a/v8js_v8.cc b/v8js_v8.cc index 2baa16e..22e6b42 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -276,13 +276,8 @@ int v8js_get_properties_hash(v8::Handle jsValue, HashTable *retval, i const char *key = ToCString(cstr); zval *value = NULL; - v8::Local php_object; - if (jsVal->IsObject()) { - php_object = v8::Local::Cast(jsVal)->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)); - } - if (!php_object.IsEmpty()) { - /* This is a PHP object, passed to JS and back. */ - value = reinterpret_cast(v8::External::Cast(*php_object)->Value()); + if (jsVal->IsObject() && jsVal->ToObject()->InternalFieldCount()) { + value = reinterpret_cast(jsVal->ToObject()->GetAlignedPointerFromInternalField(1)); Z_ADDREF_P(value); } else { From ec6c6d3eb3bcd95e134bedb0bb015cc099d854a9 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 22 May 2016 20:08:28 +0200 Subject: [PATCH 29/30] Use WeakCallbackInfo WeakCallbackData was deprecated and finally removed in V8 5.2 --- v8js_object_export.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 5d7c6e2..ef6784a 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -30,7 +30,7 @@ extern "C" { #include "v8js_object_export.h" #include "v8js_v8object_class.h" -static void v8js_weak_object_callback(const v8::WeakCallbackData &data); +static void v8js_weak_object_callback(const v8::WeakCallbackInfo &data); /* Callback for PHP methods and functions */ static void v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function *method_ptr, v8::Isolate *isolate, const v8::FunctionCallbackInfo& info TSRMLS_DC) /* {{{ */ @@ -252,7 +252,7 @@ static void v8js_construct_callback(const v8::FunctionCallbackInfo& i // decides to dispose the JS object, we add a weak persistent handle and register // a callback function that removes the reference. ctx->weak_objects[value].Reset(isolate, newobj); - ctx->weak_objects[value].SetWeak(value, v8js_weak_object_callback); + ctx->weak_objects[value].SetWeak(value, v8js_weak_object_callback, v8::WeakCallbackType::kParameter); // Just tell v8 that we're allocating some external memory // (for the moment we just always tell 1k instead of trying to find out actual values) @@ -261,7 +261,7 @@ static void v8js_construct_callback(const v8::FunctionCallbackInfo& i /* }}} */ -static void v8js_weak_object_callback(const v8::WeakCallbackData &data) { +static void v8js_weak_object_callback(const v8::WeakCallbackInfo &data) { v8::Isolate *isolate = data.GetIsolate(); zval *value = data.GetParameter(); @@ -275,7 +275,7 @@ static void v8js_weak_object_callback(const v8::WeakCallbackDataAdjustAmountOfExternalAllocatedMemory(-ctx->average_object_size); } -static void v8js_weak_closure_callback(const v8::WeakCallbackData &data) { +static void v8js_weak_closure_callback(const v8::WeakCallbackInfo &data) { v8::Isolate *isolate = data.GetIsolate(); v8js_tmpl_t *persist_tpl_ = data.GetParameter(); @@ -884,7 +884,7 @@ static v8::Handle v8js_wrap_object(v8::Isolate *isolate, zend_class_ if (ce == zend_ce_closure) { // free uncached function template when object is freed ctx->weak_closures[persist_tpl_].Reset(isolate, newobj); - ctx->weak_closures[persist_tpl_].SetWeak(persist_tpl_, v8js_weak_closure_callback); + ctx->weak_closures[persist_tpl_].SetWeak(persist_tpl_, v8js_weak_closure_callback, v8::WeakCallbackType::kParameter); } return newobj; From c34fc46ce202ad1226f606ceb41948e1f244e725 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 22 May 2016 21:07:35 +0200 Subject: [PATCH 30/30] Bump version to 0.6.3 --- package.xml | 95 ++++++++++++++++++++++++++++++----------------- php_v8js_macros.h | 2 +- 2 files changed, 62 insertions(+), 35 deletions(-) diff --git a/package.xml b/package.xml index 63fa620..f0b8493 100644 --- a/package.xml +++ b/package.xml @@ -1,5 +1,5 @@ - + v8js pecl.php.net V8 Javascript Engine for PHP @@ -16,11 +16,11 @@ stesie@php.net yes - 2016-03-25 - + 2016-05-22 + - 0.6.2 - 0.6.2 + 0.6.3 + 0.6.3 stable @@ -28,9 +28,14 @@ The MIT License (MIT) -- Pass back V8Object instances, don't re-wrap -- Retain object identity on 'return $this' -- Retain object identity on JS-side 'return this' +Bug Fixes +- Send LowMemoryNotification signals to V8 before imposing memory limit +- Fix build against V8 version 5.2 (deprecated WeakCallbackInfo & GetHiddenValue et al) +- Improve/Clarify README + +Code Cleanup +- Removed support for "old-age" V8 versions (i.e. V8 < 4.6.76) +- Removed old examples and pre-phpt test script @@ -129,7 +134,7 @@ - + @@ -164,52 +169,52 @@ - - - - - - - - + + + + + + + + - + - + - + - - + + - + - - + + - - + + - - + + - - + + - + - + - + @@ -551,5 +556,27 @@ - Retain object identity on JS-side 'return this' + + + 0.6.3 + 0.6.3 + + + stable + stable + + 2016-05-22 + The MIT License (MIT) + +Bug Fixes +- Send LowMemoryNotification signals to V8 before imposing memory limit +- Fix build against V8 version 5.2 (deprecated WeakCallbackInfo & GetHiddenValue et al) +- Improve/Clarify README + +Code Cleanup +- Removed support for "old-age" V8 versions (i.e. V8 < 4.6.76) +- Removed old examples and pre-phpt test script + + diff --git a/php_v8js_macros.h b/php_v8js_macros.h index 6345df4..b34b5ca 100644 --- a/php_v8js_macros.h +++ b/php_v8js_macros.h @@ -53,7 +53,7 @@ extern "C" { #endif /* V8Js Version */ -#define PHP_V8JS_VERSION "0.6.2" +#define PHP_V8JS_VERSION "0.6.3" /* Helper macros */ #define V8JS_GET_CLASS_NAME(var, obj) \