mirror of
https://github.com/phpv8/v8js.git
synced 2024-12-22 14:01:53 +00:00
Adapt to new v8::Persistent API, support V8 >= 3.21.12
This commit is contained in:
parent
1c4d9817dc
commit
619231913c
@ -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
|
||||
```
|
||||
|
@ -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
101
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::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)));
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user