Skip to content
This repository was archived by the owner on Mar 29, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
3 changes: 1 addition & 2 deletions php_v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ ZEND_TSRMLS_CACHE_EXTERN();

ZEND_EXTERN_MODULE_GLOBALS(v8);

#endif /* PHP_V8_H */

#endif //PHP_V8_H

/*
* Local variables:
Expand Down
268 changes: 113 additions & 155 deletions src/php_v8_callbacks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,218 +31,171 @@

#include "php_v8_value.h"
#include "php_v8_isolate.h"
#include <string>
#include <algorithm>

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<Callback>(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<CallbacksBucket>();
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<CallbacksBucket>);
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<int64_t>(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);
Expand All @@ -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;
Expand Down Expand Up @@ -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<v8::Value> 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<php_v8_callbacks_bucket_t *>(v8::Local<v8::External>::Cast(data)->Value());
assert(bucket->size > index);
bucket = static_cast<phpv8::CallbacksBucket *>(v8::Local<v8::External>::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);
Expand Down
Loading