31
31
32
32
#include " php_v8_value.h"
33
33
#include " php_v8_isolate.h"
34
+ #include < string>
35
+ #include < algorithm>
34
36
37
+ namespace phpv8 {
35
38
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 );
37
42
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
+ }
63
49
}
64
50
}
65
51
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 );
69
55
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
+ }
73
60
}
74
61
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 ;
83
64
84
- php_v8_callbacks_t ::iterator it = callbacks->find (internal_name);
65
+ if (fci_.size ) {
66
+ size += 1 ;
85
67
86
- if (it != callbacks->end ()) {
87
- efree (internal_name);
68
+ if (!Z_ISUNDEF (object_)) {
69
+ size += 1 ;
70
+ }
71
+ }
88
72
89
- return it-> second ;
73
+ return size ;
90
74
}
91
75
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 ) ;
95
79
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
+ }
103
83
}
104
84
}
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 );
112
85
113
- php_v8_callback_t *callback = (php_v8_callback_t *) ecalloc (1 , sizeof (*callback));
86
+ void CallbacksBucket::reset (CallbacksBucket *bucket) {
87
+ callbacks.clear ();
114
88
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 ;
124
91
}
125
92
}
126
93
127
- bucket->cb [index ] = callback;
94
+ phpv8::Callback *CallbacksBucket::get (size_t index) {
95
+ auto it = callbacks.find (index );
128
96
129
- return callback;
130
- }
97
+ if (it != callbacks.end ()) {
98
+ return it->second .get ();
99
+ }
131
100
132
- void php_v8_callbacks_cleanup (php_v8_callbacks_t *callbacks) {
133
- if (callbacks == NULL ) {
134
- return ;
101
+ return NULL ;
135
102
}
136
103
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);
140
106
}
141
- }
142
107
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 ;
144
110
145
- int size = php_v8_weak_callbacks_get_count (callbacks);
111
+ for (auto const &item : callbacks) {
112
+ size += item.second ->getGcCount ();
113
+ }
146
114
147
- if (*gc_data_count < size) {
148
- *gc_data = (zval *)safe_erealloc (*gc_data, size, sizeof (zval), 0 );
115
+ return size;
149
116
}
150
117
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
+ }
160
123
124
+ int PersistentData::getGcCount () {
125
+ int size = 0 ;
161
126
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
+ }
164
130
165
- if (!cb) {
166
131
return size;
167
132
}
168
133
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);
174
137
}
175
138
}
176
139
177
- return size;
178
- }
140
+ CallbacksBucket * PersistentData::bucket ( const char *prefix, bool is_symbol, const char *name) {
141
+ char *internal_name;
179
142
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);
182
144
183
- if (!bucket) {
184
- return size;
185
- }
145
+ std::string str_name (internal_name, size);
146
+ efree (internal_name);
186
147
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);
190
149
191
- return size;
192
- }
150
+ if (it != buckets.end ()) {
151
+ return it->second .get ();
152
+ }
193
153
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 ;
196
156
197
- if (callbacks == NULL || callbacks->empty ()) {
198
- return size;
157
+ return bucket.get ();
199
158
}
200
159
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 );
204
162
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
+ }
207
168
208
- void php_v8_callback_get_callback_zvals (php_v8_callback_t *cb, zval *& zv) {
209
- if (!cb) {
210
- return ;
169
+ return size;
211
170
}
212
171
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_;
219
175
}
220
176
}
221
177
178
+ void php_v8_callbacks_gc (phpv8::PersistentData *data, zval **gc_data, int * gc_data_count, zval **table, int *n) {
222
179
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 ();
227
181
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 );
230
184
}
231
- }
232
185
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;
237
187
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;
241
194
}
242
195
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) {
244
197
245
- int size = php_v8_callback_get_bucket_count ( bucket);
198
+ int size = bucket-> getGcCount ( );
246
199
247
200
if (*gc_data_count < size) {
248
201
*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
252
205
253
206
zval *local_gc_data = *gc_data;
254
207
255
- php_v8_callback_get_bucket_zvals ( bucket, local_gc_data);
208
+ bucket-> collectGcZvals ( local_gc_data);
256
209
257
210
*table = *gc_data;
258
211
*n = *gc_data_count;
@@ -285,20 +238,25 @@ static inline void php_v8_callback_set_retval_from_callback_info(v8::ReturnValue
285
238
286
239
287
240
void 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;
289
242
290
243
if (data.IsEmpty () || !data->IsExternal ()) {
291
244
PHP_V8_THROW_EXCEPTION (" Callback has no stored callback function" );
292
245
return ;
293
246
}
294
247
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 ());
297
249
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
+ }
299
257
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 () ;
302
260
303
261
/* Convert everything to be callable */
304
262
zend_fcall_info_args (&fci, args);
0 commit comments