3131
3232#include " php_v8_value.h"
3333#include " php_v8_isolate.h"
34+ #include < string>
3435
36+ namespace phpv8 {
3537
36- php_v8_callbacks_bucket_t *php_v8_callback_create_bucket (size_t size) {
38+ Callback::Callback (zend_fcall_info fci, zend_fcall_info_cache fci_cache) : fci_(fci), fci_cache_(fci_cache) {
39+ if (fci.size ) {
40+ Z_ADDREF (fci.function_name );
3741
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 );
42+ if (fci.object ) {
43+ ZVAL_OBJ (&object, fci.object );
44+ Z_ADDREF (object);
45+ } else {
46+ ZVAL_UNDEF (&object);
47+ }
6348 }
6449 }
6550
66- efree (bucket-> cb [index]);
67- bucket-> cb [index] = NULL ;
68- }
51+ Callback::~Callback () {
52+ if (fci_. size ) {
53+ zval_ptr_dtor (&fci_. function_name );
6954
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);
55+ if (!Z_ISUNDEF (object)) {
56+ zval_ptr_dtor (&object);
57+ }
58+ }
7359 }
7460
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);
61+ int Callback::getGcCount () {
62+ int size = 0 ;
8363
84- php_v8_callbacks_t ::iterator it = callbacks->find (internal_name);
64+ if (fci_.size ) {
65+ size += 1 ;
8566
86- if (it != callbacks->end ()) {
87- efree (internal_name);
67+ if (!Z_ISUNDEF (object)) {
68+ size += 1 ;
69+ }
70+ }
8871
89- return it-> second ;
72+ return size ;
9073 }
9174
92- php_v8_callbacks_bucket_t *bucket = php_v8_callback_create_bucket (size);
93-
94- (*callbacks)[internal_name] = bucket ;
75+ void Callback::collectGcZvals (zval *&zv) {
76+ if (fci_. size ) {
77+ ZVAL_COPY_VALUE (zv++, &fci_. function_name ) ;
9578
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);
79+ if (!Z_ISUNDEF (object)) {
80+ ZVAL_COPY_VALUE (zv++, &object);
81+ }
10382 }
10483 }
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);
11284
113- php_v8_callback_t *callback = (php_v8_callback_t *) ecalloc (1 , sizeof (*callback));
85+ void CallbacksBucket::reset (CallbacksBucket *bucket) {
86+ callbacks.clear ();
11487
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 );
88+ for (auto const &item : bucket->callbacks ) {
89+ callbacks[item.first ] = item.second ;
12490 }
12591 }
12692
127- bucket->cb [index] = callback;
93+ phpv8::Callback *CallbacksBucket::get (size_t index) {
94+ auto it = callbacks.find (index);
12895
129- return callback;
130- }
131-
132- void php_v8_callbacks_cleanup (php_v8_callbacks_t *callbacks) {
133- if (callbacks == NULL ) {
134- return ;
135- }
96+ if (it != callbacks.end ()) {
97+ return it->second .get ();
98+ }
13699
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 );
100+ return NULL ;
140101 }
141- }
142102
143- void php_v8_callbacks_gc (php_v8_callbacks_t *callbacks, zval **gc_data, int * gc_data_count, zval **table, int *n) {
144-
145- int size = php_v8_weak_callbacks_get_count (callbacks);
146-
147- if (*gc_data_count < size) {
148- *gc_data = (zval *)safe_erealloc (*gc_data, size, sizeof (zval), 0 );
103+ void CallbacksBucket::add (size_t index, zend_fcall_info fci, zend_fcall_info_cache fci_cache) {
104+ callbacks[index] = std::make_shared<Callback>(fci, fci_cache);
149105 }
150106
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);
107+ int CallbacksBucket::getGcCount () {
108+ int size = 0 ;
156109
157- *table = *gc_data;
158- *n = *gc_data_count;
159- }
160-
161-
162- int php_v8_callback_get_callback_count (php_v8_callback_t *cb) {
163- int size = 0 ;
110+ for (auto const &item : callbacks) {
111+ size += item.second ->getGcCount ();
112+ }
164113
165- if (!cb) {
166114 return size;
167115 }
168116
169- if (cb->fci .size ) {
170- size += 1 ;
171-
172- if (!Z_ISUNDEF (cb->object )) {
173- size += 1 ;
117+ void CallbacksBucket::collectGcZvals (zval *&zv) {
118+ for (auto const &item : callbacks) {
119+ item.second ->collectGcZvals (zv);
174120 }
175121 }
176122
177- return size;
178- }
123+ int PersistentData::getGcCount () {
124+ int size = 0 ;
179125
180- int php_v8_callback_get_bucket_count (php_v8_callbacks_bucket_t *bucket) {
181- int size = 0 ;
126+ for (auto const &item : buckets) {
127+ size += item.second ->getGcCount ();
128+ }
182129
183- if (!bucket) {
184130 return size;
185131 }
186132
187- for (size_t i = 0 ; i < bucket->size ; i++) {
188- size += php_v8_callback_get_callback_count (bucket->cb [i]);
133+ void PersistentData::collectGcZvals (zval *&zv) {
134+ for (auto const &item : buckets) {
135+ item.second ->collectGcZvals (zv);
136+ }
189137 }
190138
191- return size;
192- }
193-
194- int php_v8_weak_callbacks_get_count (php_v8_callbacks_t *callbacks) {
195- int size = 0 ;
139+ CallbacksBucket *PersistentData::bucket (const char *prefix, bool is_symbol, const char *name) {
140+ char *internal_name;
196141
197- if (callbacks == NULL || callbacks->empty ()) {
198- return size;
199- }
142+ size_t size = spprintf (&internal_name, 0 , " %s%s%s" , prefix, (is_symbol ? " sym_" : " str_" ), name);
200143
201- for (auto it = callbacks->begin (); it != callbacks->end (); ++it) {
202- size += php_v8_callback_get_bucket_count (it->second );
203- }
144+ std::string str_name (internal_name, size);
145+ efree (internal_name);
204146
205- return size;
206- }
147+ auto it = buckets.find (str_name);
207148
208- void php_v8_callback_get_callback_zvals (php_v8_callback_t *cb, zval *& zv) {
209- if (!cb) {
210- return ;
211- }
149+ if (it != buckets.end ()) {
150+ return it->second .get ();
151+ }
212152
213- if (cb-> fci . size ) {
214- ZVAL_COPY_VALUE (zv++, &cb-> fci . function_name ) ;
153+ auto bucket = std::make_shared<CallbacksBucket>();
154+ buckets[str_name] = bucket ;
215155
216- if (!Z_ISUNDEF (cb->object )) {
217- ZVAL_COPY_VALUE (zv++, &cb->object );
218- }
156+ return bucket.get ();
219157 }
220158}
221159
160+ void php_v8_callbacks_gc (phpv8::PersistentData *data, zval **gc_data, int * gc_data_count, zval **table, int *n) {
222161
223- void php_v8_callback_get_bucket_zvals (php_v8_callbacks_bucket_t *bucket, zval *& zv) {
224- if (!bucket) {
225- return ;
226- }
162+ int size = data->getGcCount ();
227163
228- for ( size_t i = 0 ; i < bucket-> size ; i++ ) {
229- php_v8_callback_get_callback_zvals (bucket-> cb [i], zv );
164+ if (*gc_data_count < size) {
165+ *gc_data = (zval *) safe_erealloc (*gc_data, size, sizeof (zval), 0 );
230166 }
231- }
232167
233- void php_v8_weak_callbacks_get_zvals (php_v8_callbacks_t *callbacks, zval *& zv) {
234- if (callbacks == NULL ) {
235- return ;
236- }
168+ *gc_data_count = size;
237169
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- }
170+ zval *local_gc_data = *gc_data;
171+
172+ data->collectGcZvals (local_gc_data);
173+
174+ *table = *gc_data;
175+ *n = *gc_data_count;
241176}
242177
243- void php_v8_bucket_gc (php_v8_callbacks_bucket_t *bucket, zval **gc_data, int * gc_data_count, zval **table, int *n) {
178+ void php_v8_bucket_gc (phpv8::CallbacksBucket *bucket, zval **gc_data, int * gc_data_count, zval **table, int *n) {
244179
245- int size = php_v8_callback_get_bucket_count ( bucket);
180+ int size = bucket-> getGcCount ( );
246181
247182 if (*gc_data_count < size) {
248183 *gc_data = (zval *)safe_erealloc (*gc_data, size, sizeof (zval), 0 );
@@ -252,7 +187,7 @@ void php_v8_bucket_gc(php_v8_callbacks_bucket_t *bucket, zval **gc_data, int * g
252187
253188 zval *local_gc_data = *gc_data;
254189
255- php_v8_callback_get_bucket_zvals ( bucket, local_gc_data);
190+ bucket-> collectGcZvals ( local_gc_data);
256191
257192 *table = *gc_data;
258193 *n = *gc_data_count;
@@ -285,20 +220,25 @@ static inline void php_v8_callback_set_retval_from_callback_info(v8::ReturnValue
285220
286221
287222void 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;
223+ phpv8::CallbacksBucket *bucket;
289224
290225 if (data.IsEmpty () || !data->IsExternal ()) {
291226 PHP_V8_THROW_EXCEPTION (" Callback has no stored callback function" );
292227 return ;
293228 }
294229
295- bucket = static_cast <php_v8_callbacks_bucket_t *>(v8::Local<v8::External>::Cast (data)->Value ());
296- assert (bucket->size > index);
230+ bucket = static_cast <phpv8::CallbacksBucket *>(v8::Local<v8::External>::Cast (data)->Value ());
297231
298- php_v8_callback_t *cb = bucket->cb [index];
232+ phpv8::Callback *cb = bucket->get (index);
233+
234+ // highly unlikely, but to play safe
235+ if (!cb) {
236+ PHP_V8_THROW_EXCEPTION (" Callback has no stored callback function" );
237+ return ;
238+ }
299239
300- zend_fcall_info fci = cb->fci ;
301- zend_fcall_info_cache fci_cache = cb->fci_cache ;
240+ zend_fcall_info fci = cb->fci () ;
241+ zend_fcall_info_cache fci_cache = cb->fci_cache () ;
302242
303243 /* Convert everything to be callable */
304244 zend_fcall_info_args (&fci, args);
0 commit comments