Skip to content
This repository was archived by the owner on Mar 29, 2024. It is now read-only.

Commit 53931b5

Browse files
authored
Merge pull request #6 from pinepain/external_memory
Refactor callbacks and add external allocated memory notification
2 parents 5b51ced + aa50b52 commit 53931b5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1092
-478
lines changed

config.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ if test "$PHP_V8" != "no"; then
187187
v8.cc \
188188
src/php_v8_a.cc \
189189
src/php_v8_exception.cc \
190+
src/php_v8_ext_mem_interface.cc \
190191
src/php_v8_try_catch.cc \
191192
src/php_v8_message.cc \
192193
src/php_v8_stack_frame.cc \

php_v8.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@ ZEND_TSRMLS_CACHE_EXTERN();
6969

7070
ZEND_EXTERN_MODULE_GLOBALS(v8);
7171

72-
#endif /* PHP_V8_H */
73-
72+
#endif //PHP_V8_H
7473

7574
/*
7675
* Local variables:

src/php_v8_callbacks.cc

Lines changed: 113 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -31,218 +31,171 @@
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

287240
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;
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

Comments
 (0)