diff options
| -rw-r--r-- | v8js-upstream.patch | 1022 | 
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(¶ms[0], c->modules_base.back()); -+				ZVAL_STRING(¶ms[0], module_base_cstr); - 				ZVAL_STRING(¶ms[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)); -+	} - } - /* }}} */ -   | 
