0
0
mirror of https://github.com/phpv8/v8js.git synced 2024-11-09 15:18:41 +00:00

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

This commit is contained in:
Stefan Siegl 2013-10-03 16:27:04 +02:00
parent 1c4d9817dc
commit 619231913c
5 changed files with 98 additions and 53 deletions

View File

@ -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
```

View File

@ -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", [ ])

101
v8js.cc
View File

@ -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::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::Value> v8obj = v8::Local<v8::Value>::New(obj->isolate, obj->v8obj);
if (Z_TYPE_P(member) == IS_STRING && v8obj->IsObject() && !v8obj->IsFunction())
{
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)));

View File

@ -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

View File

@ -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;