Skip to content

Commit a980fed

Browse files
committed
opcode-fy magical __callStatic
1 parent 73855f7 commit a980fed

File tree

3 files changed

+53
-39
lines changed

3 files changed

+53
-39
lines changed

Zend/zend_object_handlers.c

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,29 +1035,37 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
10351035
}
10361036
/* }}} */
10371037

1038+
static inline zend_op_array *zend_get_proxy_call_function(zend_class_entry *ce, zend_string *method_name, int is_static) /* {{{ */ {
1039+
zend_op_array *call_user_call = ecalloc(1, ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array)) + sizeof(zend_op));
1040+
1041+
ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
1042+
1043+
call_user_call->type = ZEND_USER_FUNCTION;
1044+
call_user_call->scope = ce;
1045+
call_user_call->prototype = is_static? ce->__callstatic : ce->__call;
1046+
call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER | (is_static? (ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) : 0);
1047+
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->opcodes = (zend_op *)((char *)call_user_call + ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array)));
1050+
call_user_call->opcodes[0].opcode = ZEND_PROXY_CALL;
1051+
call_user_call->opcodes[0].op1_type = IS_UNUSED;
1052+
call_user_call->opcodes[0].op2_type = IS_UNUSED;
1053+
call_user_call->opcodes[0].result_type = IS_UNUSED;
1054+
ZEND_VM_SET_OPCODE_HANDLER(&call_user_call->opcodes[0]);
1055+
if (UNEXPECTED(strlen(method_name->val) != method_name->len)) {
1056+
call_user_call->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0);
1057+
} else {
1058+
call_user_call->function_name = zend_string_copy(method_name);
1059+
}
1060+
1061+
return call_user_call;
1062+
}
1063+
/* }}} */
1064+
10381065
static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
10391066
{
10401067
if (ce->type == ZEND_USER_CLASS) {
1041-
zend_op_array *call_user_call = ecalloc(1, ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array)) + sizeof(zend_op));
1042-
call_user_call->type = ZEND_USER_FUNCTION;
1043-
call_user_call->scope = ce;
1044-
call_user_call->prototype = ce->__call;
1045-
call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
1046-
call_user_call->this_var = -1;
1047-
call_user_call->filename = ce->__call->op_array.filename;
1048-
call_user_call->opcodes = (zend_op *)((char *)call_user_call + ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array)));
1049-
call_user_call->opcodes[0].opcode = ZEND_PROXY_CALL;
1050-
call_user_call->opcodes[0].op1_type = IS_UNUSED;
1051-
call_user_call->opcodes[0].op2_type = IS_UNUSED;
1052-
call_user_call->opcodes[0].result_type = IS_UNUSED;
1053-
ZEND_VM_SET_OPCODE_HANDLER(&call_user_call->opcodes[0]);
1054-
1055-
if (UNEXPECTED(strlen(method_name->val) != method_name->len)) {
1056-
call_user_call->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0);
1057-
} else {
1058-
call_user_call->function_name = zend_string_copy(method_name);
1059-
}
1060-
return (union _zend_function *)call_user_call;
1068+
return (union _zend_function *)zend_get_proxy_call_function(ce, method_name, 0);
10611069
} else {
10621070
zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
10631071
call_user_call->type = ZEND_INTERNAL_FUNCTION;
@@ -1206,23 +1214,27 @@ ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{
12061214

12071215
static inline union _zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
12081216
{
1209-
zend_internal_function *callstatic_user_call = emalloc(sizeof(zend_internal_function));
1210-
callstatic_user_call->type = ZEND_INTERNAL_FUNCTION;
1211-
callstatic_user_call->module = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL;
1212-
callstatic_user_call->handler = zend_std_callstatic_user_call;
1213-
callstatic_user_call->arg_info = NULL;
1214-
callstatic_user_call->num_args = 0;
1215-
callstatic_user_call->scope = ce;
1216-
callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
1217-
//??? keep compatibility for "\0" characters
1218-
//??? see: Zend/tests/bug46238.phpt
1219-
if (UNEXPECTED(strlen(method_name->val) != method_name->len)) {
1220-
callstatic_user_call->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0);
1217+
if (ce->type == ZEND_USER_CLASS) {
1218+
return (union _zend_function *)zend_get_proxy_call_function(ce, method_name, 1);
12211219
} else {
1222-
callstatic_user_call->function_name = zend_string_copy(method_name);
1223-
}
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+
}
12241235

1225-
return (zend_function *)callstatic_user_call;
1236+
return (zend_function *)callstatic_user_call;
1237+
}
12261238
}
12271239
/* }}} */
12281240

Zend/zend_vm_def.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7591,10 +7591,11 @@ ZEND_VM_HANDLER(158, ZEND_PROXY_CALL, ANY, ANY)
75917591
ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name);
75927592
ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, 2), &args);
75937593

7594-
efree(fbc);
75957594

75967595
call->symbol_table = NULL;
7597-
i_init_func_execute_data(call, &call->func->op_array, return_value, 1);
7596+
i_init_func_execute_data(call, &call->func->op_array, return_value, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
7597+
7598+
efree(fbc);
75987599

75997600
ZEND_VM_ENTER();
76007601
}

Zend/zend_vm_execute.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,10 +1805,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PROXY_CALL_SPEC_HANDLER(ZEND_O
18051805
ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name);
18061806
ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, 2), &args);
18071807

1808-
efree(fbc);
18091808

18101809
call->symbol_table = NULL;
1811-
i_init_func_execute_data(call, &call->func->op_array, return_value, 1);
1810+
i_init_func_execute_data(call, &call->func->op_array, return_value, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
1811+
1812+
efree(fbc);
18121813

18131814
ZEND_VM_ENTER();
18141815
}

0 commit comments

Comments
 (0)