3131
3232#include " php_v8_value.h"
3333#include " php_v8_isolate.h"
34+ #include < string>
35+ #include < algorithm>
3436
37+ namespace phpv8 {
3538
36- php_v8_callbacks_bucket_t *php_v8_callback_create_bucket (size_t size) {
39+ Callback::Callback (zend_fcall_info fci, zend_fcall_info_cache fci_cache) : fci_(fci), fci_cache_(fci_cache) {
40+ if (fci_.size ) {
41+ Z_ADDREF (fci_.function_name );
3742
38- assert (size > 0 );
39-
40- php_v8_callbacks_bucket_t *bucket;
41-
42- bucket = (php_v8_callbacks_bucket_t *) ecalloc (1 , sizeof (*bucket));
43-
44- bucket->size = size;
45- bucket->cb = (php_v8_callback_t **) ecalloc (size, sizeof (*bucket->cb ));
46-
47- return bucket;
48- }
49-
50-
51- void php_v8_callback_cleanup_bucket (php_v8_callbacks_bucket_t *bucket, size_t index) {
52- assert (bucket->size >= index);
53-
54- if (bucket->cb [index] == NULL ) {
55- return ;
56- }
57-
58- if (bucket->cb [index]->fci .size ) {
59- zval_ptr_dtor (&bucket->cb [index]->fci .function_name );
60-
61- if (!Z_ISUNDEF (bucket->cb [index]->object )) {
62- zval_ptr_dtor (&bucket->cb [index]->object );
43+ if (fci_.object ) {
44+ ZVAL_OBJ (&object_, fci_.object );
45+ Z_ADDREF (object_);
46+ } else {
47+ ZVAL_UNDEF (&object_);
48+ }
6349 }
6450 }
6551
66- efree (bucket-> cb [index]);
67- bucket-> cb [index] = NULL ;
68- }
52+ Callback::~Callback () {
53+ if (fci_. size ) {
54+ zval_ptr_dtor (&fci_. function_name );
6955
70- void php_v8_callback_destroy_bucket (php_v8_callbacks_bucket_t *bucket) {
71- for (size_t i = 0 ; i < bucket->size ; i++) {
72- php_v8_callback_cleanup_bucket (bucket, i);
56+ if (!Z_ISUNDEF (object_)) {
57+ zval_ptr_dtor (&object_);
58+ }
59+ }
7360 }
7461
75- efree (bucket->cb );
76- efree (bucket);
77- }
78-
79- 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) {
80- char *internal_name;
81-
82- spprintf (&internal_name, 0 , " %s%s%s" , prefix, (is_symbol ? " sym_" : " str_" ), name);
62+ int Callback::getGcCount () {
63+ int size = 0 ;
8364
84- php_v8_callbacks_t ::iterator it = callbacks->find (internal_name);
65+ if (fci_.size ) {
66+ size += 1 ;
8567
86- if (it != callbacks->end ()) {
87- efree (internal_name);
68+ if (!Z_ISUNDEF (object_)) {
69+ size += 1 ;
70+ }
71+ }
8872
89- return it-> second ;
73+ return size ;
9074 }
9175
92- php_v8_callbacks_bucket_t *bucket = php_v8_callback_create_bucket (size);
93-
94- (*callbacks)[internal_name] = bucket ;
76+ void Callback::collectGcZvals (zval *&zv) {
77+ if (fci_. size ) {
78+ ZVAL_COPY_VALUE (zv++, &fci_. function_name ) ;
9579
96- return bucket;
97- }
98-
99- void php_v8_callbacks_copy_bucket (php_v8_callbacks_bucket_t *from, php_v8_callbacks_bucket_t *to) {
100- for (size_t i = 0 ; i < from->size ; i++) {
101- if (from->cb [i]) {
102- php_v8_callback_add (i, from->cb [i]->fci , from->cb [i]->fci_cache , to);
80+ if (!Z_ISUNDEF (object_)) {
81+ ZVAL_COPY_VALUE (zv++, &object_);
82+ }
10383 }
10484 }
105- }
106-
107-
108- 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) {
109- assert (bucket->size >= index);
110-
111- php_v8_callback_cleanup_bucket (bucket, index);
11285
113- php_v8_callback_t *callback = (php_v8_callback_t *) ecalloc (1 , sizeof (*callback));
86+ void CallbacksBucket::reset (CallbacksBucket *bucket) {
87+ callbacks.clear ();
11488
115- callback->fci = fci;
116- callback->fci_cache = fci_cache;
117-
118- if (fci.size ) {
119- Z_ADDREF (callback->fci .function_name );
120-
121- if (fci.object ) {
122- ZVAL_OBJ (&callback->object , fci.object );
123- Z_ADDREF (callback->object );
89+ for (auto const &item : bucket->callbacks ) {
90+ callbacks[item.first ] = item.second ;
12491 }
12592 }
12693
127- bucket->cb [index] = callback;
94+ phpv8::Callback *CallbacksBucket::get (size_t index) {
95+ auto it = callbacks.find (index);
12896
129- return callback;
130- }
97+ if (it != callbacks.end ()) {
98+ return it->second .get ();
99+ }
131100
132- void php_v8_callbacks_cleanup (php_v8_callbacks_t *callbacks) {
133- if (callbacks == NULL ) {
134- return ;
101+ return NULL ;
135102 }
136103
137- for (php_v8_callbacks_t ::iterator it = callbacks->begin (); it != callbacks->end (); ++it) {
138- php_v8_callback_destroy_bucket (it->second );
139- efree (it->first );
104+ void CallbacksBucket::add (size_t index, zend_fcall_info fci, zend_fcall_info_cache fci_cache) {
105+ callbacks[index] = std::make_shared<Callback>(fci, fci_cache);
140106 }
141- }
142107
143- void php_v8_callbacks_gc (php_v8_callbacks_t *callbacks, zval **gc_data, int * gc_data_count, zval **table, int *n) {
108+ int CallbacksBucket::getGcCount () {
109+ int size = 0 ;
144110
145- int size = php_v8_weak_callbacks_get_count (callbacks);
111+ for (auto const &item : callbacks) {
112+ size += item.second ->getGcCount ();
113+ }
146114
147- if (*gc_data_count < size) {
148- *gc_data = (zval *)safe_erealloc (*gc_data, size, sizeof (zval), 0 );
115+ return size;
149116 }
150117
151- *gc_data_count = size;
152-
153- zval *local_gc_data = *gc_data;
154-
155- php_v8_weak_callbacks_get_zvals (callbacks, local_gc_data);
156-
157- *table = *gc_data;
158- *n = *gc_data_count;
159- }
118+ void CallbacksBucket::collectGcZvals (zval *&zv) {
119+ for (auto const &item : callbacks) {
120+ item.second ->collectGcZvals (zv);
121+ }
122+ }
160123
124+ int PersistentData::getGcCount () {
125+ int size = 0 ;
161126
162- int php_v8_callback_get_callback_count (php_v8_callback_t *cb) {
163- int size = 0 ;
127+ for (auto const &item : buckets) {
128+ size += item.second ->getGcCount ();
129+ }
164130
165- if (!cb) {
166131 return size;
167132 }
168133
169- if (cb->fci .size ) {
170- size += 1 ;
171-
172- if (!Z_ISUNDEF (cb->object )) {
173- size += 1 ;
134+ void PersistentData::collectGcZvals (zval *&zv) {
135+ for (auto const &item : buckets) {
136+ item.second ->collectGcZvals (zv);
174137 }
175138 }
176139
177- return size;
178- }
140+ CallbacksBucket * PersistentData::bucket ( const char *prefix, bool is_symbol, const char *name) {
141+ char *internal_name;
179142
180- int php_v8_callback_get_bucket_count (php_v8_callbacks_bucket_t *bucket) {
181- int size = 0 ;
143+ size_t size = spprintf (&internal_name, 0 , " %s%s%s" , prefix, (is_symbol ? " sym_" : " str_" ), name);
182144
183- if (!bucket) {
184- return size;
185- }
145+ std::string str_name (internal_name, size);
146+ efree (internal_name);
186147
187- for (size_t i = 0 ; i < bucket->size ; i++) {
188- size += php_v8_callback_get_callback_count (bucket->cb [i]);
189- }
148+ auto it = buckets.find (str_name);
190149
191- return size;
192- }
150+ if (it != buckets.end ()) {
151+ return it->second .get ();
152+ }
193153
194- int php_v8_weak_callbacks_get_count ( php_v8_callbacks_t *callbacks) {
195- int size = 0 ;
154+ auto bucket = std::make_shared<CallbacksBucket>();
155+ buckets[str_name] = bucket ;
196156
197- if (callbacks == NULL || callbacks->empty ()) {
198- return size;
157+ return bucket.get ();
199158 }
200159
201- for (auto it = callbacks->begin (); it != callbacks->end (); ++it) {
202- size += php_v8_callback_get_bucket_count (it->second );
203- }
160+ int64_t PersistentData::calculateSize () {
161+ int64_t size = sizeof (*this );
204162
205- return size;
206- }
163+ for (auto const &item : buckets) {
164+ size += sizeof (std::shared_ptr<CallbacksBucket>);
165+ size += item.first .capacity ();
166+ size += item.second ->calculateSize ();
167+ }
207168
208- void php_v8_callback_get_callback_zvals (php_v8_callback_t *cb, zval *& zv) {
209- if (!cb) {
210- return ;
169+ return size;
211170 }
212171
213- if (cb->fci .size ) {
214- ZVAL_COPY_VALUE (zv++, &cb->fci .function_name );
215-
216- if (!Z_ISUNDEF (cb->object )) {
217- ZVAL_COPY_VALUE (zv++, &cb->object );
218- }
172+ int64_t PersistentData::adjustSize (int64_t change_in_bytes) {
173+ adjusted_size_ = std::max (static_cast <int64_t >(0 ), adjusted_size_ + change_in_bytes);
174+ return adjusted_size_;
219175 }
220176}
221177
178+ void php_v8_callbacks_gc (phpv8::PersistentData *data, zval **gc_data, int * gc_data_count, zval **table, int *n) {
222179
223- void php_v8_callback_get_bucket_zvals (php_v8_callbacks_bucket_t *bucket, zval *& zv) {
224- if (!bucket) {
225- return ;
226- }
180+ int size = data->getGcCount ();
227181
228- for ( size_t i = 0 ; i < bucket-> size ; i++ ) {
229- php_v8_callback_get_callback_zvals (bucket-> cb [i], zv );
182+ if (*gc_data_count < size) {
183+ *gc_data = (zval *) safe_erealloc (*gc_data, size, sizeof (zval), 0 );
230184 }
231- }
232185
233- void php_v8_weak_callbacks_get_zvals (php_v8_callbacks_t *callbacks, zval *& zv) {
234- if (callbacks == NULL ) {
235- return ;
236- }
186+ *gc_data_count = size;
237187
238- for (php_v8_callbacks_t ::iterator it = callbacks->begin (); it != callbacks->end (); ++it) {
239- php_v8_callback_get_bucket_zvals (it->second , zv);
240- }
188+ zval *local_gc_data = *gc_data;
189+
190+ data->collectGcZvals (local_gc_data);
191+
192+ *table = *gc_data;
193+ *n = *gc_data_count;
241194}
242195
243- void php_v8_bucket_gc (php_v8_callbacks_bucket_t *bucket, zval **gc_data, int * gc_data_count, zval **table, int *n) {
196+ void php_v8_bucket_gc (phpv8::CallbacksBucket *bucket, zval **gc_data, int * gc_data_count, zval **table, int *n) {
244197
245- int size = php_v8_callback_get_bucket_count ( bucket);
198+ int size = bucket-> getGcCount ( );
246199
247200 if (*gc_data_count < size) {
248201 *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
252205
253206 zval *local_gc_data = *gc_data;
254207
255- php_v8_callback_get_bucket_zvals ( bucket, local_gc_data);
208+ bucket-> collectGcZvals ( local_gc_data);
256209
257210 *table = *gc_data;
258211 *n = *gc_data_count;
@@ -285,20 +238,25 @@ static inline void php_v8_callback_set_retval_from_callback_info(v8::ReturnValue
285238
286239
287240void php_v8_callback_call_from_bucket_with_zargs (size_t index, v8::Local<v8::Value> data, zval *args, zval *retval) {
288- php_v8_callbacks_bucket_t *bucket;
241+ phpv8::CallbacksBucket *bucket;
289242
290243 if (data.IsEmpty () || !data->IsExternal ()) {
291244 PHP_V8_THROW_EXCEPTION (" Callback has no stored callback function" );
292245 return ;
293246 }
294247
295- bucket = static_cast <php_v8_callbacks_bucket_t *>(v8::Local<v8::External>::Cast (data)->Value ());
296- assert (bucket->size > index);
248+ bucket = static_cast <phpv8::CallbacksBucket *>(v8::Local<v8::External>::Cast (data)->Value ());
297249
298- php_v8_callback_t *cb = bucket->cb [index];
250+ phpv8::Callback *cb = bucket->get (index);
251+
252+ // highly unlikely, but to play safe
253+ if (!cb) {
254+ PHP_V8_THROW_EXCEPTION (" Callback has no stored callback function" );
255+ return ;
256+ }
299257
300- zend_fcall_info fci = cb->fci ;
301- zend_fcall_info_cache fci_cache = cb->fci_cache ;
258+ zend_fcall_info fci = cb->fci () ;
259+ zend_fcall_info_cache fci_cache = cb->fci_cache () ;
302260
303261 /* Convert everything to be callable */
304262 zend_fcall_info_args (&fci, args);
0 commit comments