diff --git a/config.m4 b/config.m4 index 81d7318..852eb9f 100644 --- a/config.m4 +++ b/config.m4 @@ -187,6 +187,7 @@ if test "$PHP_V8" != "no"; then v8.cc \ src/php_v8_a.cc \ src/php_v8_exception.cc \ + src/php_v8_ext_mem_interface.cc \ src/php_v8_try_catch.cc \ src/php_v8_message.cc \ src/php_v8_stack_frame.cc \ diff --git a/php_v8.h b/php_v8.h index cceb6ed..e90deeb 100644 --- a/php_v8.h +++ b/php_v8.h @@ -69,8 +69,7 @@ ZEND_TSRMLS_CACHE_EXTERN(); ZEND_EXTERN_MODULE_GLOBALS(v8); -#endif /* PHP_V8_H */ - +#endif //PHP_V8_H /* * Local variables: diff --git a/src/php_v8_callbacks.cc b/src/php_v8_callbacks.cc index 0b2c75f..298e814 100644 --- a/src/php_v8_callbacks.cc +++ b/src/php_v8_callbacks.cc @@ -31,218 +31,171 @@ #include "php_v8_value.h" #include "php_v8_isolate.h" +#include +#include +namespace phpv8 { -php_v8_callbacks_bucket_t *php_v8_callback_create_bucket(size_t size) { + Callback::Callback(zend_fcall_info fci, zend_fcall_info_cache fci_cache) : fci_(fci), fci_cache_(fci_cache) { + if (fci_.size) { + Z_ADDREF(fci_.function_name); - assert (size > 0); - - php_v8_callbacks_bucket_t *bucket; - - bucket = (php_v8_callbacks_bucket_t *) ecalloc(1, sizeof(*bucket)); - - bucket->size = size; - bucket->cb = (php_v8_callback_t **) ecalloc(size, sizeof(*bucket->cb)); - - return bucket; -} - - -void php_v8_callback_cleanup_bucket(php_v8_callbacks_bucket_t *bucket, size_t index) { - assert(bucket->size >= index); - - if (bucket->cb[index] == NULL) { - return; - } - - if (bucket->cb[index]->fci.size) { - zval_ptr_dtor(&bucket->cb[index]->fci.function_name); - - if (!Z_ISUNDEF(bucket->cb[index]->object)) { - zval_ptr_dtor(&bucket->cb[index]->object); + if (fci_.object) { + ZVAL_OBJ(&object_, fci_.object); + Z_ADDREF(object_); + } else { + ZVAL_UNDEF(&object_); + } } } - efree(bucket->cb[index]); - bucket->cb[index] = NULL; -} + Callback::~Callback() { + if (fci_.size) { + zval_ptr_dtor(&fci_.function_name); -void php_v8_callback_destroy_bucket(php_v8_callbacks_bucket_t *bucket) { - for (size_t i = 0; i < bucket->size; i++) { - php_v8_callback_cleanup_bucket(bucket, i); + if (!Z_ISUNDEF(object_)) { + zval_ptr_dtor(&object_); + } + } } - efree(bucket->cb); - efree(bucket); -} - -php_v8_callbacks_bucket_t *php_v8_callback_get_or_create_bucket(size_t size, const char *prefix, bool is_symbol, const char *name, php_v8_callbacks_t *callbacks) { - char *internal_name; - - spprintf(&internal_name, 0, "%s%s%s", prefix, (is_symbol ? "sym_" : "str_"), name); + int Callback::getGcCount() { + int size = 0; - php_v8_callbacks_t::iterator it = callbacks->find(internal_name); + if (fci_.size) { + size += 1; - if (it != callbacks->end()) { - efree(internal_name); + if (!Z_ISUNDEF(object_)) { + size += 1; + } + } - return it->second; + return size; } - php_v8_callbacks_bucket_t *bucket = php_v8_callback_create_bucket(size); - - (*callbacks)[internal_name] = bucket; + void Callback::collectGcZvals(zval *&zv) { + if (fci_.size) { + ZVAL_COPY_VALUE(zv++, &fci_.function_name); - return bucket; -} - -void php_v8_callbacks_copy_bucket(php_v8_callbacks_bucket_t *from, php_v8_callbacks_bucket_t *to) { - for (size_t i = 0; i < from->size; i++) { - if (from->cb[i]) { - php_v8_callback_add(i, from->cb[i]->fci, from->cb[i]->fci_cache, to); + if (!Z_ISUNDEF(object_)) { + ZVAL_COPY_VALUE(zv++, &object_); + } } } -} - - -php_v8_callback_t *php_v8_callback_add(size_t index, zend_fcall_info fci, zend_fcall_info_cache fci_cache, php_v8_callbacks_bucket_t *bucket) { - assert(bucket->size >= index); - - php_v8_callback_cleanup_bucket(bucket, index); - php_v8_callback_t *callback = (php_v8_callback_t *) ecalloc(1, sizeof(*callback)); + void CallbacksBucket::reset(CallbacksBucket *bucket) { + callbacks.clear(); - callback->fci = fci; - callback->fci_cache = fci_cache; - - if (fci.size) { - Z_ADDREF(callback->fci.function_name); - - if (fci.object) { - ZVAL_OBJ(&callback->object, fci.object); - Z_ADDREF(callback->object); + for (auto const &item : bucket->callbacks) { + callbacks[item.first] = item.second; } } - bucket->cb[index] = callback; + phpv8::Callback *CallbacksBucket::get(size_t index) { + auto it = callbacks.find(index); - return callback; -} + if (it != callbacks.end()) { + return it->second.get(); + } -void php_v8_callbacks_cleanup(php_v8_callbacks_t *callbacks) { - if (callbacks == NULL) { - return; + return NULL; } - for (php_v8_callbacks_t::iterator it = callbacks->begin(); it != callbacks->end(); ++it) { - php_v8_callback_destroy_bucket(it->second); - efree(it->first); + void CallbacksBucket::add(size_t index, zend_fcall_info fci, zend_fcall_info_cache fci_cache) { + callbacks[index] = std::make_shared(fci, fci_cache); } -} -void php_v8_callbacks_gc(php_v8_callbacks_t *callbacks, zval **gc_data, int * gc_data_count, zval **table, int *n) { + int CallbacksBucket::getGcCount() { + int size = 0; - int size = php_v8_weak_callbacks_get_count(callbacks); + for (auto const &item : callbacks) { + size += item.second->getGcCount(); + } - if (*gc_data_count < size) { - *gc_data = (zval *)safe_erealloc(*gc_data, size, sizeof(zval), 0); + return size; } - *gc_data_count = size; - - zval *local_gc_data = *gc_data; - - php_v8_weak_callbacks_get_zvals(callbacks, local_gc_data); - - *table = *gc_data; - *n = *gc_data_count; -} + void CallbacksBucket::collectGcZvals(zval *&zv) { + for (auto const &item : callbacks) { + item.second->collectGcZvals(zv); + } + } + int PersistentData::getGcCount() { + int size = 0; -int php_v8_callback_get_callback_count(php_v8_callback_t *cb) { - int size = 0; + for (auto const &item : buckets) { + size += item.second->getGcCount(); + } - if (!cb) { return size; } - if (cb->fci.size) { - size += 1; - - if (!Z_ISUNDEF(cb->object)) { - size += 1; + void PersistentData::collectGcZvals(zval *&zv) { + for (auto const &item : buckets) { + item.second->collectGcZvals(zv); } } - return size; -} + CallbacksBucket *PersistentData::bucket(const char *prefix, bool is_symbol, const char *name) { + char *internal_name; -int php_v8_callback_get_bucket_count(php_v8_callbacks_bucket_t *bucket) { - int size = 0; + size_t size = spprintf(&internal_name, 0, "%s%s%s", prefix, (is_symbol ? "sym_" : "str_"), name); - if (!bucket) { - return size; - } + std::string str_name(internal_name, size); + efree(internal_name); - for (size_t i = 0; i < bucket->size; i++) { - size += php_v8_callback_get_callback_count(bucket->cb[i]); - } + auto it = buckets.find(str_name); - return size; -} + if (it != buckets.end()) { + return it->second.get(); + } -int php_v8_weak_callbacks_get_count(php_v8_callbacks_t *callbacks) { - int size = 0; + auto bucket = std::make_shared(); + buckets[str_name] = bucket; - if (callbacks == NULL || callbacks->empty()) { - return size; + return bucket.get(); } - for (auto it = callbacks->begin(); it != callbacks->end(); ++it) { - size += php_v8_callback_get_bucket_count(it->second); - } + int64_t PersistentData::calculateSize() { + int64_t size = sizeof(*this); - return size; -} + for (auto const &item : buckets) { + size += sizeof(std::shared_ptr); + size += item.first.capacity(); + size += item.second->calculateSize(); + } -void php_v8_callback_get_callback_zvals(php_v8_callback_t *cb, zval *& zv) { - if (!cb) { - return; + return size; } - if (cb->fci.size) { - ZVAL_COPY_VALUE(zv++, &cb->fci.function_name); - - if (!Z_ISUNDEF(cb->object)) { - ZVAL_COPY_VALUE(zv++, &cb->object); - } + int64_t PersistentData::adjustSize(int64_t change_in_bytes) { + adjusted_size_ = std::max(static_cast(0), adjusted_size_ + change_in_bytes); + return adjusted_size_; } } +void php_v8_callbacks_gc(phpv8::PersistentData *data, zval **gc_data, int * gc_data_count, zval **table, int *n) { -void php_v8_callback_get_bucket_zvals(php_v8_callbacks_bucket_t *bucket, zval *& zv) { - if (!bucket) { - return; - } + int size = data->getGcCount(); - for (size_t i = 0; i < bucket->size; i++) { - php_v8_callback_get_callback_zvals(bucket->cb[i], zv); + if (*gc_data_count < size) { + *gc_data = (zval *)safe_erealloc(*gc_data, size, sizeof(zval), 0); } -} -void php_v8_weak_callbacks_get_zvals(php_v8_callbacks_t *callbacks, zval *& zv) { - if (callbacks == NULL) { - return; - } + *gc_data_count = size; - for (php_v8_callbacks_t::iterator it = callbacks->begin(); it != callbacks->end(); ++it) { - php_v8_callback_get_bucket_zvals(it->second, zv); - } + zval *local_gc_data = *gc_data; + + data->collectGcZvals(local_gc_data); + + *table = *gc_data; + *n = *gc_data_count; } -void php_v8_bucket_gc(php_v8_callbacks_bucket_t *bucket, zval **gc_data, int * gc_data_count, zval **table, int *n) { +void php_v8_bucket_gc(phpv8::CallbacksBucket *bucket, zval **gc_data, int * gc_data_count, zval **table, int *n) { - int size = php_v8_callback_get_bucket_count(bucket); + int size = bucket->getGcCount(); if (*gc_data_count < size) { *gc_data = (zval *)safe_erealloc(*gc_data, size, sizeof(zval), 0); @@ -252,7 +205,7 @@ void php_v8_bucket_gc(php_v8_callbacks_bucket_t *bucket, zval **gc_data, int * g zval *local_gc_data = *gc_data; - php_v8_callback_get_bucket_zvals(bucket, local_gc_data); + bucket->collectGcZvals(local_gc_data); *table = *gc_data; *n = *gc_data_count; @@ -285,20 +238,25 @@ static inline void php_v8_callback_set_retval_from_callback_info(v8::ReturnValue void php_v8_callback_call_from_bucket_with_zargs(size_t index, v8::Local data, zval *args, zval *retval) { - php_v8_callbacks_bucket_t *bucket; + phpv8::CallbacksBucket *bucket; if (data.IsEmpty() || !data->IsExternal()) { PHP_V8_THROW_EXCEPTION("Callback has no stored callback function"); return; } - bucket = static_cast(v8::Local::Cast(data)->Value()); - assert(bucket->size > index); + bucket = static_cast(v8::Local::Cast(data)->Value()); - php_v8_callback_t *cb = bucket->cb[index]; + phpv8::Callback *cb = bucket->get(index); + + // highly unlikely, but to play safe + if (!cb) { + PHP_V8_THROW_EXCEPTION("Callback has no stored callback function"); + return; + } - zend_fcall_info fci = cb->fci; - zend_fcall_info_cache fci_cache = cb->fci_cache; + zend_fcall_info fci = cb->fci(); + zend_fcall_info_cache fci_cache = cb->fci_cache(); /* Convert everything to be callable */ zend_fcall_info_args(&fci, args); diff --git a/src/php_v8_callbacks.h b/src/php_v8_callbacks.h index b2ade83..1f83e6a 100644 --- a/src/php_v8_callbacks.h +++ b/src/php_v8_callbacks.h @@ -15,8 +15,19 @@ #ifndef PHP_V8_CALLBACKS_H #define PHP_V8_CALLBACKS_H +namespace phpv8 { + class Callback; + class CallbacksBucket; + class PersistentData; + template class PersistentCollection; +} + + #include +#include #include +#include +#include extern "C" { #include "php.h" @@ -26,30 +37,10 @@ extern "C" { #endif } -typedef struct _php_v8_callback_t php_v8_callback_t; -typedef struct _php_v8_callbacks_bucket_t php_v8_callbacks_bucket_t; - -struct cmp_str; -typedef std::map php_v8_callbacks_t; - -extern php_v8_callbacks_bucket_t *php_v8_callback_create_bucket(size_t size); -extern void php_v8_callback_destroy_bucket(php_v8_callbacks_bucket_t *bucket); +extern void php_v8_callbacks_gc(phpv8::PersistentData *data, zval **gc_data, int * gc_data_count, zval **table, int *n); -extern php_v8_callbacks_bucket_t *php_v8_callback_get_or_create_bucket(size_t size, - const char *prefix, - bool is_symbol, - const char *name, - php_v8_callbacks_t *callbacks); - -extern void php_v8_callbacks_copy_bucket(php_v8_callbacks_bucket_t *from, php_v8_callbacks_bucket_t *to); -extern php_v8_callback_t *php_v8_callback_add(size_t index, zend_fcall_info fci, zend_fcall_info_cache fci_cache, php_v8_callbacks_bucket_t *bucket); -extern void php_v8_callbacks_cleanup(php_v8_callbacks_t *callbacks); - -extern void php_v8_callbacks_gc(php_v8_callbacks_t *callbacks, zval **gc_data, int * gc_data_count, zval **table, int *n); -extern int php_v8_weak_callbacks_get_count(php_v8_callbacks_t *callbacks); -extern void php_v8_weak_callbacks_get_zvals(php_v8_callbacks_t *callbacks, zval *& zv); -extern void php_v8_bucket_gc(php_v8_callbacks_bucket_t *bucket, zval **gc_data, int * gc_data_count, zval **table, int *n); +extern void php_v8_bucket_gc(phpv8::CallbacksBucket *bucket, zval **gc_data, int * gc_data_count, zval **table, int *n); extern void php_v8_callback_function(const v8::FunctionCallbackInfo& info); extern void php_v8_callback_accessor_name_getter(v8::Local property, const v8::PropertyCallbackInfo& info); @@ -69,23 +60,153 @@ extern void php_v8_callback_indexed_property_enumerator(const v8::PropertyCallba extern bool php_v8_callback_access_check(v8::Local accessing_context, v8::Local accessed_object, v8::Local data); +//#define PHP_V8_DEBUG_EXTERNAL_MEM 1 + +#ifdef PHP_V8_DEBUG_EXTERNAL_MEM +#define php_v8_debug_external_mem(format, ...) fprintf(stderr, (format), ##__VA_ARGS__); +#else +#define php_v8_debug_external_mem(format, ...) +#endif -struct _php_v8_callback_t { - zval object; - zend_fcall_info fci; - zend_fcall_info_cache fci_cache; -}; +namespace phpv8 { -struct _php_v8_callbacks_bucket_t { - size_t size; - php_v8_callback_t **cb; -}; + class Callback { + public: + Callback(zend_fcall_info fci, zend_fcall_info_cache fci_cache); + ~Callback(); + int getGcCount(); + void collectGcZvals(zval *& zv); + + inline zend_fcall_info fci() { + return fci_; + } + + inline zend_fcall_info_cache fci_cache() { + return fci_cache_; + } + + private: + zval object_; + zend_fcall_info fci_; + zend_fcall_info_cache fci_cache_; + }; + + + class CallbacksBucket { + public: + phpv8::Callback *get(size_t index); + void reset(CallbacksBucket *bucket); + + void add(size_t index, zend_fcall_info fci, zend_fcall_info_cache fci_cache); + int getGcCount(); + + void collectGcZvals(zval *& zv); + + inline bool empty() { + return callbacks.empty(); + } + + inline int64_t calculateSize() { + return sizeof(*this) + (sizeof(std::shared_ptr) + sizeof(Callback)) * callbacks.size(); + } + + private: + std::map> callbacks; + }; + + + class PersistentData { + public: + int getGcCount(); + void collectGcZvals(zval *& zv); + CallbacksBucket *bucket(const char *prefix, bool is_symbol, const char *name); + + inline CallbacksBucket *bucket(const char *name) { + return bucket("", false, name); + } + + inline bool empty() { + return buckets.empty(); + } + + inline int64_t getTotalSize() { + if (!size_) { + // TODO: if adjusted_size_ is going to be much larger than estimated calculateSize() value, + // we can ignore calculateSize() without loosing idea to notify v8 about + // significant external memory pressure + size_ = calculateSize() + adjusted_size_; + + if (size_ < 0) { + size_ = std::numeric_limits::max(); + } + } + + return size_; + } + + inline int64_t getAdjustedSize() { + return adjusted_size_; + } + + int64_t adjustSize(int64_t change_in_bytes); + + protected: + int64_t calculateSize(); + private: + int64_t size_; + int64_t adjusted_size_; + std::map> buckets; + }; + + + template + class PersistentCollection { + public: + ~PersistentCollection() { + for (auto const &item : collection) { + item.first->Reset(); + delete item.first; + } + } + + int getGcCount() { + int size = 0; + + for (auto const &item : collection) { + size += item.second->getGcCount(); + } + + return size; + } + + void collectGcZvals(zval *& zv) { + for (auto const &item : collection) { + item.second->collectGcZvals(zv); + } + } + + void add(v8::Persistent *persistent, phpv8::PersistentData *data) { + collection[persistent] = std::shared_ptr(data); + } + + phpv8::PersistentData *get(v8::Persistent *persistent) { + auto it = collection.find(persistent); + + if (it != collection.end()) { + return it->second.get(); + } + + return nullptr; + } + + void remove(v8::Persistent> *persistent) { + collection.erase(persistent); + } + private: + std::map *, std::shared_ptr> collection; + }; +} -struct cmp_str { - bool operator()(char const *a, char const *b) const { - return strcmp(a, b) < 0; - } -}; #endif //PHP_V8_CALLBACKS_H diff --git a/src/php_v8_exceptions.cc b/src/php_v8_exceptions.cc index f000526..858f373 100644 --- a/src/php_v8_exceptions.cc +++ b/src/php_v8_exceptions.cc @@ -231,9 +231,9 @@ PHP_MINIT_FUNCTION(php_v8_exceptions) { INIT_NS_CLASS_ENTRY(ce, PHP_V8_NS "\\Exceptions", "TryCatchException", php_v8_try_catch_exception_methods); php_v8_try_catch_exception_class_entry = zend_register_internal_class_ex(&ce, php_v8_generic_exception_class_entry); - zend_declare_property_null(php_v8_try_catch_exception_class_entry, ZEND_STRL("isolate"), ZEND_ACC_PRIVATE); - zend_declare_property_null(php_v8_try_catch_exception_class_entry, ZEND_STRL("context"), ZEND_ACC_PRIVATE); - zend_declare_property_null(php_v8_try_catch_exception_class_entry, ZEND_STRL("try_catch"), ZEND_ACC_PRIVATE); + zend_declare_property_null(php_v8_try_catch_exception_class_entry, ZEND_STRL("isolate"), ZEND_ACC_PRIVATE); + zend_declare_property_null(php_v8_try_catch_exception_class_entry, ZEND_STRL("context"), ZEND_ACC_PRIVATE); + zend_declare_property_null(php_v8_try_catch_exception_class_entry, ZEND_STRL("try_catch"), ZEND_ACC_PRIVATE); INIT_NS_CLASS_ENTRY(ce, PHP_V8_NS "\\Exceptions", "TerminationException", php_v8_termination_exception_methods); diff --git a/src/php_v8_ext_mem_interface.cc b/src/php_v8_ext_mem_interface.cc new file mode 100644 index 0000000..aed2673 --- /dev/null +++ b/src/php_v8_ext_mem_interface.cc @@ -0,0 +1,130 @@ +/* + +----------------------------------------------------------------------+ + | This file is part of the pinepain/php-v8 PHP extension. | + | | + | Copyright (c) 2015-2016 Bogdan Padalko | + | | + | Licensed under the MIT license: http://opensource.org/licenses/MIT | + | | + | For the full copyright and license information, please view the | + | LICENSE file that was distributed with this source or visit | + | http://opensource.org/licenses/MIT | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php_v8_ext_mem_interface.h" +#include "php_v8_object_template.h" +#include "php_v8_function_template.h" +#include "php_v8_value.h" +#include "php_v8.h" + +zend_class_entry *php_v8_ext_mem_interface_ce; +#define this_ce php_v8_ext_mem_interface_ce + +void php_v8_ext_mem_interface_value_AdjustExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS) { + zend_long change_in_bytes; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &change_in_bytes) == FAILURE) { + return; + } + + PHP_V8_VALUE_FETCH_INTO(getThis(), php_v8_value); + + RETURN_LONG(php_v8_value->persistent_data->adjustSize(change_in_bytes)); +} + +void php_v8_ext_mem_interface_value_GetExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS) { + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + PHP_V8_VALUE_FETCH_INTO(getThis(), php_v8_value); + + RETURN_LONG(php_v8_value->persistent_data->getAdjustedSize()); +} + + +void php_v8_ext_mem_interface_function_template_AdjustExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS) { + zend_long change_in_bytes; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &change_in_bytes) == FAILURE) { + return; + } + + PHP_V8_OBJECT_TEMPLATE_FETCH_INTO(getThis(), php_v8_object_template); + + RETURN_LONG(php_v8_object_template->persistent_data->adjustSize(change_in_bytes)); +} + +void php_v8_ext_mem_interface_function_template_GetExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS) { + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + PHP_V8_OBJECT_TEMPLATE_FETCH_INTO(getThis(), php_v8_object_template); + + RETURN_LONG(php_v8_object_template->persistent_data->getAdjustedSize()); +} + + +void php_v8_ext_mem_interface_object_template_AdjustExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS) { + zend_long change_in_bytes; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &change_in_bytes) == FAILURE) { + return; + } + + PHP_V8_FUNCTION_TEMPLATE_FETCH_INTO(getThis(), php_v8_function_template); + + RETURN_LONG(php_v8_function_template->persistent_data->adjustSize(change_in_bytes)); +} + +void php_v8_ext_mem_interface_object_template_GetExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS) { + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + PHP_V8_FUNCTION_TEMPLATE_FETCH_INTO(getThis(), php_v8_function_template); + + RETURN_LONG(php_v8_function_template->persistent_data->getAdjustedSize()); +} + + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_php_v8_ext_mem_interface_AdjustExternalAllocatedMemory, ZEND_RETURN_VALUE, 1, IS_LONG, NULL, 0) + ZEND_ARG_TYPE_INFO(0, change_in_bytes, IS_LONG, 0) +ZEND_END_ARG_INFO() + + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_php_v8_ext_mem_interface_GetExternalAllocatedMemory, ZEND_RETURN_VALUE, 0, IS_LONG, NULL, 0) +ZEND_END_ARG_INFO() + + +static const zend_function_entry php_v8_ext_mem_interface_methods[] = { + PHP_ABSTRACT_ME(V8AdjustableExternalMemoryInterface, AdjustExternalAllocatedMemory, arginfo_php_v8_ext_mem_interface_AdjustExternalAllocatedMemory) + PHP_ABSTRACT_ME(V8AdjustableExternalMemoryInterface, GetExternalAllocatedMemory, arginfo_php_v8_ext_mem_interface_GetExternalAllocatedMemory) + + PHP_FE_END +}; + +PHP_MINIT_FUNCTION (php_v8_ext_mem_interface) { + zend_class_entry ce; + + INIT_NS_CLASS_ENTRY(ce, PHP_V8_NS, "AdjustableExternalMemoryInterface", php_v8_ext_mem_interface_methods); + this_ce = zend_register_internal_interface(&ce); + + return SUCCESS; +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/src/php_v8_ext_mem_interface.h b/src/php_v8_ext_mem_interface.h new file mode 100644 index 0000000..c3b9abb --- /dev/null +++ b/src/php_v8_ext_mem_interface.h @@ -0,0 +1,51 @@ +/* + +----------------------------------------------------------------------+ + | This file is part of the pinepain/php-v8 PHP extension. | + | | + | Copyright (c) 2015-2016 Bogdan Padalko | + | | + | Licensed under the MIT license: http://opensource.org/licenses/MIT | + | | + | For the full copyright and license information, please view the | + | LICENSE file that was distributed with this source or visit | + | http://opensource.org/licenses/MIT | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_V8_EXT_MEM_INTERFACE_H +#define PHP_V8_EXT_MEM_INTERFACE_H + + +extern "C" { +#include "php.h" + +#ifdef ZTS +#include "TSRM.h" +#endif +} + + +extern zend_class_entry* php_v8_ext_mem_interface_ce; + + +extern void php_v8_ext_mem_interface_value_AdjustExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS); +extern void php_v8_ext_mem_interface_value_GetExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS); + +extern void php_v8_ext_mem_interface_function_template_AdjustExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS); +extern void php_v8_ext_mem_interface_function_template_GetExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS); + +extern void php_v8_ext_mem_interface_object_template_AdjustExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS); +extern void php_v8_ext_mem_interface_object_template_GetExternalAllocatedMemory(INTERNAL_FUNCTION_PARAMETERS); + +PHP_MINIT_FUNCTION(php_v8_ext_mem_interface); + +#endif //PHP_V8_EXT_MEM_INTERFACE_H + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/src/php_v8_function.cc b/src/php_v8_function.cc index 71d36c0..6cc3e7e 100644 --- a/src/php_v8_function.cc +++ b/src/php_v8_function.cc @@ -146,10 +146,10 @@ static PHP_METHOD(V8Function, __construct) { PHP_V8_ENTER_STORED_CONTEXT(php_v8_value); if (fci.size) { - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(1, "", false, "callback", php_v8_value->callbacks); + phpv8::CallbacksBucket *bucket = php_v8_value->persistent_data->bucket("callback"); data = v8::External::New(isolate, bucket); - php_v8_callback_add(0, fci, fci_cache, bucket); + bucket->add(0, fci, fci_cache); callback = php_v8_callback_function; } diff --git a/src/php_v8_function_template.cc b/src/php_v8_function_template.cc index 02895bd..4ba3009 100644 --- a/src/php_v8_function_template.cc +++ b/src/php_v8_function_template.cc @@ -23,6 +23,7 @@ #include "php_v8_object.h" #include "php_v8_value.h" #include "php_v8_context.h" +#include "php_v8_ext_mem_interface.h" #include "php_v8.h" zend_class_entry *php_v8_function_template_class_entry; @@ -42,33 +43,35 @@ static void php_v8_function_template_weak_callback(const v8::WeakCallbackInfoweak_function_templates)[data.GetParameter()]; - php_v8_isolate->weak_function_templates->erase(data.GetParameter()); - php_v8_callbacks_cleanup(callbacks); + phpv8::PersistentData *persistent_data = php_v8_isolate->weak_function_templates->get(data.GetParameter()); - data.GetParameter()->Reset(); + if (persistent_data != nullptr) { + // Tell v8 that we release external allocated memory + php_v8_debug_external_mem("Free allocated external memory (func tpl: %p): -%" PRId64 "\n", persistent_data, persistent_data->getTotalSize()) + isolate->AdjustAmountOfExternalAllocatedMemory(-persistent_data->getTotalSize()); + php_v8_isolate->weak_function_templates->remove(data.GetParameter()); + } - delete callbacks; + data.GetParameter()->Reset(); delete data.GetParameter(); - - // Tell v8 that we release external allocated memory - isolate->AdjustAmountOfExternalAllocatedMemory(-1024 * 1024 * 1024); } void php_v8_function_template_make_weak(php_v8_function_template_t *php_v8_function_template) { - (*php_v8_function_template->php_v8_isolate->weak_function_templates)[php_v8_function_template->persistent] = php_v8_function_template->callbacks; + php_v8_function_template->php_v8_isolate->weak_function_templates->add(php_v8_function_template->persistent, php_v8_function_template->persistent_data); php_v8_function_template->is_weak = true; php_v8_function_template->persistent->SetWeak(php_v8_function_template->persistent, php_v8_function_template_weak_callback, v8::WeakCallbackType::kParameter); - php_v8_function_template->php_v8_isolate->isolate->AdjustAmountOfExternalAllocatedMemory(1024 * 1024 * 1024); + // Tell v8 that we allocated external memory + php_v8_debug_external_mem("Allocate external memory (func tpl: %p): %" PRId64 "\n", php_v8_function_template->persistent_data, php_v8_function_template->persistent_data->getTotalSize()) + php_v8_function_template->php_v8_isolate->isolate->AdjustAmountOfExternalAllocatedMemory(php_v8_function_template->persistent_data->getTotalSize()); } static HashTable *php_v8_function_template_gc(zval *object, zval **table, int *n) { PHP_V8_FUNCTION_TEMPLATE_FETCH_INTO(object, php_v8_function_template); - php_v8_callbacks_gc(php_v8_function_template->callbacks, &php_v8_function_template->gc_data, &php_v8_function_template->gc_data_count, table, n); + php_v8_callbacks_gc(php_v8_function_template->persistent_data, &php_v8_function_template->gc_data, &php_v8_function_template->gc_data_count, table, n); return zend_std_get_properties(object); } @@ -85,14 +88,13 @@ static void php_v8_function_template_free(zend_object *object) { * unmarked as week? Note, that the only action on weak handler callback is Reset()ing persistent handler. * * */ - if (!CG(unclean_shutdown) && php_v8_function_template->callbacks && !php_v8_function_template->callbacks->empty()) { + if (zend_is_executing() && !CG(unclean_shutdown) && php_v8_function_template->persistent_data && !php_v8_function_template->persistent_data->empty()) { php_v8_function_template_make_weak(php_v8_function_template); } if (!php_v8_function_template->is_weak) { - if (php_v8_function_template->callbacks) { - php_v8_callbacks_cleanup(php_v8_function_template->callbacks); - delete php_v8_function_template->callbacks; + if (php_v8_function_template->persistent_data) { + delete php_v8_function_template->persistent_data; } if (php_v8_function_template->persistent) { @@ -122,7 +124,7 @@ static zend_object * php_v8_function_template_ctor(zend_class_entry *ce) { object_properties_init(&php_v8_function_template->std, ce); php_v8_function_template->persistent = new v8::Persistent(); - php_v8_function_template->callbacks = new php_v8_callbacks_t(); + php_v8_function_template->persistent_data = new phpv8::PersistentData(); php_v8_function_template->node = new phpv8::TemplateNode(); @@ -160,10 +162,10 @@ static PHP_METHOD(V8FunctionTemplate, __construct) { PHP_V8_ENTER_ISOLATE(php_v8_isolate); if (fci.size) { - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(1, "", false, "callback", php_v8_function_template->callbacks); + phpv8::CallbacksBucket *bucket= php_v8_function_template->persistent_data->bucket("callback"); data = v8::External::New(isolate, bucket); - php_v8_callback_add(0, fci, fci_cache, bucket); + bucket->add(0, fci, fci_cache); callback = php_v8_callback_function; } @@ -250,8 +252,8 @@ static PHP_METHOD(V8FunctionTemplate, SetCallHandler) { PHP_V8_FETCH_FUNCTION_TEMPLATE_WITH_CHECK(getThis(), php_v8_function_template); PHP_V8_ENTER_STORED_ISOLATE(php_v8_function_template); - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(1, "", false, "callback", php_v8_function_template->callbacks); - php_v8_callback_add(0, fci, fci_cache, bucket); + phpv8::CallbacksBucket *bucket= php_v8_function_template->persistent_data->bucket("callback"); + bucket->add(0, fci, fci_cache); v8::Local local_template = php_v8_function_template_get_local(isolate, php_v8_function_template); @@ -436,6 +438,16 @@ static PHP_METHOD(V8FunctionTemplate, HasInstance) { RETURN_BOOL(local_template->HasInstance(local_obj)); } +/* Non-standard, implementations of AdjustableExternalMemoryInterface::AdjustExternalAllocatedMemory */ +static PHP_METHOD(V8FunctionTemplate, AdjustExternalAllocatedMemory) { + php_v8_ext_mem_interface_function_template_AdjustExternalAllocatedMemory(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +/* Non-standard, implementations of AdjustableExternalMemoryInterface::GetExternalAllocatedMemory */ +static PHP_METHOD(V8FunctionTemplate, GetExternalAllocatedMemory) { + php_v8_ext_mem_interface_function_template_GetExternalAllocatedMemory(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + ZEND_BEGIN_ARG_INFO_EX(arginfo_v8_function_template___construct, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1) ZEND_ARG_OBJ_INFO(0, isolate, V8\\Isolate, 0) @@ -524,6 +536,14 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_function_template_HasInstance ZEND_ARG_OBJ_INFO(0, object, V8\\ObjectValue, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_function_template_AdjustExternalAllocatedMemory, ZEND_RETURN_VALUE, 1, IS_LONG, NULL, 0) + ZEND_ARG_TYPE_INFO(0, change_in_bytes, IS_LONG, 0) +ZEND_END_ARG_INFO() + + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_function_template_GetExternalAllocatedMemory, ZEND_RETURN_VALUE, 0, IS_LONG, NULL, 0) +ZEND_END_ARG_INFO() + static const zend_function_entry php_v8_function_template_methods[] = { PHP_ME(V8FunctionTemplate, __construct, arginfo_v8_function_template___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) @@ -546,6 +566,9 @@ static const zend_function_entry php_v8_function_template_methods[] = { PHP_ME(V8FunctionTemplate, RemovePrototype, arginfo_v8_function_template_RemovePrototype, ZEND_ACC_PUBLIC) PHP_ME(V8FunctionTemplate, HasInstance, arginfo_v8_function_template_HasInstance, ZEND_ACC_PUBLIC) + PHP_ME(V8FunctionTemplate, AdjustExternalAllocatedMemory, arginfo_v8_function_template_AdjustExternalAllocatedMemory, ZEND_ACC_PUBLIC) + PHP_ME(V8FunctionTemplate, GetExternalAllocatedMemory, arginfo_v8_function_template_GetExternalAllocatedMemory, ZEND_ACC_PUBLIC) + PHP_FE_END }; @@ -555,6 +578,7 @@ PHP_MINIT_FUNCTION (php_v8_function_template) { INIT_NS_CLASS_ENTRY(ce, PHP_V8_NS, "FunctionTemplate", php_v8_function_template_methods); this_ce = zend_register_internal_class_ex(&ce, php_v8_template_ce); + zend_class_implements(this_ce, 1, php_v8_ext_mem_interface_ce); this_ce->create_object = php_v8_function_template_ctor; memcpy(&php_v8_function_template_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); diff --git a/src/php_v8_function_template.h b/src/php_v8_function_template.h index cea5543..45cec3e 100644 --- a/src/php_v8_function_template.h +++ b/src/php_v8_function_template.h @@ -57,7 +57,7 @@ struct _php_v8_function_template_t { bool is_weak; v8::Persistent *persistent; - php_v8_callbacks_t *callbacks; + phpv8::PersistentData *persistent_data; zval *gc_data; int gc_data_count; diff --git a/src/php_v8_indexed_property_handler_configuration.cc b/src/php_v8_indexed_property_handler_configuration.cc index 0593748..0c069d8 100644 --- a/src/php_v8_indexed_property_handler_configuration.cc +++ b/src/php_v8_indexed_property_handler_configuration.cc @@ -42,7 +42,7 @@ static void php_v8_indexed_property_handler_configuration_free(zend_object *obje php_v8_indexed_property_handler_configuration_t *php_v8_handler = php_v8_indexed_property_handler_configuration_fetch_object(object); if (php_v8_handler->bucket) { - php_v8_callback_destroy_bucket(php_v8_handler->bucket); + delete php_v8_handler->bucket; php_v8_handler->bucket = NULL; } @@ -63,6 +63,8 @@ static zend_object * php_v8_indexed_property_handler_configuration_ctor(zend_cla zend_object_std_init(&php_v8_handler->std, ce); object_properties_init(&php_v8_handler->std, ce); + php_v8_handler->bucket = new phpv8::CallbacksBucket(); + php_v8_handler->std.handlers = &php_v8_indexed_property_handler_configuration_object_handlers; return &php_v8_handler->std; @@ -99,28 +101,26 @@ static PHP_METHOD (V8IndexedPropertyHandlerConfiguration, __construct) { PHP_V8_INDEXED_PROPERTY_HANDLER_FETCH_INTO(getThis(), php_v8_handlers); - php_v8_handlers->bucket = php_v8_callback_create_bucket(5); - - php_v8_callback_add(0, fci_getter, fci_cache_getter, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(0, fci_getter, fci_cache_getter); php_v8_handlers->getter = php_v8_callback_indexed_property_getter; if (fci_setter.size) { - php_v8_callback_add(1, fci_setter, fci_cache_setter, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(1, fci_setter, fci_cache_setter); php_v8_handlers->setter = php_v8_callback_indexed_property_setter; } if (fci_query.size) { - php_v8_callback_add(2, fci_query, fci_cache_query, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(2, fci_query, fci_cache_query); php_v8_handlers->query = php_v8_callback_indexed_property_query; } if (fci_deleter.size) { - php_v8_callback_add(3, fci_deleter, fci_cache_deleter, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(3, fci_deleter, fci_cache_deleter); php_v8_handlers->deleter = php_v8_callback_indexed_property_deleter; } if (fci_enumerator.size) { - php_v8_callback_add(4, fci_enumerator, fci_cache_enumerator, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(4, fci_enumerator, fci_cache_enumerator); php_v8_handlers->enumerator = php_v8_callback_indexed_property_enumerator; } diff --git a/src/php_v8_indexed_property_handler_configuration.h b/src/php_v8_indexed_property_handler_configuration.h index 7566e63..c105373 100644 --- a/src/php_v8_indexed_property_handler_configuration.h +++ b/src/php_v8_indexed_property_handler_configuration.h @@ -55,7 +55,8 @@ typedef struct _php_v8_indexed_property_handler_configuration_t { long flags; - php_v8_callbacks_bucket_t *bucket; + //php_v8_callbacks_bucket_t *bucket; + phpv8::CallbacksBucket *bucket; zval *gc_data; int gc_data_count; diff --git a/src/php_v8_isolate.cc b/src/php_v8_isolate.cc index 69a442e..dfc926c 100644 --- a/src/php_v8_isolate.cc +++ b/src/php_v8_isolate.cc @@ -69,47 +69,14 @@ static inline void php_v8_isolate_destroy(php_v8_isolate_t *php_v8_isolate) { } -template -static inline void php_v8_isolate_clean_weak(std::map *, php_v8_callbacks_t *> *weak) { - for (auto it = weak->begin(); it != weak->end(); ++it) { - it->first->Reset(); - delete it->first; - - php_v8_callbacks_cleanup(it->second); - delete it->second; - } -} - -template -static void php_v8_isolate_get_weak_callbacks_zval(std::map *, php_v8_callbacks_t *> *weak, zval *& zv) { - for (auto it = weak->begin(); it != weak->end(); ++it) { - php_v8_weak_callbacks_get_zvals(it->second, zv); - } -} - -template -static int php_v8_isolate_get_weak_callbacks_count(std::map *, php_v8_callbacks_t *> *weak) { - int size = 0; - - if (!weak) { - return size; - } - - for (auto it = weak->begin(); it != weak->end(); ++it) { - size += php_v8_weak_callbacks_get_count(it->second); - } - - return size; -} - static HashTable * php_v8_isolate_gc(zval *object, zval **table, int *n) { PHP_V8_ISOLATE_FETCH_INTO(object, php_v8_isolate); int size = 0; - size += php_v8_isolate_get_weak_callbacks_count(php_v8_isolate->weak_function_templates); - size += php_v8_isolate_get_weak_callbacks_count(php_v8_isolate->weak_object_templates); - size += php_v8_isolate_get_weak_callbacks_count(php_v8_isolate->weak_values); + size += php_v8_isolate->weak_function_templates->getGcCount(); + size += php_v8_isolate->weak_object_templates->getGcCount(); + size += php_v8_isolate->weak_values->getGcCount(); if (php_v8_isolate->gc_data_count < size) { php_v8_isolate->gc_data = (zval *)safe_erealloc(php_v8_isolate->gc_data, size, sizeof(zval), 0); @@ -119,9 +86,9 @@ static HashTable * php_v8_isolate_gc(zval *object, zval **table, int *n) { zval *gc_data = php_v8_isolate->gc_data; - php_v8_isolate_get_weak_callbacks_zval(php_v8_isolate->weak_function_templates, gc_data); - php_v8_isolate_get_weak_callbacks_zval(php_v8_isolate->weak_object_templates, gc_data); - php_v8_isolate_get_weak_callbacks_zval(php_v8_isolate->weak_values, gc_data); + php_v8_isolate->weak_function_templates->collectGcZvals(gc_data); + php_v8_isolate->weak_object_templates->collectGcZvals(gc_data); + php_v8_isolate->weak_values->collectGcZvals(gc_data); *table = php_v8_isolate->gc_data; *n = php_v8_isolate->gc_data_count; @@ -135,17 +102,14 @@ static void php_v8_isolate_free(zend_object *object) { php_v8_isolate_limits_free(php_v8_isolate); if (php_v8_isolate->weak_function_templates) { - php_v8_isolate_clean_weak(php_v8_isolate->weak_function_templates); delete php_v8_isolate->weak_function_templates; } if (php_v8_isolate->weak_object_templates) { - php_v8_isolate_clean_weak(php_v8_isolate->weak_object_templates); delete php_v8_isolate->weak_object_templates; } if (php_v8_isolate->weak_values) { - php_v8_isolate_clean_weak(php_v8_isolate->weak_values); delete php_v8_isolate->weak_values; } @@ -188,9 +152,9 @@ static zend_object *php_v8_isolate_ctor(zend_class_entry *ce) { php_v8_isolate->create_params = new v8::Isolate::CreateParams(); php_v8_isolate->create_params->array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); - php_v8_isolate->weak_function_templates = new std::map *, php_v8_callbacks_t *>(); - php_v8_isolate->weak_object_templates = new std::map *, php_v8_callbacks_t *>(); - php_v8_isolate->weak_values = new std::map *, php_v8_callbacks_t *>(); + php_v8_isolate->weak_function_templates = new phpv8::PersistentCollection(); + php_v8_isolate->weak_object_templates = new phpv8::PersistentCollection(); + php_v8_isolate->weak_values = new phpv8::PersistentCollection(); php_v8_isolate->std.handlers = &php_v8_isolate_object_handlers; diff --git a/src/php_v8_isolate.h b/src/php_v8_isolate.h index 48c315e..3141f65 100644 --- a/src/php_v8_isolate.h +++ b/src/php_v8_isolate.h @@ -71,13 +71,13 @@ extern php_v8_isolate_t * php_v8_isolate_fetch_object(zend_object *obj); v8::Isolate *isolate = (php_v8_isolate)->isolate; #define PHP_V8_ISOLATE_ENTER(isolate) \ - v8::Locker locker(isolate); \ - v8::Isolate::Scope isolate_scope(isolate); \ - v8::HandleScope handle_scope(isolate); + v8::Locker locker(isolate); \ + v8::Isolate::Scope isolate_scope(isolate); \ + v8::HandleScope handle_scope(isolate); #define PHP_V8_ENTER_ISOLATE(php_v8_isolate) \ - PHP_V8_DECLARE_ISOLATE(php_v8_isolate); \ - PHP_V8_ISOLATE_ENTER(isolate); \ + PHP_V8_DECLARE_ISOLATE(php_v8_isolate); \ + PHP_V8_ISOLATE_ENTER(isolate); \ #define PHP_V8_ENTER_STORED_ISOLATE(stored) PHP_V8_ENTER_ISOLATE((stored)->php_v8_isolate); @@ -121,9 +121,9 @@ struct _php_v8_isolate_t { v8::Isolate *isolate; v8::Isolate::CreateParams *create_params; - std::map*, php_v8_callbacks_t *> *weak_function_templates; - std::map*, php_v8_callbacks_t *> *weak_object_templates; - std::map*, php_v8_callbacks_t *> *weak_values; + phpv8::PersistentCollection *weak_function_templates; + phpv8::PersistentCollection *weak_object_templates; + phpv8::PersistentCollection *weak_values; uint32_t isolate_handle; php_v8_isolate_limits_t limits; diff --git a/src/php_v8_isolate_limits.cc b/src/php_v8_isolate_limits.cc index 9396b1e..3935a5f 100644 --- a/src/php_v8_isolate_limits.cc +++ b/src/php_v8_isolate_limits.cc @@ -22,8 +22,9 @@ #define PHP_V8_TIME_SLEEP_MILLISECONDS 10 //#define PHP_V8_DEBUG_EXECUTION 1 - -#define mb(sz) ((sz)/1024/1024.0) +#define one_mb (1024.0 * 1024.0) +#define kb(sz) ((sz)/1024.0) +#define mb(sz) (kb(sz)/1024.0) #define has(v, str) (v ? "has " str : "no " str) #define is(v) (v ? "yes" : "no") diff --git a/src/php_v8_named_property_handler_configuration.cc b/src/php_v8_named_property_handler_configuration.cc index 0f2beaf..de65aa6 100644 --- a/src/php_v8_named_property_handler_configuration.cc +++ b/src/php_v8_named_property_handler_configuration.cc @@ -41,7 +41,7 @@ static void php_v8_named_property_handler_configuration_free(zend_object *object php_v8_named_property_handler_configuration_t *php_v8_handler = php_v8_named_property_handler_configuration_fetch_object(object); if (php_v8_handler->bucket) { - php_v8_callback_destroy_bucket(php_v8_handler->bucket); + delete php_v8_handler->bucket; php_v8_handler->bucket = NULL; } @@ -62,6 +62,8 @@ static zend_object * php_v8_named_property_handler_configuration_ctor(zend_class zend_object_std_init(&php_v8_handler->std, ce); object_properties_init(&php_v8_handler->std, ce); + php_v8_handler->bucket = new phpv8::CallbacksBucket(); + php_v8_handler->std.handlers = &php_v8_named_property_handler_configuration_object_handlers; return &php_v8_handler->std; @@ -99,28 +101,26 @@ static PHP_METHOD (V8NamedPropertyHandlerConfiguration, __construct) { PHP_V8_NAMED_PROPERTY_HANDLER_FETCH_INTO(getThis(), php_v8_handlers); - php_v8_handlers->bucket = php_v8_callback_create_bucket(5); - - php_v8_callback_add(0, fci_getter, fci_cache_getter, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(0, fci_getter, fci_cache_getter); php_v8_handlers->getter = php_v8_callback_generic_named_property_getter; if (fci_setter.size) { - php_v8_callback_add(1, fci_setter, fci_cache_setter, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(1, fci_setter, fci_cache_setter); php_v8_handlers->setter = php_v8_callback_generic_named_property_setter; } if (fci_query.size) { - php_v8_callback_add(2, fci_query, fci_cache_query, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(2, fci_query, fci_cache_query); php_v8_handlers->query = php_v8_callback_generic_named_property_query; } if (fci_deleter.size) { - php_v8_callback_add(3, fci_deleter, fci_cache_deleter, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(3, fci_deleter, fci_cache_deleter); php_v8_handlers->deleter = php_v8_callback_generic_named_property_deleter; } if (fci_enumerator.size) { - php_v8_callback_add(4, fci_enumerator, fci_cache_enumerator, php_v8_handlers->bucket); + php_v8_handlers->bucket->add(4, fci_enumerator, fci_cache_enumerator); php_v8_handlers->enumerator = php_v8_callback_generic_named_property_enumerator; } diff --git a/src/php_v8_named_property_handler_configuration.h b/src/php_v8_named_property_handler_configuration.h index 8d43d2b..35970df 100644 --- a/src/php_v8_named_property_handler_configuration.h +++ b/src/php_v8_named_property_handler_configuration.h @@ -58,7 +58,7 @@ typedef struct _php_v8_named_property_handler_configuration_t { long flags; - php_v8_callbacks_bucket_t *bucket; + phpv8::CallbacksBucket *bucket; zval *gc_data; int gc_data_count; diff --git a/src/php_v8_object.cc b/src/php_v8_object.cc index 5f4aefa..12629ad 100644 --- a/src/php_v8_object.cc +++ b/src/php_v8_object.cc @@ -28,6 +28,7 @@ #include "php_v8_name.h" #include "php_v8_value.h" #include "php_v8_context.h" +#include "php_v8_ext_mem_interface.h" #include "php_v8.h" @@ -670,14 +671,15 @@ static PHP_METHOD(V8Object, SetAccessor) { v8::AccessorNameSetterCallback setter = 0; v8::Local data; - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(2, "accessor_", local_name->IsSymbol(), name, php_v8_value->callbacks); + + phpv8::CallbacksBucket *bucket = php_v8_value->persistent_data->bucket("accessor_", local_name->IsSymbol(), name); data = v8::External::New(isolate, bucket); - php_v8_callback_add(0, getter_fci, getter_fci_cache, bucket); + bucket->add(0, getter_fci, getter_fci_cache); getter = php_v8_callback_accessor_name_getter; if (setter_fci.size) { - php_v8_callback_add(1, setter_fci, setter_fci_cache, bucket); + bucket->add(1, setter_fci, setter_fci_cache); setter = php_v8_callback_accessor_name_setter; } @@ -1436,6 +1438,17 @@ static PHP_METHOD(V8Object, CallAsConstructor) { //static PHP_METHOD(V8Object, Cast) { //} +/* Non-standard, implementations of AdjustableExternalMemoryInterface::AdjustExternalAllocatedMemory */ +static PHP_METHOD(V8Object, AdjustExternalAllocatedMemory) { + php_v8_ext_mem_interface_value_AdjustExternalAllocatedMemory(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +/* Non-standard, implementations of AdjustableExternalMemoryInterface::GetExternalAllocatedMemory */ +static PHP_METHOD(V8Object, GetExternalAllocatedMemory) { + php_v8_ext_mem_interface_value_GetExternalAllocatedMemory(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + + ZEND_BEGIN_ARG_INFO_EX(arginfo_v8_object___construct, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1) ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0) ZEND_END_ARG_INFO() @@ -1644,6 +1657,14 @@ ZEND_END_ARG_INFO() // ZEND_ARG_OBJ_INFO(0, persistent, V8\\Value, 0) //ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_object_AdjustExternalAllocatedMemory, ZEND_RETURN_VALUE, 1, IS_LONG, NULL, 0) + ZEND_ARG_TYPE_INFO(0, change_in_bytes, IS_LONG, 0) +ZEND_END_ARG_INFO() + + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_object_GetExternalAllocatedMemory, ZEND_RETURN_VALUE, 0, IS_LONG, NULL, 0) +ZEND_END_ARG_INFO() + static const zend_function_entry php_v8_object_methods[] = { PHP_ME(V8Object, __construct, arginfo_v8_object___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) @@ -1695,15 +1716,19 @@ static const zend_function_entry php_v8_object_methods[] = { // NOTE: Not supported yet //PHP_ME(V8Object, Cast, arginfo_v8_object_Cast, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + + PHP_ME(V8Object, AdjustExternalAllocatedMemory, arginfo_v8_object_AdjustExternalAllocatedMemory, ZEND_ACC_PUBLIC) + PHP_ME(V8Object, GetExternalAllocatedMemory, arginfo_v8_object_GetExternalAllocatedMemory, ZEND_ACC_PUBLIC) + PHP_FE_END }; - PHP_MINIT_FUNCTION(php_v8_object) { zend_class_entry ce; INIT_NS_CLASS_ENTRY(ce, PHP_V8_NS, "ObjectValue", php_v8_object_methods); this_ce = zend_register_internal_class_ex(&ce, php_v8_value_class_entry); + zend_class_implements(this_ce, 1, php_v8_ext_mem_interface_ce); zend_declare_property_null(this_ce, ZEND_STRL("context"), ZEND_ACC_PRIVATE); diff --git a/src/php_v8_object_template.cc b/src/php_v8_object_template.cc index d6a64ab..8f33dfe 100644 --- a/src/php_v8_object_template.cc +++ b/src/php_v8_object_template.cc @@ -25,7 +25,7 @@ #include "php_v8_name.h" #include "php_v8_context.h" #include "php_v8_value.h" - +#include "php_v8_ext_mem_interface.h" #include "php_v8.h" zend_class_entry *php_v8_object_template_class_entry; @@ -45,33 +45,35 @@ static void php_v8_object_template_weak_callback(const v8::WeakCallbackInfoweak_object_templates)[data.GetParameter()]; - php_v8_callbacks_cleanup(callbacks); - php_v8_isolate->weak_object_templates->erase(data.GetParameter()); + phpv8::PersistentData *persistent_data = php_v8_isolate->weak_object_templates->get(data.GetParameter()); - data.GetParameter()->Reset(); + if (persistent_data != nullptr) { + // Tell v8 that we release external allocated memory + php_v8_debug_external_mem("Free allocated external memory (obj tpl: %p): -%" PRId64 "\n", persistent_data, persistent_data->getTotalSize()) + isolate->AdjustAmountOfExternalAllocatedMemory(-persistent_data->getTotalSize()); + php_v8_isolate->weak_object_templates->remove(data.GetParameter()); + } - delete callbacks; + data.GetParameter()->Reset(); delete data.GetParameter(); - - // Tell v8 that we release external allocated memory - isolate->AdjustAmountOfExternalAllocatedMemory(-1024 * 1024 * 1024); } static void php_v8_object_template_make_weak(php_v8_object_template_t *php_v8_object_template) { - (*php_v8_object_template->php_v8_isolate->weak_object_templates)[php_v8_object_template->persistent] = php_v8_object_template->callbacks; + php_v8_object_template->php_v8_isolate->weak_object_templates->add(php_v8_object_template->persistent, php_v8_object_template->persistent_data); php_v8_object_template->is_weak = true; php_v8_object_template->persistent->SetWeak(php_v8_object_template->persistent, php_v8_object_template_weak_callback, v8::WeakCallbackType::kParameter); - php_v8_object_template->php_v8_isolate->isolate->AdjustAmountOfExternalAllocatedMemory(1024 * 1024 * 1024); + // Tell v8 that we allocated external memory + php_v8_debug_external_mem("Allocate external memory (obj tpl: %p): %" PRId64 "\n", php_v8_object_template->persistent_data, php_v8_object_template->persistent_data->getTotalSize()) + php_v8_object_template->php_v8_isolate->isolate->AdjustAmountOfExternalAllocatedMemory(php_v8_object_template->persistent_data->getTotalSize()); } static HashTable * php_v8_object_template_gc(zval *object, zval **table, int *n) { PHP_V8_OBJECT_TEMPLATE_FETCH_INTO(object, php_v8_object_template); - php_v8_callbacks_gc(php_v8_object_template->callbacks, &php_v8_object_template->gc_data, &php_v8_object_template->gc_data_count, table, n); + php_v8_callbacks_gc(php_v8_object_template->persistent_data, &php_v8_object_template->gc_data, &php_v8_object_template->gc_data_count, table, n); return zend_std_get_properties(object); } @@ -79,14 +81,14 @@ static HashTable * php_v8_object_template_gc(zval *object, zval **table, int *n) static void php_v8_object_template_free(zend_object *object) { php_v8_object_template_t *php_v8_object_template = php_v8_object_template_fetch_object(object); - if (!CG(unclean_shutdown) && php_v8_object_template->callbacks && !php_v8_object_template->callbacks->empty()) { + if (zend_is_executing() && !CG(unclean_shutdown) && php_v8_object_template->persistent_data && !php_v8_object_template->persistent_data->empty()) { php_v8_object_template_make_weak(php_v8_object_template); } if (!php_v8_object_template->is_weak) { - if (php_v8_object_template->callbacks) { - php_v8_callbacks_cleanup(php_v8_object_template->callbacks); - delete php_v8_object_template->callbacks; + if (php_v8_object_template->persistent_data) { + delete php_v8_object_template->persistent_data; + php_v8_object_template->persistent_data = NULL; } if (php_v8_object_template->persistent) { @@ -116,7 +118,7 @@ static zend_object * php_v8_object_template_ctor(zend_class_entry *ce) { object_properties_init(&php_v8_object_template->std, ce); php_v8_object_template->persistent = new v8::Persistent(); - php_v8_object_template->callbacks = new php_v8_callbacks_t(); + php_v8_object_template->persistent_data = new phpv8::PersistentData(); php_v8_object_template->node = new phpv8::TemplateNode(); @@ -256,14 +258,15 @@ static PHP_METHOD(V8ObjectTemplate, SetAccessor) { v8::Local data; v8::Local signature; // TODO: add AccessorSignature support - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(2, "accessor_", local_name->IsSymbol(), name, php_v8_object_template->callbacks); + phpv8::CallbacksBucket *bucket = php_v8_object_template->persistent_data->bucket("accessor_", + local_name->IsSymbol(), name); data = v8::External::New(isolate, bucket); - php_v8_callback_add(0, getter_fci, getter_fci_cache, bucket); + bucket->add(0, getter_fci, getter_fci_cache); getter = php_v8_callback_accessor_name_getter; if (setter_fci.size) { - php_v8_callback_add(1, setter_fci, setter_fci_cache, bucket); + bucket->add(1, setter_fci, setter_fci_cache); setter = php_v8_callback_accessor_name_setter; } @@ -291,8 +294,8 @@ static PHP_METHOD(V8ObjectTemplate, SetHandlerForNamedProperty) { v8::Local local_obj_tpl = php_v8_object_template_get_local(isolate, php_v8_object_template); - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(5, "", false, "named_handlers", php_v8_object_template->callbacks); - php_v8_callbacks_copy_bucket(php_v8_handlers->bucket, bucket); + phpv8::CallbacksBucket *bucket = php_v8_object_template->persistent_data->bucket("named_handlers"); + bucket->reset(php_v8_handlers->bucket); v8::Local data = v8::External::New(isolate, bucket); @@ -323,8 +326,8 @@ static PHP_METHOD(V8ObjectTemplate, SetHandlerForIndexedProperty) { v8::Local local_obj_tpl = php_v8_object_template_get_local(isolate, php_v8_object_template); - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(5, "", false, "indexed_handlers", php_v8_object_template->callbacks); - php_v8_callbacks_copy_bucket(php_v8_handlers->bucket, bucket); + phpv8::CallbacksBucket *bucket = php_v8_object_template->persistent_data->bucket("indexed_handlers"); + bucket->reset(php_v8_handlers->bucket); v8::Local data = v8::External::New(isolate, bucket); @@ -356,10 +359,10 @@ static PHP_METHOD(V8ObjectTemplate, SetCallAsFunctionHandler) { PHP_V8_ENTER_STORED_ISOLATE(php_v8_object_template); if (fci.size) { - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(1, "", false, "callback", php_v8_object_template->callbacks); + phpv8::CallbacksBucket *bucket = php_v8_object_template->persistent_data->bucket("callback"); data = v8::External::New(isolate, bucket); - php_v8_callback_add(0, fci, fci_cache, bucket); + bucket->add(0, fci, fci_cache); callback = php_v8_callback_function; } @@ -394,14 +397,24 @@ static PHP_METHOD(V8ObjectTemplate, SetAccessCheckCallback) { PHP_V8_FETCH_OBJECT_TEMPLATE_WITH_CHECK(getThis(), php_v8_object_template); PHP_V8_ENTER_STORED_ISOLATE(php_v8_object_template); - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(1, "", false, "access_check", php_v8_object_template->callbacks); - php_v8_callback_add(0, fci_callback, fci_cache_callback, bucket); + phpv8::CallbacksBucket *bucket = php_v8_object_template->persistent_data->bucket("access_check"); + bucket->add(0, fci_callback, fci_cache_callback); v8::Local local_template = php_v8_object_template_get_local(isolate, php_v8_object_template); local_template->SetAccessCheckCallback(php_v8_callback_access_check, v8::External::New(isolate, bucket)); } +/* Non-standard, implementations of AdjustableExternalMemoryInterface::AdjustExternalAllocatedMemory */ +static PHP_METHOD(V8ObjectTemplate, AdjustExternalAllocatedMemory) { + php_v8_ext_mem_interface_object_template_AdjustExternalAllocatedMemory(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +/* Non-standard, implementations of AdjustableExternalMemoryInterface::GetExternalAllocatedMemory */ +static PHP_METHOD(V8ObjectTemplate, GetExternalAllocatedMemory) { + php_v8_ext_mem_interface_object_template_GetExternalAllocatedMemory(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + ZEND_BEGIN_ARG_INFO_EX(arginfo_v8_object_template___construct, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1) ZEND_ARG_OBJ_INFO(0, isolate, V8\\Isolate, 0) @@ -476,6 +489,15 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_php_v8_object_template_SetAccessCheckCallback, ZE ZEND_ARG_CALLABLE_INFO(0, callback, 1) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_object_template_AdjustExternalAllocatedMemory, ZEND_RETURN_VALUE, 1, IS_LONG, NULL, 0) + ZEND_ARG_TYPE_INFO(0, change_in_bytes, IS_LONG, 0) +ZEND_END_ARG_INFO() + + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_object_template_GetExternalAllocatedMemory, ZEND_RETURN_VALUE, 0, IS_LONG, NULL, 0) +ZEND_END_ARG_INFO() + + static const zend_function_entry php_v8_object_template_methods[] = { PHP_ME(V8ObjectTemplate, __construct, arginfo_v8_object_template___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) @@ -494,6 +516,9 @@ static const zend_function_entry php_v8_object_template_methods[] = { PHP_ME(V8ObjectTemplate, MarkAsUndetectable, arginfo_php_v8_object_template_MarkAsUndetectable, ZEND_ACC_PUBLIC) // PHP_ME(V8ObjectTemplate, SetAccessCheckCallback, arginfo_php_v8_object_template_SetAccessCheckCallback, ZEND_ACC_PUBLIC) + PHP_ME(V8ObjectTemplate, AdjustExternalAllocatedMemory, arginfo_v8_object_template_AdjustExternalAllocatedMemory, ZEND_ACC_PUBLIC) + PHP_ME(V8ObjectTemplate, GetExternalAllocatedMemory, arginfo_v8_object_template_GetExternalAllocatedMemory, ZEND_ACC_PUBLIC) + PHP_FE_END }; @@ -503,6 +528,7 @@ PHP_MINIT_FUNCTION (php_v8_object_template) { INIT_NS_CLASS_ENTRY(ce, PHP_V8_NS, "ObjectTemplate", php_v8_object_template_methods); this_ce = zend_register_internal_class_ex(&ce, php_v8_template_ce); + zend_class_implements(this_ce, 1, php_v8_ext_mem_interface_ce); this_ce->create_object = php_v8_object_template_ctor; memcpy(&php_v8_object_template_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); diff --git a/src/php_v8_object_template.h b/src/php_v8_object_template.h index 57986ff..5310eab 100644 --- a/src/php_v8_object_template.h +++ b/src/php_v8_object_template.h @@ -61,7 +61,7 @@ struct _php_v8_object_template_t { bool is_weak; v8::Persistent *persistent; - php_v8_callbacks_t *callbacks; + phpv8::PersistentData *persistent_data; zval *gc_data; int gc_data_count; diff --git a/src/php_v8_template.cc b/src/php_v8_template.cc index d2b6c21..d9ccc5c 100644 --- a/src/php_v8_template.cc +++ b/src/php_v8_template.cc @@ -249,14 +249,14 @@ void php_v8_template_SetNativeDataProperty(v8::Isolate *isolate, v8::Local lo PHP_V8_CONVERT_FROM_V8_STRING_TO_STRING(name, local_name); - php_v8_callbacks_bucket_t *bucket = php_v8_callback_get_or_create_bucket(2, "native_data_property_", local_name->IsSymbol(), name, php_v8_template->callbacks); + phpv8::CallbacksBucket *bucket = php_v8_template->persistent_data->bucket("native_data_property_", local_name->IsSymbol(), name); data = v8::External::New(isolate, bucket); - php_v8_callback_add(0, getter_fci, getter_fci_cache, bucket); + bucket->add(0, getter_fci, getter_fci_cache); getter = php_v8_callback_accessor_name_getter; if (setter_fci.size) { - php_v8_callback_add(1, setter_fci, setter_fci_cache, bucket); + bucket->add(1, setter_fci, setter_fci_cache); setter = php_v8_callback_accessor_name_setter; } @@ -308,6 +308,7 @@ PHP_MINIT_FUNCTION (php_v8_template) { zend_class_entry ce; INIT_NS_CLASS_ENTRY(ce, PHP_V8_NS, "Template", php_v8_template_methods); + //zend_class_implements() this_ce = zend_register_internal_class_ex(&ce, php_v8_data_class_entry); zend_declare_property_null(this_ce, ZEND_STRL("isolate"), ZEND_ACC_PRIVATE); diff --git a/src/php_v8_value.cc b/src/php_v8_value.cc index a656acb..6f8bb5b 100644 --- a/src/php_v8_value.cc +++ b/src/php_v8_value.cc @@ -62,13 +62,16 @@ static void php_v8_value_weak_callback(const v8::WeakCallbackInfoweak_values)[data.GetParameter()]; - php_v8_callbacks_cleanup(callbacks); - php_v8_isolate->weak_values->erase(data.GetParameter()); + phpv8::PersistentData *persistent_data = php_v8_isolate->weak_values->get(data.GetParameter()); - data.GetParameter()->Reset(); + if (persistent_data != nullptr) { + // Tell v8 that we release external allocated memory + php_v8_debug_external_mem("Free allocated external memory (value: %p): -%" PRId64 "\n", persistent_data, persistent_data->getTotalSize()) + isolate->AdjustAmountOfExternalAllocatedMemory(-persistent_data->getTotalSize()); + php_v8_isolate->weak_values->remove(data.GetParameter()); + } - delete callbacks; + data.GetParameter()->Reset(); delete data.GetParameter(); // Tell v8 that we release external allocated memory @@ -79,18 +82,20 @@ static void php_v8_value_make_weak(php_v8_value_t *php_v8_value) { // TODO: maybe week: if it already week, if has no isolate, if no callbacks or empty callbacks assert(!php_v8_value->is_weak); - (*php_v8_value->php_v8_isolate->weak_values)[php_v8_value->persistent] = php_v8_value->callbacks; + php_v8_value->php_v8_isolate->weak_values->add(php_v8_value->persistent, php_v8_value->persistent_data); php_v8_value->is_weak = true; php_v8_value->persistent->SetWeak(php_v8_value->persistent, php_v8_value_weak_callback, v8::WeakCallbackType::kParameter); - php_v8_value->php_v8_isolate->isolate->AdjustAmountOfExternalAllocatedMemory(1024 * 1024 * 1024); + // Tell v8 that we allocated external memory + php_v8_debug_external_mem("Allocate external memory (value: %p): %" PRId64 "\n", php_v8_value->persistent_data, php_v8_value->persistent_data->getTotalSize()) + php_v8_value->php_v8_isolate->isolate->AdjustAmountOfExternalAllocatedMemory(php_v8_value->persistent_data->getTotalSize()); } static HashTable * php_v8_value_gc(zval *object, zval **table, int *n) { PHP_V8_VALUE_FETCH_INTO(object, php_v8_value); - php_v8_callbacks_gc(php_v8_value->callbacks, &php_v8_value->gc_data, &php_v8_value->gc_data_count, table, n); + php_v8_callbacks_gc(php_v8_value->persistent_data, &php_v8_value->gc_data, &php_v8_value->gc_data_count, table, n); return zend_std_get_properties(object); } @@ -128,16 +133,16 @@ static void php_v8_value_free(zend_object *object) { // TODO: making weak makes sense for objects only - if (!CG(unclean_shutdown) && php_v8_value->callbacks && !php_v8_value->callbacks->empty()) { + if (zend_is_executing() && !CG(unclean_shutdown) && php_v8_value->persistent_data && !php_v8_value->persistent_data->empty()) { php_v8_value_make_weak(php_v8_value); // TODO: refactor logic for make weak to include checking whether it can be weak -> maybe_make_weak } // NOTE: is weak check can be made in this way: //if (!php_v8_value->persistent || !php_v8_value->persistent->IsWeak()) { if (!php_v8_value->is_weak) { - if (php_v8_value->callbacks) { - php_v8_callbacks_cleanup(php_v8_value->callbacks); - delete php_v8_value->callbacks; + if (php_v8_value->persistent_data) { + delete php_v8_value->persistent_data; + php_v8_value->persistent_data = NULL; } if (php_v8_value->persistent) { @@ -162,7 +167,7 @@ static zend_object * php_v8_value_ctor(zend_class_entry *ce) { object_properties_init(&php_v8_value->std, ce); php_v8_value->persistent = new v8::Persistent(); - php_v8_value->callbacks = new php_v8_callbacks_t(); + php_v8_value->persistent_data = new phpv8::PersistentData(); php_v8_value->std.handlers = &php_v8_value_object_handlers; diff --git a/src/php_v8_value.h b/src/php_v8_value.h index 2d1ee02..4edbc85 100644 --- a/src/php_v8_value.h +++ b/src/php_v8_value.h @@ -115,7 +115,7 @@ struct _php_v8_value_t { bool is_weak; v8::Persistent *persistent; - php_v8_callbacks_t *callbacks; + phpv8::PersistentData *persistent_data; zval *gc_data; int gc_data_count; diff --git a/stubs/src/AdjustableExternalMemoryInterface.php b/stubs/src/AdjustableExternalMemoryInterface.php new file mode 100644 index 0000000..a0da72a --- /dev/null +++ b/stubs/src/AdjustableExternalMemoryInterface.php @@ -0,0 +1,57 @@ + | + | | + | Licensed under the MIT license: http://opensource.org/licenses/MIT | + | | + | For the full copyright and license information, please view the | + | LICENSE file that was distributed with this source or visit | + | http://opensource.org/licenses/MIT | + +----------------------------------------------------------------------+ +*/ + + +namespace V8; + + +interface AdjustableExternalMemoryInterface +{ + /** + * + * Adjusts the amount of registered external memory. Used to give V8 an + * indication of the amount of externally allocated memory that is kept alive + * by JavaScript object. V8 uses this to decide when to perform global + * garbage collections. Registering externally allocated memory will trigger + * global garbage collections more often than it would otherwise in an attempt + * to garbage collect the JavaScript objects that keep the externally + * allocated memory alive. + * + * NOTE: this is non-standard method. It is adapted v8::Isolate::AdjustAmountOfExternalAllocatedMemory() method idea + * for PHP V8 ObjectValue, FunctionTemplate and ObjectTemplate objects. Such object may hold some external + * data associated with them and that data can be hold by V8 after PHP object death when object/template + * becomes weak. It is mainly useful to give a V8 a hint about that extra data, thought, it should be used + * carefully while large ExternalAllocatedMemory will lead to more frequent GC triggering, which hurts + * performance. The rule of thumb is not to use this method unless you fully understand what + * v8::Isolate::AdjustAmountOfExternalAllocatedMemory() does. There is an underlying php-v8 mechanism which + * will notify V8 about some basic memory hold by object/template which may be enough in most cases to keep + * balance between performance and resources usage. + * + * @param int $change_in_bytes the change in externally allocated memory that is kept alive by JavaScript objects. + * + * @return int the adjusted value. + * + * NOTE: returned adjusted value can't be less then zero. + */ + public function AdjustExternalAllocatedMemory(int $change_in_bytes) : int; + + /** + * Get external allocated memory hint value. + * + * @return int + */ + public function GetExternalAllocatedMemory() : int; +} diff --git a/stubs/src/FunctionTemplate.php b/stubs/src/FunctionTemplate.php index 41a8508..affa422 100644 --- a/stubs/src/FunctionTemplate.php +++ b/stubs/src/FunctionTemplate.php @@ -114,7 +114,7 @@ * \endcode */ //class FunctionTemplateInterface extends TemplateInterface -class FunctionTemplate extends Template +class FunctionTemplate extends Template implements AdjustableExternalMemoryInterface { private $isolate; @@ -250,4 +250,18 @@ public function RemovePrototype() public function HasInstance(Value $object) : bool { } + + /** + * {@inheritdoc} + */ + public function AdjustExternalAllocatedMemory(int $change_in_bytes) : int + { + } + + /** + * {@inheritdoc} + */ + public function GetExternalAllocatedMemory() : int + { + } } diff --git a/stubs/src/IndexedPropertyHandlerConfiguration.php b/stubs/src/IndexedPropertyHandlerConfiguration.php index 83490f0..58283e9 100644 --- a/stubs/src/IndexedPropertyHandlerConfiguration.php +++ b/stubs/src/IndexedPropertyHandlerConfiguration.php @@ -21,11 +21,11 @@ class IndexedPropertyHandlerConfiguration { /** - * @param callable $getter - * @param callable $setter - * @param callable $query - * @param callable $deleter - * @param callable $enumerator + * @param callable $getter The callback to invoke when getting a property. + * @param callable $setter The callback to invoke when setting a property. + * @param callable $query The callback to invoke to check if an object has a property. + * @param callable $deleter The callback to invoke when deleting a property. + * @param callable $enumerator The callback to invoke to enumerate all the indexed properties of an object. * @param int $flags One of \v8\PropertyHandlerFlags constants */ public function __construct(callable $getter, diff --git a/stubs/src/NamedPropertyHandlerConfiguration.php b/stubs/src/NamedPropertyHandlerConfiguration.php index e18de6f..a0b1848 100644 --- a/stubs/src/NamedPropertyHandlerConfiguration.php +++ b/stubs/src/NamedPropertyHandlerConfiguration.php @@ -21,11 +21,11 @@ class NamedPropertyHandlerConfiguration { /** - * @param callable $getter - * @param callable $setter - * @param callable $query - * @param callable $deleter - * @param callable $enumerator + * @param callable $getter The callback to invoke when getting a property. + * @param callable $setter The callback to invoke when setting a property. + * @param callable $query The callback to invoke to check if a property is present, and if present, get its attributes. + * @param callable $deleter The callback to invoke when deleting a property. + * @param callable $enumerator The callback to invoke to enumerate all the named properties of an object. * @param int $flags One of \v8\PropertyHandlerFlags constants */ public function __construct(callable $getter, diff --git a/stubs/src/ObjectTemplate.php b/stubs/src/ObjectTemplate.php index f6cbe09..b460271 100644 --- a/stubs/src/ObjectTemplate.php +++ b/stubs/src/ObjectTemplate.php @@ -24,7 +24,7 @@ * Properties added to an ObjectTemplate are added to each object * created from the ObjectTemplate. */ -class ObjectTemplate extends Template +class ObjectTemplate extends Template implements AdjustableExternalMemoryInterface { public function __construct(Isolate $isolate, FunctionTemplate $constructor = null) { @@ -102,20 +102,29 @@ public function SetAccessor( /** * Sets a named property handler on the object template. * + * Whenever a property whose name is a string or a symbol is accessed on + * objects created from this object template, the provided callback is + * invoked instead of accessing the property directly on the JavaScript + * object. + * * See \v8\NamedPropertyHandlerConfiguration constructor argument description for details * - * @param \v8\NamedPropertyHandlerConfiguration + * @param \v8\NamedPropertyHandlerConfiguration The NamedPropertyHandlerConfiguration that defines the callbacks to invoke when accessing a property. */ public function SetHandlerForNamedProperty(NamedPropertyHandlerConfiguration $configuration) { } /** - * Sets a indexed property handler on the object template. + * Sets an indexed property handler on the object template. + * + * Whenever an indexed property is accessed on objects created from + * this object template, the provided callback is invoked instead of + * accessing the property directly on the JavaScript object. * * See \v8\IndexedPropertyHandlerConfiguration constructor argument description for details * - * @param \V8\IndexedPropertyHandlerConfiguration $configuration + * @param \V8\IndexedPropertyHandlerConfiguration $configuration The IndexedPropertyHandlerConfiguration that defines the callbacks to invoke when accessing a property. */ public function SetHandlerForIndexedProperty(IndexedPropertyHandlerConfiguration $configuration) { @@ -158,4 +167,18 @@ public function MarkAsUndetectable() //public function SetAccessCheckCallback(callable $callback) //{ //} + + /** + * {@inheritdoc} + */ + public function AdjustExternalAllocatedMemory(int $change_in_bytes) : int + { + } + + /** + * {@inheritdoc} + */ + public function GetExternalAllocatedMemory() : int + { + } } diff --git a/stubs/src/ObjectValue.php b/stubs/src/ObjectValue.php index 52e4a39..20e2715 100644 --- a/stubs/src/ObjectValue.php +++ b/stubs/src/ObjectValue.php @@ -21,7 +21,7 @@ /** * A JavaScript object (ECMA-262, 4.3.3) */ -class ObjectValue extends Value +class ObjectValue extends Value implements AdjustableExternalMemoryInterface { public function __construct(Context $context) { @@ -530,4 +530,18 @@ public function CallAsFunction(Context $context, Value $recv, array $arguments = public function CallAsConstructor(Context $context, array $arguments = []) : Value { } + + /** + * {@inheritdoc} + */ + public function AdjustExternalAllocatedMemory(int $change_in_bytes) : int + { + } + + /** + * {@inheritdoc} + */ + public function GetExternalAllocatedMemory() : int + { + } } diff --git a/tests/005-V8FunctionTemplate_external_memory.phpt b/tests/005-V8FunctionTemplate_external_memory.phpt new file mode 100644 index 0000000..3662fef --- /dev/null +++ b/tests/005-V8FunctionTemplate_external_memory.phpt @@ -0,0 +1,32 @@ +--TEST-- +V8\FunctionTemplate - external memory +--SKIPIF-- + +--FILE-- +inline('Adjusted external memory size by default', $value->GetExternalAllocatedMemory()); +$helper->inline('After adjusting from zero to 1kb', $value->AdjustExternalAllocatedMemory(1024)); +$helper->inline('After adjusting from 1kb to 2kb', $value->AdjustExternalAllocatedMemory(1024)); +$helper->inline('After adjusting down from 2kb to 1kb', $value->AdjustExternalAllocatedMemory(-1024)); +$helper->inline('After adjusting down to more that was adjusted initially', $value->AdjustExternalAllocatedMemory(-9999999999)); +$helper->line(); + +?> +--EXPECT-- +Adjusted external memory size by default: 0 +After adjusting from zero to 1kb: 1024 +After adjusting from 1kb to 2kb: 2048 +After adjusting down from 2kb to 1kb: 1024 +After adjusting down to more that was adjusted initially: 0 diff --git a/tests/005-V8ObjectTemplate_external_memory.phpt b/tests/005-V8ObjectTemplate_external_memory.phpt new file mode 100644 index 0000000..8461724 --- /dev/null +++ b/tests/005-V8ObjectTemplate_external_memory.phpt @@ -0,0 +1,32 @@ +--TEST-- +V8\ObjectTemplate - external memory +--SKIPIF-- + +--FILE-- +inline('Adjusted external memory size by default', $value->GetExternalAllocatedMemory()); +$helper->inline('After adjusting from zero to 1kb', $value->AdjustExternalAllocatedMemory(1024)); +$helper->inline('After adjusting from 1kb to 2kb', $value->AdjustExternalAllocatedMemory(1024)); +$helper->inline('After adjusting down from 2kb to 1kb', $value->AdjustExternalAllocatedMemory(-1024)); +$helper->inline('After adjusting down to more that was adjusted initially', $value->AdjustExternalAllocatedMemory(-9999999999)); +$helper->line(); + +?> +--EXPECT-- +Adjusted external memory size by default: 0 +After adjusting from zero to 1kb: 1024 +After adjusting from 1kb to 2kb: 2048 +After adjusting down from 2kb to 1kb: 1024 +After adjusting down to more that was adjusted initially: 0 diff --git a/tests/005-V8ObjectValue_external_memory.phpt b/tests/005-V8ObjectValue_external_memory.phpt new file mode 100644 index 0000000..1a28947 --- /dev/null +++ b/tests/005-V8ObjectValue_external_memory.phpt @@ -0,0 +1,32 @@ +--TEST-- +V8\ObjectValue - external memory +--SKIPIF-- + +--FILE-- +inline('Adjusted external memory size by default', $value->GetExternalAllocatedMemory()); +$helper->inline('After adjusting from zero to 1kb', $value->AdjustExternalAllocatedMemory(1024)); +$helper->inline('After adjusting from 1kb to 2kb', $value->AdjustExternalAllocatedMemory(1024)); +$helper->inline('After adjusting down from 2kb to 1kb', $value->AdjustExternalAllocatedMemory(-1024)); +$helper->inline('After adjusting down to more that was adjusted initially', $value->AdjustExternalAllocatedMemory(-9999999999)); +$helper->line(); + +?> +--EXPECT-- +Adjusted external memory size by default: 0 +After adjusting from zero to 1kb: 1024 +After adjusting from 1kb to 2kb: 2048 +After adjusting down from 2kb to 1kb: 1024 +After adjusting down to more that was adjusted initially: 0 diff --git a/tests/V8ArrayObject.phpt b/tests/V8ArrayObject.phpt index 89b8387..4c79b57 100644 --- a/tests/V8ArrayObject.phpt +++ b/tests/V8ArrayObject.phpt @@ -129,7 +129,7 @@ V8\ArrayObject::CreationContext() matches expected value Converters: ----------- V8\ArrayObject(V8\Value)->ToBoolean(): - object(V8\BooleanValue)#96 (1) { + object(V8\BooleanValue)#98 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -145,7 +145,7 @@ V8\ArrayObject(V8\Value)->ToBoolean(): } } V8\ArrayObject(V8\Value)->ToNumber(): - object(V8\NumberValue)#96 (1) { + object(V8\NumberValue)#98 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -161,7 +161,7 @@ V8\ArrayObject(V8\Value)->ToNumber(): } } V8\ArrayObject(V8\Value)->ToString(): - object(V8\StringValue)#96 (1) { + object(V8\StringValue)#98 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -177,7 +177,7 @@ V8\ArrayObject(V8\Value)->ToString(): } } V8\ArrayObject(V8\Value)->ToDetailString(): - object(V8\StringValue)#96 (1) { + object(V8\StringValue)#98 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -246,7 +246,7 @@ V8\ArrayObject(V8\Value)->ToObject(): } } V8\ArrayObject(V8\Value)->ToInteger(): - object(V8\NumberValue)#96 (1) { + object(V8\NumberValue)#98 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -262,7 +262,7 @@ V8\ArrayObject(V8\Value)->ToInteger(): } } V8\ArrayObject(V8\Value)->ToUint32(): - object(V8\NumberValue)#96 (1) { + object(V8\NumberValue)#98 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -278,7 +278,7 @@ V8\ArrayObject(V8\Value)->ToUint32(): } } V8\ArrayObject(V8\Value)->ToInt32(): - object(V8\NumberValue)#96 (1) { + object(V8\NumberValue)#98 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> diff --git a/tests/V8Exception_CreateMessage.phpt b/tests/V8Exception_CreateMessage.phpt index 950a1ec..2b9dbc0 100644 --- a/tests/V8Exception_CreateMessage.phpt +++ b/tests/V8Exception_CreateMessage.phpt @@ -71,6 +71,7 @@ $helper->line(); $v8_helper->run_checks($res); ?> +EOF --EXPECTF-- Can create message when out of context: ok @@ -180,3 +181,6 @@ V8\ObjectValue(V8\Value)->IsStringObject(): bool(false) V8\ObjectValue(V8\Value)->IsSymbolObject(): bool(false) V8\ObjectValue(V8\Value)->IsNativeError(): bool(false) V8\ObjectValue(V8\Value)->IsRegExp(): bool(false) + + +EOF diff --git a/tests/V8FunctionObject.phpt b/tests/V8FunctionObject.phpt index 4e476cb..70a34e1 100644 --- a/tests/V8FunctionObject.phpt +++ b/tests/V8FunctionObject.phpt @@ -34,6 +34,7 @@ $helper->dump($func); $helper->space(); $helper->assert('FunctionObject extends ObjectValue', $func instanceof \V8\ObjectValue); +$helper->assert('FunctionObject implements AdjustableExternalMemoryInterface', $func instanceof \V8\AdjustableExternalMemoryInterface); $helper->line(); $v8_helper->run_checks($func, 'Checkers'); @@ -113,6 +114,7 @@ object(v8Tests\TrackingDtors\FunctionObject)#6 (2) { FunctionObject extends ObjectValue: ok +FunctionObject implements AdjustableExternalMemoryInterface: ok Checkers: --------- @@ -149,7 +151,7 @@ Should output Hello World string string(11) "Script done" v8Tests\TrackingDtors\FunctionObject(V8\FunctionObject)->GetScriptOrigin(): - object(V8\ScriptOrigin)#111 (6) { + object(V8\ScriptOrigin)#113 (6) { ["resource_name":"V8\ScriptOrigin":private]=> string(0) "" ["resource_line_offset":"V8\ScriptOrigin":private]=> @@ -157,7 +159,7 @@ v8Tests\TrackingDtors\FunctionObject(V8\FunctionObject)->GetScriptOrigin(): ["resource_column_offset":"V8\ScriptOrigin":private]=> int(0) ["options":"V8\ScriptOrigin":private]=> - object(V8\ScriptOriginOptions)#112 (3) { + object(V8\ScriptOriginOptions)#114 (3) { ["is_embedder_debug_script":"V8\ScriptOriginOptions":private]=> bool(false) ["is_shared_cross_origin":"V8\ScriptOriginOptions":private]=> diff --git a/tests/V8FunctionTemplate.phpt b/tests/V8FunctionTemplate.phpt index 8d4d4c3..ea88345 100644 --- a/tests/V8FunctionTemplate.phpt +++ b/tests/V8FunctionTemplate.phpt @@ -29,6 +29,8 @@ $helper->dump($function_template); $helper->space(); $helper->assert('FunctionTemplate extends Template', $function_template instanceof \V8\Template); +$helper->assert('FunctionTemplate implements AdjustableExternalMemoryInterface', $function_template instanceof \V8\AdjustableExternalMemoryInterface); + $helper->line(); $print_func_tpl = new \V8\FunctionTemplate($isolate, function (\V8\FunctionCallbackInfo $info) { @@ -162,6 +164,7 @@ object(V8\FunctionTemplate)#5 (1) { FunctionTemplate extends Template: ok +FunctionTemplate implements AdjustableExternalMemoryInterface: ok Object representation: ---------------------- diff --git a/tests/V8FunctionTemplate_callback_weakness.phpt b/tests/V8FunctionTemplate_callback_weakness.phpt new file mode 100644 index 0000000..b4b8227 --- /dev/null +++ b/tests/V8FunctionTemplate_callback_weakness.phpt @@ -0,0 +1,88 @@ +--TEST-- +V8\FunctionTemplate - callback weakness +--SKIPIF-- + +--FILE-- +header('Functions before setting as a callback'); +debug_zval_dump($f1); +debug_zval_dump($f2); + +$fnc = new \V8\FunctionTemplate($isolate, $f1); + +$helper->header('Functions after f1 was set as a callback'); +debug_zval_dump($f1); +debug_zval_dump($f2); + +$fnc->SetCallHandler($f2); + +$helper->header('Functions after f2 was set as a callback'); +debug_zval_dump($f1); +debug_zval_dump($f2); + +$fnc = null; +$helper->header('Functions after function template was destroyed'); + +debug_zval_dump($f1); +debug_zval_dump($f2); + +$isolate = null; +//for($i = 0; $i<1000; $i++) { +// $isolate->LowMemoryNotification(); +//} +$helper->header('Functions after isolate was destroyed'); + +debug_zval_dump($f1); +debug_zval_dump($f2); + + +echo 'We are done for now', PHP_EOL; + +?> +--EXPECT-- +Functions before setting as a callback: +--------------------------------------- +object(Closure)#4 (0) refcount(2){ +} +object(Closure)#5 (0) refcount(2){ +} +Functions after f1 was set as a callback: +----------------------------------------- +object(Closure)#4 (0) refcount(3){ +} +object(Closure)#5 (0) refcount(2){ +} +Functions after f2 was set as a callback: +----------------------------------------- +object(Closure)#4 (0) refcount(2){ +} +object(Closure)#5 (0) refcount(3){ +} +Functions after function template was destroyed: +------------------------------------------------ +object(Closure)#4 (0) refcount(2){ +} +object(Closure)#5 (0) refcount(3){ +} +Functions after isolate was destroyed: +-------------------------------------- +object(Closure)#4 (0) refcount(2){ +} +object(Closure)#5 (0) refcount(2){ +} +We are done for now diff --git a/tests/V8ObjectTemplate.phpt b/tests/V8ObjectTemplate.phpt index cddb7d8..4d3bda3 100644 --- a/tests/V8ObjectTemplate.phpt +++ b/tests/V8ObjectTemplate.phpt @@ -21,6 +21,7 @@ $helper->dump($value); $helper->space(); $helper->assert('ObjectTemplate extends Template', $value instanceof \V8\Template); +$helper->assert('ObjectTemplate implements AdjustableExternalMemoryInterface', $value instanceof \V8\AdjustableExternalMemoryInterface); $helper->line(); $helper->header('Accessors'); @@ -64,6 +65,7 @@ object(V8\ObjectTemplate)#4 (1) { ObjectTemplate extends Template: ok +ObjectTemplate implements AdjustableExternalMemoryInterface: ok Accessors: ---------- diff --git a/tests/V8ObjectValue.phpt b/tests/V8ObjectValue.phpt index 2b35c8b..c108923 100644 --- a/tests/V8ObjectValue.phpt +++ b/tests/V8ObjectValue.phpt @@ -26,6 +26,7 @@ $helper->space(); $helper->assert('ObjectValue extends Value', $value instanceof \V8\Value); $helper->assert('ObjectValue does not extend PrimitiveValue', !($value instanceof \V8\PrimitiveValue)); +$helper->assert('ObjectValue implements AdjustableExternalMemoryInterface', $value instanceof \V8\AdjustableExternalMemoryInterface); $helper->line(); $helper->header('Accessors'); @@ -103,6 +104,7 @@ object(V8\ObjectValue)#6 (2) { ObjectValue extends Value: ok ObjectValue does not extend PrimitiveValue: ok +ObjectValue implements AdjustableExternalMemoryInterface: ok Accessors: ---------- @@ -149,7 +151,7 @@ V8\ObjectValue(V8\Value)->IsRegExp(): bool(false) Converters: ----------- V8\ObjectValue(V8\Value)->ToBoolean(): - object(V8\BooleanValue)#93 (1) { + object(V8\BooleanValue)#95 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -165,7 +167,7 @@ V8\ObjectValue(V8\Value)->ToBoolean(): } } V8\ObjectValue(V8\Value)->ToNumber(): - object(V8\NumberValue)#93 (1) { + object(V8\NumberValue)#95 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -181,7 +183,7 @@ V8\ObjectValue(V8\Value)->ToNumber(): } } V8\ObjectValue(V8\Value)->ToString(): - object(V8\StringValue)#93 (1) { + object(V8\StringValue)#95 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -197,7 +199,7 @@ V8\ObjectValue(V8\Value)->ToString(): } } V8\ObjectValue(V8\Value)->ToDetailString(): - object(V8\StringValue)#93 (1) { + object(V8\StringValue)#95 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -266,7 +268,7 @@ V8\ObjectValue(V8\Value)->ToObject(): } } V8\ObjectValue(V8\Value)->ToInteger(): - object(V8\NumberValue)#93 (1) { + object(V8\NumberValue)#95 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -282,7 +284,7 @@ V8\ObjectValue(V8\Value)->ToInteger(): } } V8\ObjectValue(V8\Value)->ToUint32(): - object(V8\NumberValue)#93 (1) { + object(V8\NumberValue)#95 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> @@ -298,7 +300,7 @@ V8\ObjectValue(V8\Value)->ToUint32(): } } V8\ObjectValue(V8\Value)->ToInt32(): - object(V8\NumberValue)#93 (1) { + object(V8\NumberValue)#95 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> diff --git a/tests/V8StringObject.phpt b/tests/V8StringObject.phpt index bb47786..c2c5cf4 100644 --- a/tests/V8StringObject.phpt +++ b/tests/V8StringObject.phpt @@ -127,7 +127,7 @@ StringObject extends ObjectValue: ok Getters: -------- V8\StringObject->ValueOf(): - object(V8\StringValue)#96 (1) { + object(V8\StringValue)#98 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> diff --git a/tests/V8SymbolObject.phpt b/tests/V8SymbolObject.phpt index 55fd416..5cdca30 100644 --- a/tests/V8SymbolObject.phpt +++ b/tests/V8SymbolObject.phpt @@ -130,7 +130,7 @@ SymbolObject extends ObjectValue: ok Getters: -------- V8\SymbolObject->ValueOf(): - object(V8\SymbolValue)#96 (1) { + object(V8\SymbolValue)#98 (1) { ["isolate":"V8\Value":private]=> object(V8\Isolate)#3 (5) { ["snapshot":"V8\Isolate":private]=> diff --git a/v8.cc b/v8.cc index 714236d..79c7e9c 100644 --- a/v8.cc +++ b/v8.cc @@ -67,6 +67,7 @@ #include "php_v8_value.h" #include "php_v8_data.h" +#include "php_v8_ext_mem_interface.h" #include @@ -97,70 +98,71 @@ PHP_INI_END() */ PHP_MINIT_FUNCTION(v8) { - PHP_MINIT(php_v8_exceptions)(INIT_FUNC_ARGS_PASSTHRU); /* Exceptions */ - - PHP_MINIT(php_v8_heap_statistics)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_startup_data)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_isolate)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_context)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_script)(INIT_FUNC_ARGS_PASSTHRU); - - PHP_MINIT(php_v8_exception)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_try_catch)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_message)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_stack_frame)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_stack_trace)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_script_origin_options)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_script_origin)(INIT_FUNC_ARGS_PASSTHRU); - - PHP_MINIT(php_v8_data)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_value)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_primitive)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_null)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_boolean)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_name)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_string)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_symbol)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_number)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_integer)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_int32)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_uint32)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_integrity_level)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_object)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_function)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_array)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_date)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_regexp)(INIT_FUNC_ARGS_PASSTHRU); - - PHP_MINIT(php_v8_number_object)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_boolean_object)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_string_object)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_symbol_object)(INIT_FUNC_ARGS_PASSTHRU); - - PHP_MINIT(php_v8_template)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_object_template)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_function_template)(INIT_FUNC_ARGS_PASSTHRU); - - - PHP_MINIT(php_v8_property_attribute)(INIT_FUNC_ARGS_PASSTHRU); /* Helper class, holds constants for v8 internals similarity/compatibility */ - PHP_MINIT(php_v8_access_control)(INIT_FUNC_ARGS_PASSTHRU); /* Helper class, holds constants */ - PHP_MINIT(php_v8_return_value)(INIT_FUNC_ARGS_PASSTHRU); - - PHP_MINIT(php_v8_callback_info)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_property_callback_info)(INIT_FUNC_ARGS_PASSTHRU); /* PropertyCallbackInfo inherits CallbackInfo */ - PHP_MINIT(php_v8_function_callback_info)(INIT_FUNC_ARGS_PASSTHRU); /* FunctionCallbackInfo inherits CallbackInfo */ - - PHP_MINIT(php_v8_property_handler_flags)(INIT_FUNC_ARGS_PASSTHRU); /* Helper class, holds constants */ - PHP_MINIT(php_v8_named_property_handler_configuration)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(php_v8_indexed_property_handler_configuration)(INIT_FUNC_ARGS_PASSTHRU); - - PHP_MINIT(php_v8_access_type)(INIT_FUNC_ARGS_PASSTHRU); /* Helper class, holds constants */ - - /* If you have INI entries, uncomment these lines - REGISTER_INI_ENTRIES(); - */ - - return SUCCESS; + PHP_MINIT(php_v8_exceptions)(INIT_FUNC_ARGS_PASSTHRU); /* Exceptions */ + PHP_MINIT(php_v8_ext_mem_interface)(INIT_FUNC_ARGS_PASSTHRU); /* AdjustableExternalMemoryInterface */ + + PHP_MINIT(php_v8_heap_statistics)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_startup_data)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_isolate)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_context)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_script)(INIT_FUNC_ARGS_PASSTHRU); + + PHP_MINIT(php_v8_exception)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_try_catch)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_message)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_stack_frame)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_stack_trace)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_script_origin_options)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_script_origin)(INIT_FUNC_ARGS_PASSTHRU); + + PHP_MINIT(php_v8_data)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_value)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_primitive)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_null)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_boolean)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_name)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_string)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_symbol)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_number)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_integer)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_int32)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_uint32)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_integrity_level)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_object)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_function)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_array)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_date)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_regexp)(INIT_FUNC_ARGS_PASSTHRU); + + PHP_MINIT(php_v8_number_object)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_boolean_object)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_string_object)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_symbol_object)(INIT_FUNC_ARGS_PASSTHRU); + + PHP_MINIT(php_v8_template)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_object_template)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_function_template)(INIT_FUNC_ARGS_PASSTHRU); + + + PHP_MINIT(php_v8_property_attribute)(INIT_FUNC_ARGS_PASSTHRU); /* Helper class, holds constants for v8 internals similarity/compatibility */ + PHP_MINIT(php_v8_access_control)(INIT_FUNC_ARGS_PASSTHRU); /* Helper class, holds constants */ + PHP_MINIT(php_v8_return_value)(INIT_FUNC_ARGS_PASSTHRU); + + PHP_MINIT(php_v8_callback_info)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_property_callback_info)(INIT_FUNC_ARGS_PASSTHRU); /* PropertyCallbackInfo inherits CallbackInfo */ + PHP_MINIT(php_v8_function_callback_info)(INIT_FUNC_ARGS_PASSTHRU); /* FunctionCallbackInfo inherits CallbackInfo */ + + PHP_MINIT(php_v8_property_handler_flags)(INIT_FUNC_ARGS_PASSTHRU); /* Helper class, holds constants */ + PHP_MINIT(php_v8_named_property_handler_configuration)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(php_v8_indexed_property_handler_configuration)(INIT_FUNC_ARGS_PASSTHRU); + + PHP_MINIT(php_v8_access_type)(INIT_FUNC_ARGS_PASSTHRU); /* Helper class, holds constants */ + + /* If you have INI entries, uncomment these lines + REGISTER_INI_ENTRIES(); + */ + + return SUCCESS; } /* }}} */ @@ -168,10 +170,10 @@ PHP_MINIT_FUNCTION(v8) */ PHP_MSHUTDOWN_FUNCTION(v8) { - /* uncomment this line if you have INI entries - UNREGISTER_INI_ENTRIES(); - */ - return SUCCESS; + /* uncomment this line if you have INI entries + UNREGISTER_INI_ENTRIES(); + */ + return SUCCESS; } /* }}} */ @@ -180,7 +182,7 @@ PHP_MSHUTDOWN_FUNCTION(v8) */ PHP_RINIT_FUNCTION(v8) { - return SUCCESS; + return SUCCESS; } /* }}} */ @@ -189,7 +191,7 @@ PHP_RINIT_FUNCTION(v8) */ PHP_RSHUTDOWN_FUNCTION(v8) { - return SUCCESS; + return SUCCESS; } /* }}} */ @@ -197,21 +199,21 @@ PHP_RSHUTDOWN_FUNCTION(v8) */ PHP_MINFO_FUNCTION(v8) { - php_info_print_table_start(); - php_info_print_table_header(2, "V8 support", "enabled"); - php_info_print_table_row(2, "Version", PHP_V8_VERSION); - php_info_print_table_row(2, "Revision", PHP_V8_REVISION); - php_info_print_table_row(2, "Compiled", __DATE__ " @ " __TIME__); - php_info_print_table_end(); - - php_info_print_table_start(); - php_info_print_table_row(2, "V8 Engine Compiled Version", PHP_V8_LIBV8_VERSION); - php_info_print_table_row(2, "V8 Engine Linked Version", v8::V8::GetVersion()); - php_info_print_table_end(); - - /* Remove comments if you have entries in php.ini - DISPLAY_INI_ENTRIES(); - */ + php_info_print_table_start(); + php_info_print_table_header(2, "V8 support", "enabled"); + php_info_print_table_row(2, "Version", PHP_V8_VERSION); + php_info_print_table_row(2, "Revision", PHP_V8_REVISION); + php_info_print_table_row(2, "Compiled", __DATE__ " @ " __TIME__); + php_info_print_table_end(); + + php_info_print_table_start(); + php_info_print_table_row(2, "V8 Engine Compiled Version", PHP_V8_LIBV8_VERSION); + php_info_print_table_row(2, "V8 Engine Linked Version", v8::V8::GetVersion()); + php_info_print_table_end(); + + /* Remove comments if you have entries in php.ini + DISPLAY_INI_ENTRIES(); + */ } /* }}} */ @@ -221,9 +223,9 @@ PHP_MINFO_FUNCTION(v8) static PHP_GINIT_FUNCTION(v8) { #if defined(COMPILE_DL_V8) && defined(ZTS) - ZEND_TSRMLS_CACHE_UPDATE(); + ZEND_TSRMLS_CACHE_UPDATE(); #endif - v8_globals->v8_initialized = false; + v8_globals->v8_initialized = false; } /* }}} */ @@ -241,27 +243,27 @@ static PHP_GSHUTDOWN_FUNCTION(v8) * Every user visible function must have an entry in php_v8_functions[]. */ const zend_function_entry php_v8_functions[] = { - PHP_FE_END /* Must be the last line in php_v8_functions[] */ + PHP_FE_END /* Must be the last line in php_v8_functions[] */ }; /* }}} */ /* {{{ php_v8_module_entry */ zend_module_entry php_v8_module_entry = { - STANDARD_MODULE_HEADER, - "v8", - php_v8_functions, - PHP_MINIT(v8), - PHP_MSHUTDOWN(v8), - PHP_RINIT(v8), /* Replace with NULL if there's nothing to do at request start */ - PHP_RSHUTDOWN(v8), /* Replace with NULL if there's nothing to do at request end */ - PHP_MINFO(v8), - PHP_V8_VERSION, - PHP_MODULE_GLOBALS(v8), - PHP_GINIT(v8), - PHP_GSHUTDOWN(v8), - NULL, - STANDARD_MODULE_PROPERTIES_EX + STANDARD_MODULE_HEADER, + "v8", + php_v8_functions, + PHP_MINIT(v8), + PHP_MSHUTDOWN(v8), + PHP_RINIT(v8), /* Replace with NULL if there's nothing to do at request start */ + PHP_RSHUTDOWN(v8), /* Replace with NULL if there's nothing to do at request end */ + PHP_MINFO(v8), + PHP_V8_VERSION, + PHP_MODULE_GLOBALS(v8), + PHP_GINIT(v8), + PHP_GSHUTDOWN(v8), + NULL, + STANDARD_MODULE_PROPERTIES_EX }; /* }}} */