Skip to content

Commit 34e58a6

Browse files
committed
Reduced overhead of magic method calls (__get/__set/__unset/__isset/__dectructor/__clone).
1 parent 3c600e2 commit 34e58a6

File tree

2 files changed

+116
-13
lines changed

2 files changed

+116
-13
lines changed

Zend/zend_object_handlers.c

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ static void zend_std_call_getter(zval *object, zval *member, zval *retval) /* {{
179179
{
180180
zend_class_entry *ce = Z_OBJCE_P(object);
181181
zend_class_entry *orig_fake_scope = EG(fake_scope);
182+
zend_fcall_info fci;
183+
zend_fcall_info_cache fcic;
182184

183185
EG(fake_scope) = NULL;
184186

@@ -187,7 +189,20 @@ static void zend_std_call_getter(zval *object, zval *member, zval *retval) /* {{
187189
188190
it should return whether the call was successful or not
189191
*/
190-
zend_call_method_with_1_params(object, ce, &ce->__get, ZEND_GET_FUNC_NAME, retval, member);
192+
193+
fci.size = sizeof(fci);
194+
fci.object = Z_OBJ_P(object);
195+
fci.retval = retval;
196+
fci.param_count = 1;
197+
fci.params = member;
198+
fci.no_separation = 1;
199+
ZVAL_UNDEF(&fci.function_name); /* Unused */
200+
201+
fcic.function_handler = ce->__get;
202+
fcic.called_scope = ce;
203+
fcic.object = Z_OBJ_P(object);
204+
205+
zend_call_function(&fci, &fcic);
191206

192207
EG(fake_scope) = orig_fake_scope;
193208
}
@@ -197,14 +212,35 @@ static void zend_std_call_setter(zval *object, zval *member, zval *value) /* {{{
197212
{
198213
zend_class_entry *ce = Z_OBJCE_P(object);
199214
zend_class_entry *orig_fake_scope = EG(fake_scope);
215+
zend_fcall_info fci;
216+
zend_fcall_info_cache fcic;
217+
zval args[2], ret;
200218

201219
EG(fake_scope) = NULL;
202220

203221
/* __set handler is called with two arguments:
204222
property name
205223
value to be set
206224
*/
207-
zend_call_method_with_2_params(object, ce, &ce->__set, ZEND_SET_FUNC_NAME, NULL, member, value);
225+
226+
ZVAL_COPY_VALUE(&args[0], member);
227+
ZVAL_COPY_VALUE(&args[1], value);
228+
ZVAL_UNDEF(&ret);
229+
230+
fci.size = sizeof(fci);
231+
fci.object = Z_OBJ_P(object);
232+
fci.retval = &ret;
233+
fci.param_count = 2;
234+
fci.params = args;
235+
fci.no_separation = 1;
236+
ZVAL_UNDEF(&fci.function_name); /* Unused */
237+
238+
fcic.function_handler = ce->__set;
239+
fcic.called_scope = ce;
240+
fcic.object = Z_OBJ_P(object);
241+
242+
zend_call_function(&fci, &fcic);
243+
zval_ptr_dtor(&ret);
208244

209245
EG(fake_scope) = orig_fake_scope;
210246
}
@@ -214,14 +250,32 @@ static void zend_std_call_unsetter(zval *object, zval *member) /* {{{ */
214250
{
215251
zend_class_entry *ce = Z_OBJCE_P(object);
216252
zend_class_entry *orig_fake_scope = EG(fake_scope);
253+
zend_fcall_info fci;
254+
zend_fcall_info_cache fcic;
255+
zval ret;
217256

218257
EG(fake_scope) = NULL;
219258

220259
/* __unset handler is called with one argument:
221260
property name
222261
*/
223262

224-
zend_call_method_with_1_params(object, ce, &ce->__unset, ZEND_UNSET_FUNC_NAME, NULL, member);
263+
ZVAL_UNDEF(&ret);
264+
265+
fci.size = sizeof(fci);
266+
fci.object = Z_OBJ_P(object);
267+
fci.retval = &ret;
268+
fci.param_count = 1;
269+
fci.params = member;
270+
fci.no_separation = 1;
271+
ZVAL_UNDEF(&fci.function_name); /* Unused */
272+
273+
fcic.function_handler = ce->__unset;
274+
fcic.called_scope = ce;
275+
fcic.object = Z_OBJ_P(object);
276+
277+
zend_call_function(&fci, &fcic);
278+
zval_ptr_dtor(&ret);
225279

226280
EG(fake_scope) = orig_fake_scope;
227281
}
@@ -231,6 +285,8 @@ static void zend_std_call_issetter(zval *object, zval *member, zval *retval) /*
231285
{
232286
zend_class_entry *ce = Z_OBJCE_P(object);
233287
zend_class_entry *orig_fake_scope = EG(fake_scope);
288+
zend_fcall_info fci;
289+
zend_fcall_info_cache fcic;
234290

235291
EG(fake_scope) = NULL;
236292

@@ -240,7 +296,19 @@ static void zend_std_call_issetter(zval *object, zval *member, zval *retval) /*
240296
it should return whether the property is set or not
241297
*/
242298

243-
zend_call_method_with_1_params(object, ce, &ce->__isset, ZEND_ISSET_FUNC_NAME, retval, member);
299+
fci.size = sizeof(fci);
300+
fci.object = Z_OBJ_P(object);
301+
fci.retval = retval;
302+
fci.param_count = 1;
303+
fci.params = member;
304+
fci.no_separation = 1;
305+
ZVAL_UNDEF(&fci.function_name); /* Unused */
306+
307+
fcic.function_handler = ce->__isset;
308+
fcic.called_scope = ce;
309+
fcic.object = Z_OBJ_P(object);
310+
311+
zend_call_function(&fci, &fcic);
244312

245313
EG(fake_scope) = orig_fake_scope;
246314
}

Zend/zend_objects.c

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
7878

7979
if (destructor) {
8080
zend_object *old_exception;
81-
zval obj;
8281
zend_class_entry *orig_fake_scope;
82+
zend_fcall_info fci;
83+
zend_fcall_info_cache fcic;
84+
zval ret;
8385

8486
if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
8587
if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
@@ -124,7 +126,6 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
124126
}
125127

126128
GC_ADDREF(object);
127-
ZVAL_OBJ(&obj, object);
128129

129130
/* Make sure that destructors are protected from previously thrown exceptions.
130131
* For example, if an exception was thrown in a function and when the function's
@@ -141,15 +142,32 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
141142
}
142143
orig_fake_scope = EG(fake_scope);
143144
EG(fake_scope) = NULL;
144-
zend_call_method_with_0_params(&obj, object->ce, &destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
145+
146+
ZVAL_UNDEF(&ret);
147+
148+
fci.size = sizeof(fci);
149+
fci.object = object;
150+
fci.retval = &ret;
151+
fci.param_count = 0;
152+
fci.params = NULL;
153+
fci.no_separation = 1;
154+
ZVAL_UNDEF(&fci.function_name); /* Unused */
155+
156+
fcic.function_handler = destructor;
157+
fcic.called_scope = object->ce;
158+
fcic.object = object;
159+
160+
zend_call_function(&fci, &fcic);
161+
zval_ptr_dtor(&ret);
162+
145163
if (old_exception) {
146164
if (EG(exception)) {
147165
zend_exception_set_previous(EG(exception), old_exception);
148166
} else {
149167
EG(exception) = old_exception;
150168
}
151169
}
152-
zval_ptr_dtor(&obj);
170+
OBJ_RELEASE(object);
153171
EG(fake_scope) = orig_fake_scope;
154172
}
155173
}
@@ -220,12 +238,29 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object,
220238
}
221239

222240
if (old_object->ce->clone) {
223-
zval new_obj;
241+
zend_fcall_info fci;
242+
zend_fcall_info_cache fcic;
243+
zval ret;
244+
245+
GC_ADDREF(new_object);
246+
247+
ZVAL_UNDEF(&ret);
248+
249+
fci.size = sizeof(fci);
250+
fci.object = new_object;
251+
fci.retval = &ret;
252+
fci.param_count = 0;
253+
fci.params = NULL;
254+
fci.no_separation = 1;
255+
ZVAL_UNDEF(&fci.function_name); /* Unused */
256+
257+
fcic.function_handler = new_object->ce->clone;
258+
fcic.called_scope = new_object->ce;
259+
fcic.object = new_object;
224260

225-
ZVAL_OBJ(&new_obj, new_object);
226-
Z_ADDREF(new_obj);
227-
zend_call_method_with_0_params(&new_obj, old_object->ce, &old_object->ce->clone, ZEND_CLONE_FUNC_NAME, NULL);
228-
zval_ptr_dtor(&new_obj);
261+
zend_call_function(&fci, &fcic);
262+
zval_ptr_dtor(&ret);
263+
OBJ_RELEASE(new_object);
229264
}
230265
}
231266

0 commit comments

Comments
 (0)