Skip to content

Commit 769d1d5

Browse files
committed
Support internal magical __call/__callStatic
1 parent a980fed commit 769d1d5

File tree

3 files changed

+100
-54
lines changed

3 files changed

+100
-54
lines changed

Zend/zend_object_handlers.c

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,15 +1037,18 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
10371037

10381038
static inline zend_op_array *zend_get_proxy_call_function(zend_class_entry *ce, zend_string *method_name, int is_static) /* {{{ */ {
10391039
zend_op_array *call_user_call = ecalloc(1, ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array)) + sizeof(zend_op));
1040+
zend_function *fbc = is_static? ce->__callstatic : ce->__call;
10401041

1041-
ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
1042+
ZEND_ASSERT(fbc);
10421043

10431044
call_user_call->type = ZEND_USER_FUNCTION;
10441045
call_user_call->scope = ce;
1045-
call_user_call->prototype = is_static? ce->__callstatic : ce->__call;
1046+
call_user_call->prototype = fbc;
10461047
call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER | (is_static? (ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) : 0);
10471048
call_user_call->this_var = -1;
1048-
call_user_call->filename = is_static? ce->__callstatic->op_array. filename : ce->__call->op_array.filename;
1049+
call_user_call->filename = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.filename : STR_EMPTY_ALLOC();
1050+
call_user_call->line_start = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_start : 0;
1051+
call_user_call->line_end = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_end : 0;
10491052
call_user_call->opcodes = (zend_op *)((char *)call_user_call + ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array)));
10501053
call_user_call->opcodes[0].opcode = ZEND_PROXY_CALL;
10511054
call_user_call->opcodes[0].op1_type = IS_UNUSED;
@@ -1064,26 +1067,7 @@ static inline zend_op_array *zend_get_proxy_call_function(zend_class_entry *ce,
10641067

10651068
static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
10661069
{
1067-
if (ce->type == ZEND_USER_CLASS) {
1068-
return (union _zend_function *)zend_get_proxy_call_function(ce, method_name, 0);
1069-
} else {
1070-
zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
1071-
call_user_call->type = ZEND_INTERNAL_FUNCTION;
1072-
call_user_call->module = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL;
1073-
call_user_call->handler = zend_std_call_user_call;
1074-
call_user_call->arg_info = NULL;
1075-
call_user_call->num_args = 0;
1076-
call_user_call->scope = ce;
1077-
call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
1078-
//??? keep compatibility for "\0" characters
1079-
//??? see: Zend/tests/bug46238.phpt
1080-
if (UNEXPECTED(strlen(method_name->val) != method_name->len)) {
1081-
call_user_call->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0);
1082-
} else {
1083-
call_user_call->function_name = zend_string_copy(method_name);
1084-
}
1085-
return (union _zend_function *)call_user_call;
1086-
}
1070+
return (union _zend_function *)zend_get_proxy_call_function(ce, method_name, 0);
10871071
}
10881072
/* }}} */
10891073

@@ -1214,27 +1198,7 @@ ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{
12141198

12151199
static inline union _zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
12161200
{
1217-
if (ce->type == ZEND_USER_CLASS) {
1218-
return (union _zend_function *)zend_get_proxy_call_function(ce, method_name, 1);
1219-
} else {
1220-
zend_internal_function *callstatic_user_call = emalloc(sizeof(zend_internal_function));
1221-
callstatic_user_call->type = ZEND_INTERNAL_FUNCTION;
1222-
callstatic_user_call->module = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL;
1223-
callstatic_user_call->handler = zend_std_callstatic_user_call;
1224-
callstatic_user_call->arg_info = NULL;
1225-
callstatic_user_call->num_args = 0;
1226-
callstatic_user_call->scope = ce;
1227-
callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
1228-
//??? keep compatibility for "\0" characters
1229-
//??? see: Zend/tests/bug46238.phpt
1230-
if (UNEXPECTED(strlen(method_name->val) != method_name->len)) {
1231-
callstatic_user_call->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0);
1232-
} else {
1233-
callstatic_user_call->function_name = zend_string_copy(method_name);
1234-
}
1235-
1236-
return (zend_function *)callstatic_user_call;
1237-
}
1201+
return (union _zend_function *)zend_get_proxy_call_function(ce, method_name, 1);
12381202
}
12391203
/* }}} */
12401204

Zend/zend_vm_def.h

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7564,7 +7564,7 @@ ZEND_VM_HANDLER(158, ZEND_PROXY_CALL, ANY, ANY)
75647564
zval args;
75657565
zend_function *fbc = EX(func);
75667566
zend_object *obj = Z_OBJ(EX(This));
7567-
zval *return_value = EX(return_value);
7567+
zval *ret = EX(return_value);
75687568
zend_call_kind call_kind = EX_CALL_KIND();
75697569
uint32_t num_args = EX_NUM_ARGS();
75707570
zend_execute_data *call, *prev_execute_data = EX(prev_execute_data);
@@ -7585,17 +7585,58 @@ ZEND_VM_HANDLER(158, ZEND_PROXY_CALL, ANY, ANY)
75857585
}
75867586

75877587
zend_vm_stack_free_call_frame(execute_data);
7588+
75887589
call = zend_vm_stack_push_call_frame(call_kind,
75897590
fbc->common.prototype, 2, fbc->common.scope, obj, prev_execute_data);
75907591

75917592
ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name);
75927593
ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, 2), &args);
7594+
if (call->func->type == ZEND_USER_FUNCTION) {
7595+
call->symbol_table = NULL;
7596+
i_init_func_execute_data(call, &call->func->op_array,
7597+
ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
75937598

7599+
efree(fbc);
75947600

7595-
call->symbol_table = NULL;
7596-
i_init_func_execute_data(call, &call->func->op_array, return_value, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
7601+
ZEND_VM_ENTER();
7602+
} else {
7603+
zval retval;
7604+
7605+
ZEND_ASSERT(call->func->type == ZEND_INTERNAL_FUNCTION);
7606+
SAVE_OPLINE();
7607+
7608+
if (ret == NULL) {
7609+
ZVAL_NULL(&retval);
7610+
ret = &retval;
7611+
}
75977612

7598-
efree(fbc);
7613+
Z_VAR_FLAGS_P(ret) = (call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
75997614

7600-
ZEND_VM_ENTER();
7615+
EG(current_execute_data) = call;
7616+
7617+
call->func->internal_function.handler(call, ret);
7618+
7619+
execute_data = EG(current_execute_data) = call->prev_execute_data;
7620+
7621+
efree(fbc);
7622+
7623+
zend_vm_stack_free_args(call);
7624+
zend_vm_stack_free_call_frame(call);
7625+
7626+
if (ret == &retval) {
7627+
zval_ptr_dtor(ret);
7628+
}
7629+
7630+
if (UNEXPECTED(EG(exception) != NULL)) {
7631+
zend_throw_exception_internal(NULL);
7632+
if (ret != &retval) {
7633+
zval_ptr_dtor(ret);
7634+
}
7635+
HANDLE_EXCEPTION_LEAVE();
7636+
}
7637+
7638+
LOAD_OPLINE();
7639+
ZEND_VM_INC_OPCODE();
7640+
ZEND_VM_LEAVE();
7641+
}
76017642
}

Zend/zend_vm_execute.h

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,7 +1778,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PROXY_CALL_SPEC_HANDLER(ZEND_O
17781778
zval args;
17791779
zend_function *fbc = EX(func);
17801780
zend_object *obj = Z_OBJ(EX(This));
1781-
zval *return_value = EX(return_value);
1781+
zval *ret = EX(return_value);
17821782
zend_call_kind call_kind = EX_CALL_KIND();
17831783
uint32_t num_args = EX_NUM_ARGS();
17841784
zend_execute_data *call, *prev_execute_data = EX(prev_execute_data);
@@ -1799,19 +1799,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PROXY_CALL_SPEC_HANDLER(ZEND_O
17991799
}
18001800

18011801
zend_vm_stack_free_call_frame(execute_data);
1802+
18021803
call = zend_vm_stack_push_call_frame(call_kind,
18031804
fbc->common.prototype, 2, fbc->common.scope, obj, prev_execute_data);
18041805

18051806
ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name);
18061807
ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, 2), &args);
1808+
if (call->func->type == ZEND_USER_FUNCTION) {
1809+
call->symbol_table = NULL;
1810+
i_init_func_execute_data(call, &call->func->op_array,
1811+
ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
18071812

1813+
efree(fbc);
18081814

1809-
call->symbol_table = NULL;
1810-
i_init_func_execute_data(call, &call->func->op_array, return_value, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
1815+
ZEND_VM_ENTER();
1816+
} else {
1817+
zval retval;
18111818

1812-
efree(fbc);
1819+
ZEND_ASSERT(call->func->type == ZEND_INTERNAL_FUNCTION);
1820+
SAVE_OPLINE();
18131821

1814-
ZEND_VM_ENTER();
1822+
if (ret == NULL) {
1823+
ZVAL_NULL(&retval);
1824+
ret = &retval;
1825+
}
1826+
1827+
Z_VAR_FLAGS_P(ret) = (call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
1828+
1829+
EG(current_execute_data) = call;
1830+
1831+
call->func->internal_function.handler(call, ret);
1832+
1833+
execute_data = EG(current_execute_data) = call->prev_execute_data;
1834+
1835+
efree(fbc);
1836+
1837+
zend_vm_stack_free_args(call);
1838+
zend_vm_stack_free_call_frame(call);
1839+
1840+
if (ret == &retval) {
1841+
zval_ptr_dtor(ret);
1842+
}
1843+
1844+
if (UNEXPECTED(EG(exception) != NULL)) {
1845+
zend_throw_exception_internal(NULL);
1846+
if (ret != &retval) {
1847+
zval_ptr_dtor(ret);
1848+
}
1849+
HANDLE_EXCEPTION_LEAVE();
1850+
}
1851+
1852+
LOAD_OPLINE();
1853+
ZEND_VM_INC_OPCODE();
1854+
ZEND_VM_LEAVE();
1855+
}
18151856
}
18161857
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
18171858
{

0 commit comments

Comments
 (0)