浏览代码

Adapt to new v8::Persistent API, support V8 >= 3.21.12

Stefan Siegl 11 年之前
父节点
当前提交
619231913c
共有 5 个文件被更改,包括 97 次插入52 次删除
  1. 2 2
      README.md
  2. 2 3
      config.m4
  3. 64 35
      v8js.cc
  4. 28 11
      v8js_convert.cc
  5. 1 1
      v8js_methods.cc

+ 2 - 2
README.md

@@ -14,7 +14,7 @@ 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, hence the need for 3.17.11 or above. (See <https://github.com/preillyme/v8js/issues/12>.)
+    This extension makes use of V8 isolates to ensure separation between multiple V8Js instances and already uses the new persistence API, hence the need for 3.21.12 or above.
 
 - PHP 5.3.3+
 
@@ -51,7 +51,7 @@ cd /tmp
 git clone https://github.com/preillyme/v8js.git
 cd v8js
 phpize
-./configure CXXFLAGS="-DV8_USE_UNSAFE_HANDLES=1"
+./configure
 make
 sudo make install
 ```

+ 2 - 3
config.m4

@@ -67,9 +67,8 @@ CPPFLAGS=$old_CPPFLAGS
     set $ac_cv_v8_version
     IFS=$ac_IFS
     V8_API_VERSION=`expr [$]1 \* 1000000 + [$]2 \* 1000 + [$]3`
-    if test "$V8_API_VERSION" -lt 3017011 ; then
-       # see https://github.com/preillyme/v8js/issues/12
-       AC_MSG_ERROR([libv8 must be version 3.17.11 or greater])
+    if test "$V8_API_VERSION" -lt 3021012 ; then
+       AC_MSG_ERROR([libv8 must be version 3.21.12 or greater])
     fi
     AC_DEFINE_UNQUOTED([PHP_V8_API_VERSION], $V8_API_VERSION, [ ])
     AC_DEFINE_UNQUOTED([PHP_V8_VERSION], "$ac_cv_v8_version", [ ])

+ 64 - 35
v8js.cc

@@ -116,15 +116,18 @@ static zval *php_v8js_v8_read_property(zval *object, zval *member, int type ZEND
 	zval *retval = NULL;
 	php_v8js_object *obj = (php_v8js_object *) zend_object_store_get_object(object TSRMLS_CC);
 
-	if (Z_TYPE_P(member) == IS_STRING && obj->v8obj->IsObject() && !obj->v8obj->IsFunction())
+	v8::Locker locker(obj->isolate);
+	v8::Isolate::Scope isolate_scope(obj->isolate);
+	v8::HandleScope local_scope(obj->isolate);
+	v8::Local<v8::Context> temp_context = v8::Context::New(obj->isolate);
+	v8::Context::Scope temp_scope(temp_context);
+
+	v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(obj->isolate, obj->v8obj);
+
+	if (Z_TYPE_P(member) == IS_STRING && v8obj->IsObject() && !v8obj->IsFunction())
 	{
-		v8::Locker locker(obj->isolate);
-		v8::Isolate::Scope isolate_scope(obj->isolate);
-		v8::HandleScope local_scope(obj->isolate);
-		v8::Local<v8::Context> temp_context = v8::Context::New(obj->isolate);
-		v8::Context::Scope temp_scope(temp_context);
 
-		v8::Local<v8::Object> jsObj = obj->v8obj->ToObject();
+		v8::Local<v8::Object> jsObj = v8obj->ToObject();
 		v8::Local<v8::String> jsKey = V8JS_STRL(Z_STRVAL_P(member), Z_STRLEN_P(member));
 		v8::Local<v8::Value> jsVal;
 
@@ -155,8 +158,16 @@ static void php_v8js_v8_write_property(zval *object, zval *member, zval *value Z
 {
 	php_v8js_object *obj = (php_v8js_object *) zend_object_store_get_object(object TSRMLS_CC);
 
-	if (obj->v8obj->IsObject() && !obj->v8obj->IsFunction()) {
-		obj->v8obj->ToObject()->ForceSet(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)), zval_to_v8js(value, obj->isolate TSRMLS_CC));
+	v8::Locker locker(obj->isolate);
+	v8::Isolate::Scope isolate_scope(obj->isolate);
+	v8::HandleScope local_scope(obj->isolate);
+	v8::Local<v8::Context> temp_context = v8::Context::New(obj->isolate);
+	v8::Context::Scope temp_scope(temp_context);
+
+	v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(obj->isolate, obj->v8obj);
+
+	if (v8obj->IsObject() && !v8obj->IsFunction()) {
+		v8obj->ToObject()->ForceSet(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)), zval_to_v8js(value, obj->isolate TSRMLS_CC));
 	}
 }
 /* }}} */
@@ -165,8 +176,16 @@ static void php_v8js_v8_unset_property(zval *object, zval *member ZEND_HASH_KEY_
 {
 	php_v8js_object *obj = (php_v8js_object *) zend_object_store_get_object(object TSRMLS_CC);
 
-	if (obj->v8obj->IsObject() && !obj->v8obj->IsFunction()) {
-		obj->v8obj->ToObject()->ForceDelete(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)));
+	v8::Locker locker(obj->isolate);
+	v8::Isolate::Scope isolate_scope(obj->isolate);
+	v8::HandleScope local_scope(obj->isolate);
+	v8::Local<v8::Context> temp_context = v8::Context::New(obj->isolate);
+	v8::Context::Scope temp_scope(temp_context);
+
+	v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(obj->isolate, obj->v8obj);
+
+	if (v8obj->IsObject() && !v8obj->IsFunction()) {
+		v8obj->ToObject()->ForceDelete(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)));
 	}
 }
 /* }}} */
@@ -224,8 +243,9 @@ static HashTable *php_v8js_v8_get_properties(zval *object TSRMLS_DC) /* {{{ */
 	v8::HandleScope local_scope(obj->isolate);
 	v8::Local<v8::Context> temp_context = v8::Context::New(obj->isolate);
 	v8::Context::Scope temp_scope(temp_context);
+	v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(obj->isolate, obj->v8obj);
 
-	if (php_v8js_v8_get_properties_hash(obj->v8obj, retval, obj->flags, obj->isolate TSRMLS_CC) == SUCCESS) {
+	if (php_v8js_v8_get_properties_hash(v8obj, retval, obj->flags, obj->isolate TSRMLS_CC) == SUCCESS) {
 		return retval;
 	}
 
@@ -251,9 +271,10 @@ static zend_function *php_v8js_v8_get_method(zval **object_ptr, char *method, in
 	v8::Local<v8::Context> temp_context = v8::Context::New(obj->isolate);
 	v8::Context::Scope temp_scope(temp_context);
 	v8::Local<v8::String> jsKey = V8JS_STRL(method, method_len);
+	v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(obj->isolate, obj->v8obj);
 
-	if (!obj->v8obj.IsEmpty() && obj->v8obj->IsObject() && !obj->v8obj->IsFunction()) {
-		v8::Local<v8::Object> jsObj = obj->v8obj->ToObject();
+	if (!obj->v8obj.IsEmpty() && v8obj->IsObject() && !v8obj->IsFunction()) {
+		v8::Local<v8::Object> jsObj = v8obj->ToObject();
 		
 		if (jsObj->Has(jsKey) && jsObj->Get(jsKey)->IsFunction()) {
 			f = (zend_function *) ecalloc(1, sizeof(*f));
@@ -296,7 +317,7 @@ static int php_v8js_v8_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) /
 	v8::Context::Scope temp_scope(temp_context);
 
 	v8::Local<v8::String> method_name = V8JS_SYML(method, strlen(method));
-	v8::Local<v8::Object> v8obj = obj->v8obj->ToObject();
+	v8::Local<v8::Object> v8obj = v8::Local<v8::Value>::New(obj->isolate, obj->v8obj)->ToObject();
 	v8::Local<v8::Function> cb;
 
 	if (method_name->Equals(V8JS_SYM(V8JS_V8_INVOKE_FUNC_NAME))) {
@@ -309,7 +330,7 @@ static int php_v8js_v8_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) /
 	v8::Local<v8::Value> js_retval;
 
 	for (i = 0; i < argc; i++) {
-		jsArgv[i] = v8::Local<v8::Value>::New(zval_to_v8js(*argv[i], obj->isolate TSRMLS_CC));
+		jsArgv[i] = v8::Local<v8::Value>::New(obj->isolate, zval_to_v8js(*argv[i], obj->isolate TSRMLS_CC));
 	}
 
 	js_retval = cb->Call(V8JS_GLOBAL, argc, jsArgv);
@@ -334,7 +355,14 @@ static int php_v8js_v8_get_closure(zval *object, zend_class_entry **ce_ptr, zend
 
 	php_v8js_object *obj = (php_v8js_object *) zend_object_store_get_object(object TSRMLS_CC);
 
-	if (!obj->v8obj->IsFunction()) {
+	v8::Locker locker(obj->isolate);
+	v8::Isolate::Scope isolate_scope(obj->isolate);
+	v8::HandleScope local_scope(obj->isolate);
+	v8::Local<v8::Context> temp_context = v8::Context::New(obj->isolate);
+	v8::Context::Scope temp_scope(temp_context);
+	v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(obj->isolate, obj->v8obj);
+
+	if (!v8obj->IsFunction()) {
 		return FAILURE;
 	}
 
@@ -392,7 +420,7 @@ void php_v8js_create_v8(zval *res, v8::Handle<v8::Value> value, int flags, v8::I
 
 	c = (php_v8js_object *) zend_object_store_get_object(res TSRMLS_CC);
 
-	c->v8obj = v8::Persistent<v8::Value>::New(isolate, value);
+	c->v8obj.Reset(isolate, value);
 	c->flags = flags;
 	c->isolate = isolate;
 }
@@ -555,6 +583,7 @@ static PHP_METHOD(V8Js, __construct)
 	c->pending_exception = NULL;
 	c->in_execution = 0;
 	c->isolate = v8::Isolate::New();
+	c->isolate->SetData(c);
 	c->time_limit_hit = false;
 	c->memory_limit_hit = false;
 	c->module_loader = NULL;
@@ -590,15 +619,17 @@ static PHP_METHOD(V8Js, __construct)
 	/* Create global template for global object */
 	// Now we are using multiple isolates this needs to be created for every context
 
-	c->global_template = v8::Persistent<v8::FunctionTemplate>::New(c->isolate, v8::FunctionTemplate::New());
-	c->global_template->SetClassName(V8JS_SYM("V8Js"));
+	v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New();
+	tpl->SetClassName(V8JS_SYM("V8Js"));
+	c->global_template.Reset(c->isolate, tpl);
 
 	/* Register builtin methods */
-	php_v8js_register_methods(c->global_template->InstanceTemplate(), c);
+	php_v8js_register_methods(tpl->InstanceTemplate(), c);
 
 	/* Create context */
-	c->context = v8::Persistent<v8::Context>::New(c->isolate, v8::Context::New(c->isolate, &extension_conf, c->global_template->InstanceTemplate()));
-	c->context->SetAlignedPointerInEmbedderData(1, c);
+	v8::Local<v8::Context> context = v8::Context::New(c->isolate, &extension_conf, tpl->InstanceTemplate());
+	context->SetAlignedPointerInEmbedderData(1, c);
+	c->context.Reset(c->isolate, context);
 
 	if (exts) {
 		_php_v8js_free_ext_strarr(exts, exts_count);
@@ -612,7 +643,7 @@ static PHP_METHOD(V8Js, __construct)
 	}
 
 	/* Enter context */
-	v8::Context::Scope context_scope(c->context);
+	v8::Context::Scope context_scope(context);
 
 	/* Create the PHP container object's function template */
 	v8::Local<v8::FunctionTemplate> php_obj_t = v8::FunctionTemplate::New();
@@ -635,10 +666,11 @@ static PHP_METHOD(V8Js, __construct)
 	}
 
 	/* Set name for the PHP JS object */
-	c->object_name = v8::Persistent<v8::String>::New(c->isolate, (object_name_len) ? V8JS_SYML(object_name, object_name_len) : V8JS_SYM("PHP"));
+	v8::Local<v8::String> object_name_js = (object_name_len) ? V8JS_SYML(object_name, object_name_len) : V8JS_SYM("PHP");
+	c->object_name.Reset(c->isolate, object_name_js);
 
 	/* Add the PHP object into global object */
-	V8JS_GLOBAL->Set(c->object_name, php_obj_t->InstanceTemplate()->NewInstance(), v8::ReadOnly);
+	V8JS_GLOBAL->Set(object_name_js, php_obj_t->InstanceTemplate()->NewInstance(), v8::ReadOnly);
 }
 /* }}} */
 
@@ -653,7 +685,8 @@ static PHP_METHOD(V8Js, __construct)
 	(ctx) = (php_v8js_ctx *) zend_object_store_get_object(object TSRMLS_CC); \
 	v8::Locker locker((ctx)->isolate); \
 	v8::Isolate::Scope isolate_scope((ctx)->isolate); \
-	v8::Context::Scope context_scope((ctx)->context);
+	v8::HandleScope handle_scope((ctx)->isolate); \
+	v8::Context::Scope context_scope((ctx)->isolate, (ctx)->context);
 
 static void php_v8js_timer_push(long time_limit, long memory_limit, php_v8js_ctx *c TSRMLS_DC)
 {
@@ -762,8 +795,6 @@ static PHP_METHOD(V8Js, executeString)
 	/* Catch JS exceptions */
 	v8::TryCatch try_catch;
 
-	v8::HandleScope handle_scope(c->isolate);
-
 	/* Set script identifier */
 	v8::Local<v8::String> sname = identifier_len ? V8JS_SYML(identifier, identifier_len) : V8JS_SYM("V8Js::executeString()");
 
@@ -1089,10 +1120,9 @@ static void php_v8js_write_property(zval *object, zval *member, zval *value ZEND
 {
 	V8JS_BEGIN_CTX(c, object)
 
-	v8::HandleScope handle_scope(c->isolate);
-
 	/* Global PHP JS object */
-	v8::Local<v8::Object> jsobj = V8JS_GLOBAL->Get(c->object_name)->ToObject();
+	v8::Local<v8::String> object_name_js = v8::Local<v8::String>::New(c->isolate, c->object_name);
+	v8::Local<v8::Object> jsobj = V8JS_GLOBAL->Get(object_name_js)->ToObject();
 
 	/* Write value to PHP JS object */
 	jsobj->ForceSet(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)), zval_to_v8js(value, c->isolate TSRMLS_CC), v8::ReadOnly);
@@ -1106,10 +1136,9 @@ static void php_v8js_unset_property(zval *object, zval *member ZEND_HASH_KEY_DC
 {
 	V8JS_BEGIN_CTX(c, object)
 
-	v8::HandleScope handle_scope(c->isolate);
-
 	/* Global PHP JS object */
-	v8::Local<v8::Object> jsobj = V8JS_GLOBAL->Get(c->object_name)->ToObject();
+	v8::Local<v8::String> object_name_js = v8::Local<v8::String>::New(c->isolate, c->object_name);
+	v8::Local<v8::Object> jsobj = V8JS_GLOBAL->Get(object_name_js)->ToObject();
 	
 	/* Delete value from PHP JS object */
 	jsobj->ForceDelete(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)));

+ 28 - 11
v8js_convert.cc

@@ -26,11 +26,25 @@ extern "C" {
 
 #include "php_v8js_macros.h"
 #include <v8.h>
-#include <map>
 #include <stdexcept>
 
-typedef std::pair<v8::Isolate *, const char *> TemplateCacheKey;
-typedef std::map<TemplateCacheKey, v8::Persistent<v8::FunctionTemplate> > TemplateCache;
+namespace v8 {
+	template<class T>
+	struct CopyablePersistentTraits {
+		typedef Persistent<T, CopyablePersistentTraits<T> > CopyablePersistent;
+		static const bool kResetInDestructor = true;
+		template<class S, class M>
+		V8_INLINE(static void Copy(const Persistent<S, M>& source,
+								   CopyablePersistent* dest)) {
+			// do nothing, just allow copy
+		}
+	};
+}
+
+
+typedef std::pair<struct php_v8js_ctx *, const char *> TemplateCacheKey;
+typedef v8::Persistent<v8::FunctionTemplate, v8::CopyablePersistentTraits<v8::FunctionTemplate> > TemplateCacheEntry;
+typedef std::map<TemplateCacheKey, TemplateCacheEntry> TemplateCache;
 
 /* Callback for PHP methods and functions */
 static void php_v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function *method_ptr, v8::Isolate *isolate, const v8::FunctionCallbackInfo<v8::Value>& info) /* {{{ */
@@ -373,14 +387,18 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
 	/* Object methods */
 	if (ce == php_ce_v8_function) {
 		php_v8js_object *c = (php_v8js_object *) zend_object_store_get_object(value TSRMLS_CC);
-		return c->v8obj;
+		v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(isolate, c->v8obj);
+
+		return v8obj;
 	} else if (ce) {
-		v8::Handle<v8::FunctionTemplate> new_tpl;
+		php_v8js_ctx *ctx = (php_v8js_ctx *) isolate->GetData();
+		v8::Local<v8::FunctionTemplate> new_tpl;
 		bool cached_tpl = true;
 		static TemplateCache tpl_map;
 
 		try {
-			new_tpl = tpl_map.at(std::make_pair(isolate, ce->name));
+			new_tpl = v8::Local<v8::FunctionTemplate>::New
+				(isolate, tpl_map.at(std::make_pair(ctx, ce->name)));
 		}
 		catch (const std::out_of_range &) {
 			cached_tpl = false;
@@ -399,8 +417,8 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
 				new_tpl->InstanceTemplate()->SetCallAsFunctionHandler(php_v8js_php_callback);
 			} else {
 				/* Add new v8::FunctionTemplate to tpl_map, as long as it is not a closure. */
-				tpl_map[std::make_pair(isolate, ce->name)] =
-					v8::Persistent<v8::FunctionTemplate>::New(isolate, new_tpl);
+				TemplateCacheEntry tce(isolate, new_tpl);
+				tpl_map[std::make_pair(ctx, ce->name)] = tce;
 			}
 		}
 
@@ -477,15 +495,14 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
 		// decides to dispose the JS object, we add a weak persistent handle and register
 		// a callback function that removes the reference.
 		v8::Handle<v8::Value> external = v8::External::New(value);
-		v8::Persistent<v8::Object> persist_newobj = v8::Persistent<v8::Object>::New
-			(isolate, new_tpl->GetFunction()->NewInstance(1, &external));
+		v8::Persistent<v8::Object> persist_newobj(isolate, new_tpl->GetFunction()->NewInstance(1, &external));
 		persist_newobj.MakeWeak(value, php_v8js_weak_object_callback);
 
 		// 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)
 		v8::V8::AdjustAmountOfExternalAllocatedMemory(1024);
 
-		newobj = persist_newobj;
+		newobj = v8::Local<v8::Object>::New(isolate, persist_newobj);
 
 		if (ce != zend_ce_closure) {
 			// These unfortunately cannot be attached to the template, hence we have to put them

+ 1 - 1
v8js_methods.cc

@@ -270,7 +270,7 @@ V8JS_METHOD(require)
 	global->Set(v8::String::New("module"), module);
 
 	// Each module gets its own context so different modules do not affect each other
-	v8::Persistent<v8::Context> context = v8::Persistent<v8::Context>::New(c->isolate, v8::Context::New(c->isolate, NULL, global));
+	v8::Local<v8::Context> context = v8::Local<v8::Context>::New(c->isolate, v8::Context::New(c->isolate, NULL, global));
 
 	// Catch JS exceptions
 	v8::TryCatch try_catch;