summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--v8js-upstream.patch1022
1 files changed, 0 insertions, 1022 deletions
diff --git a/v8js-upstream.patch b/v8js-upstream.patch
deleted file mode 100644
index 937915d..0000000
--- a/v8js-upstream.patch
+++ /dev/null
@@ -1,1022 +0,0 @@
-Some selected patches from https://github.com/phpv8/v8js/compare/2.1.0...php7
-to fix compatibility with upcoming PHP 7.3
-
-
-From 48a763d6dbd0543ef49e275c6a5d4de4e25af24a Mon Sep 17 00:00:00 2001
-From: Stefan Siegl <stesie@brokenpipe.de>
-Date: Thu, 1 Feb 2018 19:38:47 +0100
-Subject: [PATCH 02/18] pass module_base directly via FunctionTemplate, closes
- #349
-
----
- tests/issue_349_basic.phpt | 82 ++++++++++++++++++++++++++++++++++++++
- v8js_methods.cc | 34 +++++++++++-----
- 2 files changed, 106 insertions(+), 10 deletions(-)
- create mode 100644 tests/issue_349_basic.phpt
-
-diff --git a/tests/issue_349_basic.phpt b/tests/issue_349_basic.phpt
-new file mode 100644
-index 0000000..f7a6d7d
---- /dev/null
-+++ b/tests/issue_349_basic.phpt
-@@ -0,0 +1,82 @@
-+--TEST--
-+Test V8Js::setModuleNormaliser : Custom normalisation #005
-+--SKIPIF--
-+<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
-+--FILE--
-+<?php
-+
-+$v8 = new V8Js();
-+
-+$v8->setModuleNormaliser(function ($base, $moduleName) {
-+ var_dump($base, $moduleName);
-+ if ($base == '' && $moduleName == './tags') {
-+ return ['./tags', 'index.js'];
-+ }
-+ if ($base == './tags' && $moduleName == './if.js') {
-+ return ['./tags', 'if.js'];
-+ }
-+ return [$base, $moduleName];
-+});
-+
-+$v8->setModuleLoader(function ($moduleName) {
-+ print("setModuleLoader called for ".$moduleName."\n");
-+ switch ($moduleName) {
-+ case './app.js':
-+ return "require('./tags')";
-+ case './tags/index.js':
-+ return "require('./if.js')";
-+ }
-+});
-+
-+$v8->executeString("require('./app.js')");
-+
-+echo "------------------------------------------------\n";
-+
-+$v8 = new V8Js();
-+
-+$v8->setModuleNormaliser(function ($base, $moduleName) {
-+ var_dump($base, $moduleName);
-+ if ($base == '' && $moduleName == './tags') {
-+ return ['./tags', 'index.js'];
-+ }
-+ if ($base == './tags' && $moduleName == './if.js') {
-+ return ['./tags', 'if.js'];
-+ }
-+ return [$base, $moduleName];
-+});
-+
-+$v8->setModuleLoader(function ($moduleName) {
-+ print("setModuleLoader called for ".$moduleName."\n");
-+ switch ($moduleName) {
-+ case './app.js':
-+ return "require('./tags')()"; // different
-+ case './tags/index.js':
-+ return "module.exports = function() {require('./if.js')}"; // different
-+ }
-+});
-+
-+$v8->executeString("require('./app.js')");
-+
-+?>
-+===EOF===
-+--EXPECT--
-+string(0) ""
-+string(8) "./app.js"
-+setModuleLoader called for ./app.js
-+string(0) ""
-+string(6) "./tags"
-+setModuleLoader called for ./tags/index.js
-+string(6) "./tags"
-+string(7) "./if.js"
-+setModuleLoader called for ./tags/if.js
-+------------------------------------------------
-+string(0) ""
-+string(8) "./app.js"
-+setModuleLoader called for ./app.js
-+string(0) ""
-+string(6) "./tags"
-+setModuleLoader called for ./tags/index.js
-+string(6) "./tags"
-+string(7) "./if.js"
-+setModuleLoader called for ./tags/if.js
-+===EOF===
-diff --git a/v8js_methods.cc b/v8js_methods.cc
-index 947d348..644c8c2 100644
---- a/v8js_methods.cc
-+++ b/v8js_methods.cc
-@@ -205,10 +205,10 @@ V8JS_METHOD(var_dump) /* {{{ */
- V8JS_METHOD(require)
- {
- v8::Isolate *isolate = info.GetIsolate();
-+ v8js_ctx *c = (v8js_ctx *) isolate->GetData(0);
-
-- // Get the extension context
-- v8::Local<v8::External> data = v8::Local<v8::External>::Cast(info.Data());
-- v8js_ctx *c = static_cast<v8js_ctx*>(data->Value());
-+ v8::String::Utf8Value module_base(info.Data());
-+ const char *module_base_cstr = ToCString(module_base);
-
- // Check that we have a module loader
- if(Z_TYPE(c->module_loader) == IS_NULL) {
-@@ -225,7 +225,7 @@ V8JS_METHOD(require)
- normalised_path = (char *)emalloc(PATH_MAX);
- module_name = (char *)emalloc(PATH_MAX);
-
-- v8js_commonjs_normalise_identifier(c->modules_base.back(), module_id, normalised_path, module_name);
-+ v8js_commonjs_normalise_identifier(module_base_cstr, module_id, normalised_path, module_name);
- }
- else {
- // Call custom normaliser
-@@ -238,7 +238,7 @@ V8JS_METHOD(require)
- isolate->Exit();
- v8::Unlocker unlocker(isolate);
-
-- ZVAL_STRING(&params[0], c->modules_base.back());
-+ ZVAL_STRING(&params[0], module_base_cstr);
- ZVAL_STRING(&params[1], module_id);
-
- call_result = call_user_function_ex(EG(function_table), NULL, &c->module_normaliser,
-@@ -445,7 +445,7 @@ V8JS_METHOD(require)
- v8::Local<v8::String> source = V8JS_ZSTR(Z_STR(module_code));
- zval_ptr_dtor(&module_code);
-
-- source = v8::String::Concat(V8JS_SYM("(function (exports, module) {"), source);
-+ source = v8::String::Concat(V8JS_SYM("(function (exports, module, require) {"), source);
- source = v8::String::Concat(source, V8JS_SYM("\n});"));
-
- // Create and compile script
-@@ -459,6 +459,17 @@ V8JS_METHOD(require)
- return;
- }
-
-+ v8::Local<v8::String> base_path = V8JS_STR(normalised_path);
-+ v8::MaybeLocal<v8::Function> require_fn = v8::FunctionTemplate::New(isolate, V8JS_MN(require), base_path)->GetFunction();
-+
-+ if (require_fn.IsEmpty()) {
-+ efree(normalised_path);
-+ efree(normalised_module_id);
-+ info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Failed to create require method")));
-+ return;
-+ }
-+
-+
- // Add this module and path to the stack
- c->modules_stack.push_back(normalised_module_id);
- c->modules_base.push_back(normalised_path);
-@@ -474,15 +485,18 @@ V8JS_METHOD(require)
- module->Set(V8JS_SYM("exports"), exports);
-
- if (module_function->IsFunction()) {
-- v8::Local<v8::Value> *jsArgv = static_cast<v8::Local<v8::Value> *>(alloca(2 * sizeof(v8::Local<v8::Value>)));
-+ v8::Local<v8::Value> *jsArgv = static_cast<v8::Local<v8::Value> *>(alloca(3 * sizeof(v8::Local<v8::Value>)));
- new(&jsArgv[0]) v8::Local<v8::Value>;
- jsArgv[0] = exports;
-
- new(&jsArgv[1]) v8::Local<v8::Value>;
- jsArgv[1] = module;
-
-+ new(&jsArgv[2]) v8::Local<v8::Value>;
-+ jsArgv[2] = require_fn.ToLocalChecked();
-+
- // actually call the module
-- v8::Local<v8::Function>::Cast(module_function)->Call(exports, 2, jsArgv);
-+ v8::Local<v8::Function>::Cast(module_function)->Call(exports, 3, jsArgv);
- }
-
- // Remove this module and path from the stack
-@@ -532,8 +546,8 @@ void v8js_register_methods(v8::Local<v8::ObjectTemplate> global, v8js_ctx *c) /*
- 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);
-
-- c->modules_base.push_back("");
-- global->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(isolate, V8JS_MN(require), v8::External::New(isolate, c)), v8::ReadOnly);
-+ v8::Local<v8::String> base_path = V8JS_STRL("", 0);
-+ global->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(isolate, V8JS_MN(require), base_path), v8::ReadOnly);
- }
- /* }}} */
-
-
-From 313ad1e258542e2db64a0a38f64eb789c963bd03 Mon Sep 17 00:00:00 2001
-From: Stefan Siegl <stesie@brokenpipe.de>
-Date: Thu, 1 Feb 2018 19:43:36 +0100
-Subject: [PATCH 04/18] cleanup: remove no longer needed modules_base from ctx,
- refs #349
-
----
- v8js_class.cc | 2 --
- v8js_class.h | 1 -
- v8js_methods.cc | 2 --
- 3 files changed, 5 deletions(-)
-
-diff --git a/v8js_class.cc b/v8js_class.cc
-index a572864..dc366aa 100644
---- a/v8js_class.cc
-+++ b/v8js_class.cc
-@@ -200,7 +200,6 @@ static void v8js_free_storage(zend_object *object) /* {{{ */
- }
-
- c->modules_stack.~vector();
-- c->modules_base.~vector();
-
- zval_ptr_dtor(&c->zval_snapshot_blob);
-
-@@ -226,7 +225,6 @@ static zend_object* v8js_new(zend_class_entry *ce) /* {{{ */
- new(&c->array_tmpl) v8::Persistent<v8::FunctionTemplate>();
-
- new(&c->modules_stack) std::vector<char*>();
-- new(&c->modules_base) std::vector<char*>();
- new(&c->modules_loaded) std::map<char *, v8js_persistent_value_t, cmp_str>;
-
- new(&c->template_cache) std::map<const zend_string *,v8js_function_tmpl_t>();
-diff --git a/v8js_class.h b/v8js_class.h
-index 4886754..cd06fc5 100644
---- a/v8js_class.h
-+++ b/v8js_class.h
-@@ -57,7 +57,6 @@ struct v8js_ctx {
- zval module_loader;
-
- std::vector<char *> modules_stack;
-- std::vector<char *> modules_base;
- std::map<char *, v8js_persistent_value_t, cmp_str> modules_loaded;
- std::map<const zend_string *,v8js_function_tmpl_t> template_cache;
-
-diff --git a/v8js_methods.cc b/v8js_methods.cc
-index 644c8c2..4bee095 100644
---- a/v8js_methods.cc
-+++ b/v8js_methods.cc
-@@ -472,7 +472,6 @@ V8JS_METHOD(require)
-
- // Add this module and path to the stack
- c->modules_stack.push_back(normalised_module_id);
-- c->modules_base.push_back(normalised_path);
-
- // Run script to evaluate closure
- v8::Local<v8::Value> module_function = script->Run();
-@@ -501,7 +500,6 @@ V8JS_METHOD(require)
-
- // Remove this module and path from the stack
- c->modules_stack.pop_back();
-- c->modules_base.pop_back();
-
- efree(normalised_path);
-
-
-From c7019e3c1a311e6ed2cccda01445e21fa5a17969 Mon Sep 17 00:00:00 2001
-From: Jan-E <github@ehrhardt.nl>
-Date: Thu, 5 Jul 2018 11:22:17 +0200
-Subject: [PATCH 05/18] Remove GC_G(gc_active) check
-
----
- v8js_v8object_class.cc | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc
-index 49669ac..abc32d3 100644
---- a/v8js_v8object_class.cc
-+++ b/v8js_v8object_class.cc
-@@ -210,10 +210,12 @@ static HashTable *v8js_v8object_get_properties(zval *object) /* {{{ */
- v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object);
-
- if (obj->properties == NULL) {
-+#if PHP_VERSION_ID < 70300
- if (GC_G(gc_active)) {
- /* the garbage collector is running, don't create more zvals */
- return NULL;
- }
-+#endif
-
- ALLOC_HASHTABLE(obj->properties);
- zend_hash_init(obj->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
-
-From 826aaa689cd420d1ea0961109607a8641de31031 Mon Sep 17 00:00:00 2001
-From: Jan-E <github@ehrhardt.nl>
-Date: Thu, 5 Jul 2018 11:30:20 +0200
-Subject: [PATCH 06/18] Change to GC_IS_RECURSIVE for PHP 7.3
-
----
- v8js_convert.cc | 4 ++++
- v8js_exceptions.cc | 4 ++++
- v8js_object_export.cc | 6 ++++++
- 3 files changed, 14 insertions(+)
-
-diff --git a/v8js_convert.cc b/v8js_convert.cc
-index 056e31b..4091cf0 100644
---- a/v8js_convert.cc
-+++ b/v8js_convert.cc
-@@ -70,7 +70,11 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate
- v8::Local<v8::Array> newarr;
-
- /* Prevent recursion */
-+#if PHP_VERSION_ID >= 70300
-+ if (myht && GC_IS_RECURSIVE(myht)) {
-+#else
- if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) {
-+#endif
- return V8JS_NULL;
- }
-
-diff --git a/v8js_exceptions.cc b/v8js_exceptions.cc
-index 42fe7b1..967cae8 100644
---- a/v8js_exceptions.cc
-+++ b/v8js_exceptions.cc
-@@ -88,7 +88,11 @@ void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8::
-
- zend_class_entry *exception_ce = zend_exception_get_default();
- if (instanceof_function(php_exception->ce, exception_ce)) {
-+#ifdef GC_ADDREF
-+ GC_ADDREF(php_exception);
-+#else
- ++GC_REFCOUNT(php_exception);
-+#endif
- zend_exception_set_previous(Z_OBJ_P(return_value), php_exception);
- }
- }
-diff --git a/v8js_object_export.cc b/v8js_object_export.cc
-index 4d61e76..85bd701 100644
---- a/v8js_object_export.cc
-+++ b/v8js_object_export.cc
-@@ -137,7 +137,9 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, v
-
- zend_try {
- /* zend_fcall_info_cache */
-+#if PHP_VERSION_ID < 70300
- fcc.initialized = 1;
-+#endif
- fcc.function_handler = method_ptr;
- fcc.calling_scope = object->ce;
- fcc.called_scope = object->ce;
-@@ -1013,7 +1015,11 @@ v8::Local<v8::Value> v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate) /* {{
- }
-
- /* Prevent recursion */
-+#if PHP_VERSION_ID >= 70300
-+ if (myht && GC_IS_RECURSIVE(myht)) {
-+#else
- if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) {
-+#endif
- return V8JS_NULL;
- }
-
-
-From 0c2b55d8028cbdc603a84136a883edee277fed99 Mon Sep 17 00:00:00 2001
-From: Jan-E <github@ehrhardt.nl>
-Date: Thu, 5 Jul 2018 11:41:32 +0200
-Subject: [PATCH 07/18] Add GC_(UN)PROTECT_RECURSION, move (un)protecting
- outside loops
-
----
- php_v8js_macros.h | 11 +++++++++++
- v8js_convert.cc | 27 ++++++++++++++++-----------
- v8js_object_export.cc | 29 +++++++++++++++++------------
- 3 files changed, 44 insertions(+), 23 deletions(-)
-
-diff --git a/php_v8js_macros.h b/php_v8js_macros.h
-index e95ca55..2503663 100644
---- a/php_v8js_macros.h
-+++ b/php_v8js_macros.h
-@@ -166,6 +166,17 @@ extern struct _v8js_process_globals v8js_process_globals;
- /* Register builtin methods into passed object */
- void v8js_register_methods(v8::Local<v8::ObjectTemplate>, v8js_ctx *c);
-
-+#ifdef ZEND_HASH_INC_APPLY_COUNT
-+#ifndef GC_PROTECT_RECURSION
-+# define GC_PROTECT_RECURSION(ht) ZEND_HASH_INC_APPLY_COUNT(ht)
-+#endif
-+#endif
-+#ifdef ZEND_HASH_DEC_APPLY_COUNT
-+#ifndef GC_UNPROTECT_RECURSION
-+# define GC_UNPROTECT_RECURSION(ht) ZEND_HASH_DEC_APPLY_COUNT(ht)
-+#endif
-+#endif
-+
- #endif /* PHP_V8JS_MACROS_H */
-
- /*
-diff --git a/v8js_convert.cc b/v8js_convert.cc
-index 4091cf0..b701154 100644
---- a/v8js_convert.cc
-+++ b/v8js_convert.cc
-@@ -84,21 +84,26 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate
- {
- zval *data;
- ulong index = 0;
-- HashTable *tmp_ht;
-
-- ZEND_HASH_FOREACH_VAL(myht, data) {
-- tmp_ht = HASH_OF(data);
--
-- if (tmp_ht) {
-- ZEND_HASH_INC_APPLY_COUNT(myht);
-- }
-+#if PHP_VERSION_ID >= 70300
-+ if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
-+#else
-+ if (myht) {
-+#endif
-+ GC_PROTECT_RECURSION(myht);
-+ }
-
-+ ZEND_HASH_FOREACH_VAL(myht, data) {
- newarr->Set(index++, zval_to_v8js(data, isolate));
--
-- if (tmp_ht) {
-- ZEND_HASH_DEC_APPLY_COUNT(myht);
-- }
- } ZEND_HASH_FOREACH_END();
-+
-+#if PHP_VERSION_ID >= 70300
-+ if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
-+#else
-+ if (myht) {
-+#endif
-+ GC_UNPROTECT_RECURSION(myht);
-+ }
- }
- return newarr;
- }
-diff --git a/v8js_object_export.cc b/v8js_object_export.cc
-index 85bd701..3568871 100644
---- a/v8js_object_export.cc
-+++ b/v8js_object_export.cc
-@@ -955,21 +955,20 @@ static v8::Local<v8::Object> v8js_wrap_array_to_object(v8::Isolate *isolate, zva
- if (i > 0)
- {
- zval *data;
-- HashTable *tmp_ht;
-
-- ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, data) {
-- tmp_ht = HASH_OF(data);
-+#if PHP_VERSION_ID >= 70300
-+ if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
-+#else
-+ if (myht) {
-+#endif
-+ GC_PROTECT_RECURSION(myht);
-+ }
-
-- if (tmp_ht) {
-- ZEND_HASH_INC_APPLY_COUNT(tmp_ht);
-- }
-+ ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, data) {
-
- if (key) {
- if (ZSTR_VAL(key)[0] == '\0' && Z_TYPE_P(value) == IS_OBJECT) {
- /* Skip protected and private members. */
-- if (tmp_ht) {
-- ZEND_HASH_DEC_APPLY_COUNT(tmp_ht);
-- }
- continue;
- }
-
-@@ -991,10 +990,16 @@ static v8::Local<v8::Object> v8js_wrap_array_to_object(v8::Isolate *isolate, zva
- newobj->Set(static_cast<uint32_t>(index), zval_to_v8js(data, isolate));
- }
-
-- if (tmp_ht) {
-- ZEND_HASH_DEC_APPLY_COUNT(tmp_ht);
-- }
- } ZEND_HASH_FOREACH_END();
-+
-+#if PHP_VERSION_ID >= 70300
-+ if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
-+#else
-+ if (myht) {
-+#endif
-+ GC_UNPROTECT_RECURSION(myht);
-+ }
-+
- }
-
- return newobj;
-
-From c87ddb8ebf9b249663f32b9e94b6fad698b3e2c1 Mon Sep 17 00:00:00 2001
-From: Jan-E <github@ehrhardt.nl>
-Date: Thu, 5 Jul 2018 11:45:03 +0200
-Subject: [PATCH 08/18] Fix tests for added method
- DateTime::createFromImmutable()
-
----
- tests/var_dump.phpt | 5 +-
- tests/var_dump_73.phpt | 322 +++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 326 insertions(+), 1 deletion(-)
- create mode 100644 tests/var_dump_73.phpt
-
-diff --git a/tests/var_dump.phpt b/tests/var_dump.phpt
-index 9ce0896..7a5d7d8 100644
---- a/tests/var_dump.phpt
-+++ b/tests/var_dump.phpt
-@@ -1,7 +1,10 @@
- --TEST--
- Test V8::executeString() : var_dump
- --SKIPIF--
--<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
-+<?php
-+require_once(dirname(__FILE__) . '/skipif.inc');
-+if (PHP_VERSION_ID >= 70300) die('skip Only for php version < 7.3');
-+?>
- --INI--
- date.timezone=UTC
- --FILE--
-diff --git a/tests/var_dump_73.phpt b/tests/var_dump_73.phpt
-new file mode 100644
-index 0000000..553febb
---- /dev/null
-+++ b/tests/var_dump_73.phpt
-@@ -0,0 +1,322 @@
-+--TEST--
-+Test V8::executeString() : var_dump
-+--SKIPIF--
-+<?php
-+require_once(dirname(__FILE__) . '/skipif.inc');
-+if (PHP_VERSION_ID < 70300) die('skip Only for php version >= 7.3');
-+?>
-+--INI--
-+date.timezone=UTC
-+--FILE--
-+<?php
-+# Test var_dump of various types
-+
-+$JS = <<< EOT
-+
-+print("--- JS var_dump of PHP object ----\\n");
-+var_dump(PHP.phptypes);
-+
-+print("--- JS var_dump of JS object ----\\n");
-+var types = {
-+ undefined: undefined,
-+ null: null,
-+ bool: true,
-+ string: "string",
-+ uint: 1,
-+ int: -1,
-+ number: 3.141592654,
-+ // XXX this gets parsed with local timezone,
-+ // which is bad for test repeatability.
-+ //date: new Date('September 27, 1976 09:00:00 GMT'),
-+ regexp: /regexp/,
-+ array: [1,2,3],
-+ object: { field: "foo" },
-+ function: function id(x) { return x; },
-+ phpobject: PHP.obj
-+};
-+
-+var_dump(types);
-+print("--- PHP var_dump of JS object ----\\n");
-+types;
-+EOT;
-+
-+class Foo {
-+ var $field = "php";
-+}
-+
-+$v8 = new V8Js();
-+$v8->obj = new Foo;
-+
-+$phptypes = $v8->phptypes = array(
-+ "null" => NULL,
-+ "bool" => true,
-+ "string" => "string",
-+ "uint" => 1,
-+ "int" => -1,
-+ "number" => 3.141592654,
-+ "date" => new DateTime('September 27, 1976 09:00:00 UTC', new DateTimeZone('UTC')),
-+ //"regexp" => new Regexp('/regexp/'), /* no native PHP regex type */
-+ "array" => array(1,2,3),
-+ "object" => array( "field" => "foo" ),
-+ "function" => (function ($x) { return $x; }),
-+ "phpobject" => new Foo
-+);
-+
-+echo "---- PHP var_dump of PHP object ----\n";
-+var_dump($phptypes);
-+
-+try {
-+ var_dump($v8->executeString($JS, 'var_dump.js'));
-+} catch (V8JsScriptException $e) {
-+ echo "Error!\n";
-+ var_dump($e);
-+}
-+?>
-+===EOF===
-+--EXPECTF--
-+---- PHP var_dump of PHP object ----
-+array(11) {
-+ ["null"]=>
-+ NULL
-+ ["bool"]=>
-+ bool(true)
-+ ["string"]=>
-+ string(6) "string"
-+ ["uint"]=>
-+ int(1)
-+ ["int"]=>
-+ int(-1)
-+ ["number"]=>
-+ float(3.141592654)
-+ ["date"]=>
-+ object(DateTime)#%d (3) {
-+ ["date"]=>
-+ string(%d) "1976-09-27 09:00:00%r(\.0+)?%r"
-+ ["timezone_type"]=>
-+ int(3)
-+ ["timezone"]=>
-+ string(3) "UTC"
-+ }
-+ ["array"]=>
-+ array(3) {
-+ [0]=>
-+ int(1)
-+ [1]=>
-+ int(2)
-+ [2]=>
-+ int(3)
-+ }
-+ ["object"]=>
-+ array(1) {
-+ ["field"]=>
-+ string(3) "foo"
-+ }
-+ ["function"]=>
-+ object(Closure)#%d (1) {
-+ ["parameter"]=>
-+ array(1) {
-+ ["$x"]=>
-+ string(10) "<required>"
-+ }
-+ }
-+ ["phpobject"]=>
-+ object(Foo)#%d (1) {
-+ ["field"]=>
-+ string(3) "php"
-+ }
-+}
-+--- JS var_dump of PHP object ----
-+array (11) {
-+ ["null"] =>
-+ NULL
-+ ["bool"] =>
-+ bool(true)
-+ ["string"] =>
-+ string(6) "string"
-+ ["uint"] =>
-+ int(1)
-+ ["int"] =>
-+ int(-1)
-+ ["number"] =>
-+ float(3.141593)
-+ ["date"] =>
-+ object(DateTime)#%d (19) {
-+ ["createFromImmutable"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["createFromFormat"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["getLastErrors"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["format"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["modify"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["add"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["sub"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["getTimezone"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["setTimezone"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["getOffset"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["setTime"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["setDate"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["setISODate"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["setTimestamp"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["getTimestamp"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["diff"] =>
-+ object(Closure)#%d {
-+ function () { [native code] }
-+ }
-+ ["$date"] =>
-+ string(%d) "1976-09-27 09:00:00%r(\.0+)?%r"
-+ ["$timezone_type"] =>
-+ int(3)
-+ ["$timezone"] =>
-+ string(3) "UTC"
-+ }
-+ ["array"] =>
-+ array(3) {
-+ [0] =>
-+ int(1)
-+ [1] =>
-+ int(2)
-+ [2] =>
-+ int(3)
-+ }
-+ ["object"] =>
-+ array (1) {
-+ ["field"] =>
-+ string(3) "foo"
-+ }
-+ ["function"] =>
-+ object(Closure)#%d (0) {
-+ }
-+ ["phpobject"] =>
-+ object(Foo)#%d (1) {
-+ ["$field"] =>
-+ string(3) "php"
-+ }
-+}
-+--- JS var_dump of JS object ----
-+object(Object)#%d (12) {
-+ ["undefined"] =>
-+ NULL
-+ ["null"] =>
-+ NULL
-+ ["bool"] =>
-+ bool(true)
-+ ["string"] =>
-+ string(6) "string"
-+ ["uint"] =>
-+ int(1)
-+ ["int"] =>
-+ int(-1)
-+ ["number"] =>
-+ float(3.141593)
-+ ["regexp"] =>
-+ regexp(/regexp/)
-+ ["array"] =>
-+ array(3) {
-+ [0] =>
-+ int(1)
-+ [1] =>
-+ int(2)
-+ [2] =>
-+ int(3)
-+ }
-+ ["object"] =>
-+ object(Object)#%d (1) {
-+ ["field"] =>
-+ string(3) "foo"
-+ }
-+ ["function"] =>
-+ object(Closure)#%d {
-+ function id(x) { return x; }
-+ }
-+ ["phpobject"] =>
-+ object(Foo)#%d (1) {
-+ ["$field"] =>
-+ string(3) "php"
-+ }
-+}
-+--- PHP var_dump of JS object ----
-+object(V8Object)#%d (12) {
-+ ["undefined"]=>
-+ NULL
-+ ["null"]=>
-+ NULL
-+ ["bool"]=>
-+ bool(true)
-+ ["string"]=>
-+ string(6) "string"
-+ ["uint"]=>
-+ int(1)
-+ ["int"]=>
-+ int(-1)
-+ ["number"]=>
-+ float(3.141592654)
-+ ["regexp"]=>
-+ object(V8Object)#%d (0) {
-+ }
-+ ["array"]=>
-+ array(3) {
-+ [0]=>
-+ int(1)
-+ [1]=>
-+ int(2)
-+ [2]=>
-+ int(3)
-+ }
-+ ["object"]=>
-+ object(V8Object)#%d (1) {
-+ ["field"]=>
-+ string(3) "foo"
-+ }
-+ ["function"]=>
-+ object(V8Function)#%d (0) {
-+ }
-+ ["phpobject"]=>
-+ object(Foo)#%d (1) {
-+ ["field"]=>
-+ string(3) "php"
-+ }
-+}
-+===EOF===
-
-From 61f98e2a4a01ae429390768e92c7af1cb2418f4d Mon Sep 17 00:00:00 2001
-From: Jan-E <github@ehrhardt.nl>
-Date: Sat, 7 Jul 2018 05:18:31 +0200
-Subject: [PATCH 11/18] extensions_error.phpt runs fine on Windows
-
----
- tests/extensions_error.phpt | 6 ------
- 1 file changed, 6 deletions(-)
-
-diff --git a/tests/extensions_error.phpt b/tests/extensions_error.phpt
-index f59b0b7..b11054a 100644
---- a/tests/extensions_error.phpt
-+++ b/tests/extensions_error.phpt
-@@ -9,12 +9,6 @@ phpinfo(INFO_MODULES);
- $minfo = ob_get_contents();
- ob_end_clean();
-
--if(strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
-- // On Windows the "Fatal error" happens to appear before the error
-- // message output by V8 itself.
-- echo "skip Windows";
--}
--
- if(preg_match("/V8 Engine Linked Version => (.*)/", $minfo, $matches)) {
- $version = explode('.', $matches[1]);
- if($version[0] < 5 || ($version[0] == 5 && $version[1] < 7)) {
-
-From 4762dd1f0ae799add559f18307032d697b05497e Mon Sep 17 00:00:00 2001
-From: Stefan Siegl <stesie@brokenpipe.de>
-Date: Fri, 13 Jul 2018 14:21:45 +0200
-Subject: [PATCH 13/18] fix null-ptr deref
-
----
- v8js_class.cc | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
-
-diff --git a/v8js_class.cc b/v8js_class.cc
-index 8f66f7c..524e55e 100644
---- a/v8js_class.cc
-+++ b/v8js_class.cc
-@@ -273,9 +273,14 @@ static void v8js_jsext_free_storage(v8js_jsext *jsext) /* {{{ */
- v8js_free_ext_strarr(jsext->deps, jsext->deps_count);
- }
- delete jsext->extension;
-+
- // Free the persisted non-interned strings we allocated.
-- zend_string_release(jsext->name);
-- zend_string_release(jsext->source);
-+ if (jsext->name) {
-+ zend_string_release(jsext->name);
-+ }
-+ if (jsext->source) {
-+ zend_string_release(jsext->source);
-+ }
-
- free(jsext);
- }
-
-From 90b6b31f06a7ff990c462d6ec012b28c54a31faf Mon Sep 17 00:00:00 2001
-From: Stefan Siegl <stesie@brokenpipe.de>
-Date: Fri, 13 Jul 2018 15:41:41 +0200
-Subject: [PATCH 14/18] break recursion immediately on PHP <= 7.2 as well
-
----
- tests/array_recursive.phpt | 25 +++++++++++++++++++++++++
- v8js_convert.cc | 15 +++++++++------
- 2 files changed, 34 insertions(+), 6 deletions(-)
- create mode 100644 tests/array_recursive.phpt
-
-diff --git a/tests/array_recursive.phpt b/tests/array_recursive.phpt
-new file mode 100644
-index 0000000..47df7ea
---- /dev/null
-+++ b/tests/array_recursive.phpt
-@@ -0,0 +1,25 @@
-+--TEST--
-+Test V8::executeString() : export of recursive array
-+--SKIPIF--
-+<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
-+--FILE--
-+<?php
-+
-+$a = [];
-+$a[] = &$a;
-+$a[] = 23;
-+
-+$v8 = new V8Js();
-+$v8->foo = $a;
-+$v8->executeString('var_dump(PHP.foo);');
-+
-+?>
-+===EOF===
-+--EXPECT--
-+array(2) {
-+ [0] =>
-+ NULL
-+ [1] =>
-+ int(23)
-+}
-+===EOF===
-diff --git a/v8js_convert.cc b/v8js_convert.cc
-index b701154..3f91dd1 100644
---- a/v8js_convert.cc
-+++ b/v8js_convert.cc
-@@ -71,10 +71,11 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate
-
- /* Prevent recursion */
- #if PHP_VERSION_ID >= 70300
-- if (myht && GC_IS_RECURSIVE(myht)) {
-+ if (myht && GC_IS_RECURSIVE(myht))
- #else
-- if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) {
-+ if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 0)
- #endif
-+ {
- return V8JS_NULL;
- }
-
-@@ -86,10 +87,11 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate
- ulong index = 0;
-
- #if PHP_VERSION_ID >= 70300
-- if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
-+ if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE))
- #else
-- if (myht) {
-+ if (myht)
- #endif
-+ {
- GC_PROTECT_RECURSION(myht);
- }
-
-@@ -98,10 +100,11 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate
- } ZEND_HASH_FOREACH_END();
-
- #if PHP_VERSION_ID >= 70300
-- if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
-+ if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE))
- #else
-- if (myht) {
-+ if (myht)
- #endif
-+ {
- GC_UNPROTECT_RECURSION(myht);
- }
- }
-
-From 18b79d90046a63209cedf58ef24e2f4f0281f7a1 Mon Sep 17 00:00:00 2001
-From: Stefan Siegl <stesie@brokenpipe.de>
-Date: Wed, 18 Jul 2018 23:36:13 +0200
-Subject: [PATCH 18/18] don't free interned strings, only persistent ones
-
----
- v8js_class.cc | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/v8js_class.cc b/v8js_class.cc
-index a9cda70..9f67992 100644
---- a/v8js_class.cc
-+++ b/v8js_class.cc
-@@ -991,7 +991,10 @@ static void v8js_persistent_zval_ctor(zval *p) /* {{{ */
- static void v8js_persistent_zval_dtor(zval *p) /* {{{ */
- {
- assert(Z_TYPE_P(p) == IS_STRING);
-- free(Z_STR_P(p));
-+
-+ if (!ZSTR_IS_INTERNED(Z_STR_P(p))) {
-+ free(Z_STR_P(p));
-+ }
- }
- /* }}} */
-