Skip to content

Commit f45e0ce

Browse files
committed
Remove ZEND_OVERLOADED_FUNCTION and corresponding call_method object handler
1 parent 2306c85 commit f45e0ce

18 files changed

+94
-259
lines changed

UPGRADING.INTERNALS

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ PHP 8.0 INTERNALS UPGRADE NOTES
22

33
1. Internal API changes
44
a. Object Handlers API
5+
b. ZEND_OVERLOADED_FUNCTION and corresponding call_method() object handler
56

67
2. Build system changes
78
a. Abstract
@@ -14,10 +15,15 @@ PHP 8.0 INTERNALS UPGRADE NOTES
1415
1. Internal API changes
1516
========================
1617

17-
a. Object Handlers API and some related functions, e.g. zend_call_method() and
18-
zend_objects_clone_obj() were changed to receive zend_object* instead of
19-
zval* and zend_string* instead of zval* for property names.
18+
a. Object Handlers API and some related functions, e.g. zend_call_method() and
19+
zend_objects_clone_obj() were changed to receive zend_object* instead of
20+
zval* and zend_string* instead of zval* for property names.
2021

22+
b. ZEND_OVERLOADED_FUNCTION and corresponding call_method() object handler
23+
were removed. ZEND_INTERNAL_FUNCTION with ZEND_ACC_CALL_VIA_HANDLER and
24+
defined "handler" callback should be used instead. This "handler" callback
25+
should also take care about function cleanup. See ext/zend_test/test.c
26+
for example.
2127

2228
========================
2329
2. Build system changes

Zend/tests/overloaded_func_001.phpt

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ if (!extension_loaded('zend-test')) die('skip zend-test extension not loaded');
66
?>
77
--FILE--
88
<?php
9+
$o = new _ZendTestChildClass();
10+
var_dump($o->test());
911
var_dump(_ZendTestClass::test());
1012
?>
11-
--EXPECTF--
12-
Fatal error: Uncaught Error: Cannot call overloaded function for non-object in %soverloaded_func_001.php:%d
13-
Stack trace:
14-
#0 {main}
15-
thrown in %soverloaded_func_001.php on line %d
13+
--EXPECT--
14+
string(4) "test"
15+
string(4) "test"

Zend/zend_API.c

+5-13
Original file line numberDiff line numberDiff line change
@@ -3014,8 +3014,7 @@ static zend_always_inline int zend_is_callable_check_func(int check_flags, zval
30143014
(!fcc->function_handler->common.scope ||
30153015
!instanceof_function(ce_org, fcc->function_handler->common.scope))) {
30163016
if (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
3017-
if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION &&
3018-
fcc->function_handler->common.function_name) {
3017+
if (fcc->function_handler->common.function_name) {
30193018
zend_string_release_ex(fcc->function_handler->common.function_name, 0);
30203019
}
30213020
zend_free_trampoline(fcc->function_handler);
@@ -3206,11 +3205,8 @@ static zend_always_inline zend_bool zend_is_callable_impl(zval *callable, zend_o
32063205
ret = zend_is_callable_check_func(check_flags, callable, fcc, strict_class, error);
32073206
if (fcc == &fcc_local &&
32083207
fcc->function_handler &&
3209-
((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) ||
3210-
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
3211-
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
3212-
if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION &&
3213-
fcc->function_handler->common.function_name) {
3208+
(fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
3209+
if (fcc->function_handler->common.function_name) {
32143210
zend_string_release_ex(fcc->function_handler->common.function_name, 0);
32153211
}
32163212
zend_free_trampoline(fcc->function_handler);
@@ -3322,12 +3318,8 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam
33223318
add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
33233319
}
33243320
if (fcc.function_handler &&
3325-
((fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) ||
3326-
fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
3327-
fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
3328-
if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) {
3329-
zend_string_release_ex(fcc.function_handler->common.function_name, 0);
3330-
}
3321+
(fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
3322+
zend_string_release_ex(fcc.function_handler->common.function_name, 0);
33313323
zend_free_trampoline(fcc.function_handler);
33323324
}
33333325
return 1;

Zend/zend_compile.h

-2
Original file line numberDiff line numberDiff line change
@@ -875,9 +875,7 @@ void zend_assert_valid_class_name(const zend_string *const_name);
875875

876876
#define ZEND_INTERNAL_FUNCTION 1
877877
#define ZEND_USER_FUNCTION 2
878-
#define ZEND_OVERLOADED_FUNCTION 3
879878
#define ZEND_EVAL_CODE 4
880-
#define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5
881879

882880
/* A quick check (type == ZEND_USER_FUNCTION || type == ZEND_EVAL_CODE) */
883881
#define ZEND_USER_CODE(type) ((type & 1) == 0)

Zend/zend_execute.c

-37
Original file line numberDiff line numberDiff line change
@@ -4069,43 +4069,6 @@ static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(zval
40694069
}
40704070
/* }}} */
40714071

4072-
ZEND_API int ZEND_FASTCALL zend_do_fcall_overloaded(zend_execute_data *call, zval *ret) /* {{{ */
4073-
{
4074-
zend_function *fbc = call->func;
4075-
zend_object *object;
4076-
4077-
/* Not sure what should be done here if it's a static method */
4078-
if (UNEXPECTED(Z_TYPE(call->This) != IS_OBJECT)) {
4079-
zend_vm_stack_free_args(call);
4080-
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
4081-
zend_string_release_ex(fbc->common.function_name, 0);
4082-
}
4083-
efree(fbc);
4084-
zend_vm_stack_free_call_frame(call);
4085-
4086-
zend_throw_error(NULL, "Cannot call overloaded function for non-object");
4087-
return 0;
4088-
}
4089-
4090-
object = Z_OBJ(call->This);
4091-
4092-
ZVAL_NULL(ret);
4093-
4094-
EG(current_execute_data) = call;
4095-
object->handlers->call_method(fbc->common.function_name, object, call, ret);
4096-
EG(current_execute_data) = call->prev_execute_data;
4097-
4098-
zend_vm_stack_free_args(call);
4099-
4100-
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
4101-
zend_string_release_ex(fbc->common.function_name, 0);
4102-
}
4103-
efree(fbc);
4104-
4105-
return 1;
4106-
}
4107-
/* }}} */
4108-
41094072
static zend_never_inline zend_bool ZEND_FASTCALL zend_fe_reset_iterator(zval *array_ptr, int by_ref OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
41104073
{
41114074
zend_class_entry *ce = Z_OBJCE_P(array_ptr);

Zend/zend_execute.h

-2
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,6 @@ ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table);
375375
ZEND_API void zend_free_compiled_variables(zend_execute_data *execute_data);
376376
ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num);
377377

378-
ZEND_API int ZEND_FASTCALL zend_do_fcall_overloaded(zend_execute_data *call, zval *ret);
379-
380378
#define CACHE_ADDR(num) \
381379
((void**)((char*)EX_RUN_TIME_CACHE() + (num)))
382380

Zend/zend_execute_API.c

+3-25
Original file line numberDiff line numberDiff line change
@@ -772,8 +772,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
772772
/* We must re-initialize function again */
773773
fci_cache->function_handler = NULL;
774774
}
775-
} else if (func->type == ZEND_INTERNAL_FUNCTION) {
775+
} else {
776776
int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
777+
778+
ZEND_ASSERT(func->type == ZEND_INTERNAL_FUNCTION);
777779
ZVAL_NULL(fci->retval);
778780
call->prev_execute_data = EG(current_execute_data);
779781
call->return_value = NULL; /* this is not a constructor call */
@@ -796,30 +798,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
796798
/* We must re-initialize function again */
797799
fci_cache->function_handler = NULL;
798800
}
799-
} else { /* ZEND_OVERLOADED_FUNCTION */
800-
ZVAL_NULL(fci->retval);
801-
802-
/* Not sure what should be done here if it's a static method */
803-
if (fci->object) {
804-
call->prev_execute_data = EG(current_execute_data);
805-
EG(current_execute_data) = call;
806-
fci->object->handlers->call_method(func->common.function_name, fci->object, call, fci->retval);
807-
EG(current_execute_data) = call->prev_execute_data;
808-
} else {
809-
zend_throw_error(NULL, "Cannot call overloaded function for non-object");
810-
}
811-
812-
zend_vm_stack_free_args(call);
813-
814-
if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
815-
zend_string_release_ex(func->common.function_name, 0);
816-
}
817-
efree(func);
818-
819-
if (EG(exception)) {
820-
zval_ptr_dtor(fci->retval);
821-
ZVAL_UNDEF(fci->retval);
822-
}
823801
}
824802

825803
zend_vm_stack_free_call_frame(call);

Zend/zend_iterators.c

-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ static const zend_object_handlers iterator_object_handlers = {
4444
NULL, /* unset dim */
4545
NULL, /* props get */
4646
NULL, /* method get */
47-
NULL, /* call */
4847
NULL, /* get ctor */
4948
NULL, /* get class name */
5049
NULL, /* compare */

Zend/zend_object_handlers.c

-1
Original file line numberDiff line numberDiff line change
@@ -1845,7 +1845,6 @@ ZEND_API const zend_object_handlers std_object_handlers = {
18451845
zend_std_unset_dimension, /* unset_dimension */
18461846
zend_std_get_properties, /* get_properties */
18471847
zend_std_get_method, /* get_method */
1848-
NULL, /* call_method */
18491848
zend_std_get_constructor, /* get_constructor */
18501849
zend_std_get_class_name, /* get_class_name */
18511850
zend_std_compare_objects, /* compare_objects */

Zend/zend_object_handlers.h

-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ typedef zend_array *(*zend_object_get_properties_for_t)(zend_object *object, zen
120120
/* args on stack! */
121121
/* Andi - EX(fbc) (function being called) needs to be initialized already in the INIT fcall opcode so that the parameters can be parsed the right way. We need to add another callback for this.
122122
*/
123-
typedef int (*zend_object_call_method_t)(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS);
124123
typedef zend_function *(*zend_object_get_method_t)(zend_object **object, zend_string *method, const zval *key);
125124
typedef zend_function *(*zend_object_get_constructor_t)(zend_object *object);
126125

@@ -171,7 +170,6 @@ struct _zend_object_handlers {
171170
zend_object_unset_dimension_t unset_dimension; /* required */
172171
zend_object_get_properties_t get_properties; /* required */
173172
zend_object_get_method_t get_method; /* required */
174-
zend_object_call_method_t call_method; /* optional */
175173
zend_object_get_constructor_t get_constructor; /* required */
176174
zend_object_get_class_name_t get_class_name; /* required */
177175
zend_object_compare_t compare_objects; /* optional */

Zend/zend_vm_def.h

+2-17
Original file line numberDiff line numberDiff line change
@@ -4019,9 +4019,10 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
40194019
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
40204020
zend_execute_ex(call);
40214021
}
4022-
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
4022+
} else {
40234023
zval retval;
40244024

4025+
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
40254026
call->prev_execute_data = execute_data;
40264027
EG(current_execute_data) = call;
40274028

@@ -4053,22 +4054,6 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
40534054
EG(current_execute_data) = execute_data;
40544055
zend_vm_stack_free_args(call);
40554056

4056-
if (!RETURN_VALUE_USED(opline)) {
4057-
zval_ptr_dtor(ret);
4058-
}
4059-
4060-
} else { /* ZEND_OVERLOADED_FUNCTION */
4061-
zval retval;
4062-
4063-
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
4064-
4065-
call->prev_execute_data = execute_data;
4066-
4067-
if (UNEXPECTED(!zend_do_fcall_overloaded(call, ret))) {
4068-
UNDEF_RESULT();
4069-
HANDLE_EXCEPTION();
4070-
}
4071-
40724057
if (!RETURN_VALUE_USED(opline)) {
40734058
zval_ptr_dtor(ret);
40744059
}

Zend/zend_vm_execute.h

+4-34
Original file line numberDiff line numberDiff line change
@@ -963,9 +963,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
963963
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
964964
zend_execute_ex(call);
965965
}
966-
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
966+
} else {
967967
zval retval;
968968

969+
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
969970
call->prev_execute_data = execute_data;
970971
EG(current_execute_data) = call;
971972

@@ -997,22 +998,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
997998
EG(current_execute_data) = execute_data;
998999
zend_vm_stack_free_args(call);
9991000

1000-
if (!0) {
1001-
zval_ptr_dtor(ret);
1002-
}
1003-
1004-
} else { /* ZEND_OVERLOADED_FUNCTION */
1005-
zval retval;
1006-
1007-
ret = 0 ? EX_VAR(opline->result.var) : &retval;
1008-
1009-
call->prev_execute_data = execute_data;
1010-
1011-
if (UNEXPECTED(!zend_do_fcall_overloaded(call, ret))) {
1012-
UNDEF_RESULT();
1013-
HANDLE_EXCEPTION();
1014-
}
1015-
10161001
if (!0) {
10171002
zval_ptr_dtor(ret);
10181003
}
@@ -1084,9 +1069,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
10841069
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
10851070
zend_execute_ex(call);
10861071
}
1087-
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
1072+
} else {
10881073
zval retval;
10891074

1075+
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
10901076
call->prev_execute_data = execute_data;
10911077
EG(current_execute_data) = call;
10921078

@@ -1118,22 +1104,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
11181104
EG(current_execute_data) = execute_data;
11191105
zend_vm_stack_free_args(call);
11201106

1121-
if (!1) {
1122-
zval_ptr_dtor(ret);
1123-
}
1124-
1125-
} else { /* ZEND_OVERLOADED_FUNCTION */
1126-
zval retval;
1127-
1128-
ret = 1 ? EX_VAR(opline->result.var) : &retval;
1129-
1130-
call->prev_execute_data = execute_data;
1131-
1132-
if (UNEXPECTED(!zend_do_fcall_overloaded(call, ret))) {
1133-
UNDEF_RESULT();
1134-
HANDLE_EXCEPTION();
1135-
}
1136-
11371107
if (!1) {
11381108
zval_ptr_dtor(ret);
11391109
}

0 commit comments

Comments
 (0)