mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Fix object overloading support
This commit is contained in:
parent
64f91d80fa
commit
e663d856b3
@ -186,7 +186,7 @@ typedef struct _zend_function_entry {
|
||||
typedef struct _zend_property_reference {
|
||||
int type; /* read, write or r/w */
|
||||
zval *object;
|
||||
zend_llist elements_list;
|
||||
zend_llist *elements_list;
|
||||
} zend_property_reference;
|
||||
|
||||
|
||||
|
@ -130,6 +130,16 @@ typedef struct _zend_internal_function {
|
||||
} zend_internal_function;
|
||||
|
||||
|
||||
typedef struct _zend_overloaded_function {
|
||||
zend_uchar type; /* MUST be the first element of this struct! */
|
||||
|
||||
zend_uchar *arg_types; /* MUST be the second element of this struct */
|
||||
char *function_name; /* MUST be the third element of this struct */
|
||||
|
||||
zend_uint var;
|
||||
} zend_overloaded_function;
|
||||
|
||||
|
||||
typedef union _zend_function {
|
||||
zend_uchar type; /* MUST be the first element of this struct! */
|
||||
struct {
|
||||
@ -140,6 +150,7 @@ typedef union _zend_function {
|
||||
|
||||
zend_op_array op_array;
|
||||
zend_internal_function internal_function;
|
||||
zend_overloaded_function overloaded_function;
|
||||
} zend_function;
|
||||
|
||||
|
||||
|
@ -54,9 +54,9 @@
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
static zval get_overloaded_property(ELS_D);
|
||||
static void set_overloaded_property(zval *value ELS_DC);
|
||||
static void call_overloaded_function(int arg_count, zval *return_value ELS_DC);
|
||||
static zval get_overloaded_property(temp_variable *T ELS_DC);
|
||||
static void set_overloaded_property(temp_variable *T, zval *value ELS_DC);
|
||||
static void call_overloaded_function(temp_variable *T, int arg_count, zval *return_value ELS_DC);
|
||||
static void zend_fetch_var_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type ELS_DC);
|
||||
static void zend_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type ELS_DC);
|
||||
static void zend_fetch_property_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type ELS_DC);
|
||||
@ -96,7 +96,7 @@ static inline zval *_get_zval_ptr(znode *node, temp_variable *Ts, int *should_fr
|
||||
|
||||
switch (Ts[node->u.var].EA.type) {
|
||||
case IS_OVERLOADED_OBJECT:
|
||||
Ts[node->u.var].tmp_var = get_overloaded_property(ELS_C);
|
||||
Ts[node->u.var].tmp_var = get_overloaded_property(&Ts[node->u.var] ELS_CC);
|
||||
Ts[node->u.var].tmp_var.refcount=1;
|
||||
Ts[node->u.var].tmp_var.is_ref=1;
|
||||
return &Ts[node->u.var].tmp_var;
|
||||
@ -262,7 +262,7 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2
|
||||
if (!variable_ptr_ptr) {
|
||||
switch (Ts[op1->u.var].EA.type) {
|
||||
case IS_OVERLOADED_OBJECT:
|
||||
set_overloaded_property(value ELS_CC);
|
||||
set_overloaded_property(&Ts[op1->u.var], value ELS_CC);
|
||||
if (type == IS_TMP_VAR) {
|
||||
zval_dtor(value);
|
||||
}
|
||||
@ -623,7 +623,6 @@ static void zend_fetch_dimension_address(znode *result, znode *op1, znode *op2,
|
||||
|
||||
|
||||
if (container_ptr == NULL) {
|
||||
zend_property_reference *property_reference;
|
||||
zend_overloaded_element overloaded_element;
|
||||
|
||||
if (Ts[op1->u.var].EA.type == IS_STRING_OFFSET) {
|
||||
@ -649,9 +648,8 @@ static void zend_fetch_dimension_address(znode *result, znode *op1, znode *op2,
|
||||
zval_copy_ctor(&overloaded_element.element);
|
||||
}
|
||||
|
||||
zend_stack_top(&EG(overloaded_objects_stack), (void **) &property_reference);
|
||||
|
||||
zend_llist_add_element(&property_reference->elements_list, &overloaded_element);
|
||||
Ts[result->u.var].EA = Ts[op1->u.var].EA;
|
||||
zend_llist_add_element(Ts[result->u.var].EA.data.overloaded_element.elements_list, &overloaded_element);
|
||||
|
||||
Ts[result->u.var].EA.type = IS_OVERLOADED_OBJECT;
|
||||
*retval = NULL;
|
||||
@ -786,7 +784,6 @@ static void zend_fetch_property_address(znode *result, znode *op1, znode *op2, t
|
||||
|
||||
|
||||
if (container_ptr == NULL) {
|
||||
zend_property_reference *property_reference;
|
||||
zend_overloaded_element overloaded_element;
|
||||
|
||||
if (Ts[op1->u.var].EA.type == IS_STRING_OFFSET) {
|
||||
@ -812,9 +809,8 @@ static void zend_fetch_property_address(znode *result, znode *op1, znode *op2, t
|
||||
zval_copy_ctor(&overloaded_element.element);
|
||||
}
|
||||
|
||||
zend_stack_top(&EG(overloaded_objects_stack), (void **) &property_reference);
|
||||
|
||||
zend_llist_add_element(&property_reference->elements_list, &overloaded_element);
|
||||
Ts[result->u.var].EA = Ts[op1->u.var].EA;
|
||||
zend_llist_add_element(Ts[result->u.var].EA.data.overloaded_element.elements_list, &overloaded_element);
|
||||
|
||||
Ts[result->u.var].EA.type = IS_OVERLOADED_OBJECT;
|
||||
*retval = NULL;
|
||||
@ -830,19 +826,18 @@ static void zend_fetch_property_address(znode *result, znode *op1, znode *op2, t
|
||||
|
||||
if (container->type == IS_OBJECT
|
||||
&& container->value.obj.ce->handle_property_get) {
|
||||
zend_property_reference property_reference;
|
||||
zend_overloaded_element overloaded_element;
|
||||
|
||||
property_reference.object = container;
|
||||
property_reference.type = type;
|
||||
zend_llist_init(&property_reference.elements_list, sizeof(zend_overloaded_element), NULL, 0);
|
||||
Ts[result->u.var].EA.data.overloaded_element.object = container;
|
||||
Ts[result->u.var].EA.data.overloaded_element.type = type;
|
||||
Ts[result->u.var].EA.data.overloaded_element.elements_list = (zend_llist *) emalloc(sizeof(zend_llist));
|
||||
zend_llist_init(Ts[result->u.var].EA.data.overloaded_element.elements_list, sizeof(zend_overloaded_element), NULL, 0);
|
||||
overloaded_element.element = *get_zval_ptr(op2, Ts, &free_op2, type);
|
||||
overloaded_element.type = OE_IS_OBJECT;
|
||||
if (!free_op2) {
|
||||
zval_copy_ctor(&overloaded_element.element);
|
||||
}
|
||||
zend_llist_add_element(&property_reference.elements_list, &overloaded_element);
|
||||
zend_stack_push(&EG(overloaded_objects_stack), &property_reference, sizeof(zend_property_reference));
|
||||
zend_llist_add_element(Ts[result->u.var].EA.data.overloaded_element.elements_list, &overloaded_element);
|
||||
Ts[result->u.var].EA.type = IS_OVERLOADED_OBJECT;
|
||||
*retval = NULL;
|
||||
return;
|
||||
@ -897,43 +892,31 @@ static void zend_fetch_property_address(znode *result, znode *op1, znode *op2, t
|
||||
}
|
||||
|
||||
|
||||
static zval get_overloaded_property(ELS_D)
|
||||
static zval get_overloaded_property(temp_variable *T ELS_DC)
|
||||
{
|
||||
zend_property_reference *property_reference;
|
||||
zval result;
|
||||
|
||||
zend_stack_top(&EG(overloaded_objects_stack), (void **) &property_reference);
|
||||
result = (property_reference->object)->value.obj.ce->handle_property_get(property_reference);
|
||||
result = (T->EA.data.overloaded_element.object)->value.obj.ce->handle_property_get(&T->EA.data.overloaded_element);
|
||||
|
||||
zend_llist_destroy(&property_reference->elements_list);
|
||||
|
||||
zend_stack_del_top(&EG(overloaded_objects_stack));
|
||||
zend_llist_destroy(T->EA.data.overloaded_element.elements_list);
|
||||
efree(T->EA.data.overloaded_element.elements_list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void set_overloaded_property(zval *value ELS_DC)
|
||||
static void set_overloaded_property(temp_variable *T, zval *value ELS_DC)
|
||||
{
|
||||
zend_property_reference *property_reference;
|
||||
|
||||
zend_stack_top(&EG(overloaded_objects_stack), (void **) &property_reference);
|
||||
(property_reference->object)->value.obj.ce->handle_property_set(property_reference, value);
|
||||
|
||||
zend_llist_destroy(&property_reference->elements_list);
|
||||
|
||||
zend_stack_del_top(&EG(overloaded_objects_stack));
|
||||
(T->EA.data.overloaded_element.object)->value.obj.ce->handle_property_set(&T->EA.data.overloaded_element, value);
|
||||
zend_llist_destroy(T->EA.data.overloaded_element.elements_list);
|
||||
efree(T->EA.data.overloaded_element.elements_list);
|
||||
}
|
||||
|
||||
|
||||
static void call_overloaded_function(int arg_count, zval *return_value ELS_DC)
|
||||
static void call_overloaded_function(temp_variable *T, int arg_count, zval *return_value ELS_DC)
|
||||
{
|
||||
zend_property_reference *property_reference;
|
||||
|
||||
zend_stack_top(&EG(overloaded_objects_stack), (void **) &property_reference);
|
||||
(property_reference->object)->value.obj.ce->handle_function_call(arg_count, return_value, property_reference->object, 1 ELS_CC, property_reference);
|
||||
zend_llist_destroy(&property_reference->elements_list);
|
||||
|
||||
zend_stack_del_top(&EG(overloaded_objects_stack));
|
||||
(T->EA.data.overloaded_element.object)->value.obj.ce->handle_function_call(arg_count, return_value, T->EA.data.overloaded_element.object, 1 ELS_CC, &T->EA.data.overloaded_element);
|
||||
zend_llist_destroy(T->EA.data.overloaded_element.elements_list);
|
||||
efree(T->EA.data.overloaded_element.elements_list);
|
||||
}
|
||||
|
||||
|
||||
@ -1520,31 +1503,28 @@ binary_assign_op_addr: {
|
||||
if ((!object.ptr && Ts[opline->op1.u.var].EA.type==IS_OVERLOADED_OBJECT)
|
||||
|| ((object.ptr && object.ptr->type==IS_OBJECT) && (object.ptr->value.obj.ce->handle_function_call))) { /* overloaded function call */
|
||||
zend_overloaded_element overloaded_element;
|
||||
zend_property_reference *property_reference;
|
||||
|
||||
overloaded_element.element = *function_name;
|
||||
overloaded_element.type = OE_IS_METHOD;
|
||||
|
||||
if (object.ptr) {
|
||||
zend_property_reference property_reference;
|
||||
|
||||
property_reference.object = object.ptr;
|
||||
property_reference.type = BP_VAR_NA;
|
||||
zend_llist_init(&property_reference.elements_list, sizeof(zend_overloaded_element), NULL, 0);
|
||||
zend_stack_push(&EG(overloaded_objects_stack), &property_reference, sizeof(zend_property_reference));
|
||||
Ts[opline->op1.u.var].EA.data.overloaded_element.object = object.ptr;
|
||||
Ts[opline->op1.u.var].EA.data.overloaded_element.type = BP_VAR_NA;
|
||||
Ts[opline->op1.u.var].EA.data.overloaded_element.elements_list = (zend_llist *) emalloc(sizeof(zend_llist));
|
||||
zend_llist_init(Ts[opline->op1.u.var].EA.data.overloaded_element.elements_list, sizeof(zend_overloaded_element), NULL, 0);
|
||||
}
|
||||
zend_stack_top(&EG(overloaded_objects_stack), (void **) &property_reference);
|
||||
zend_llist_add_element(&property_reference->elements_list, &overloaded_element);
|
||||
zend_llist_add_element(Ts[opline->op1.u.var].EA.data.overloaded_element.elements_list, &overloaded_element);
|
||||
fbc = (zend_function *) emalloc(sizeof(zend_function));
|
||||
fbc->type = ZEND_OVERLOADED_FUNCTION;
|
||||
fbc->common.arg_types = NULL;
|
||||
fbc->overloaded_function.var = opline->op1.u.var;
|
||||
goto overloaded_function_call_cont;
|
||||
}
|
||||
|
||||
if (!object.ptr || object.ptr->type != IS_OBJECT) {
|
||||
zend_error(E_ERROR, "Call to a member function on a non-object");
|
||||
}
|
||||
object.ptr->refcount++; /* For this pointer */
|
||||
object.ptr->refcount++; /* For $this pointer */
|
||||
active_function_table = &(object.ptr->value.obj.ce->function_table);
|
||||
}
|
||||
} else { /* function pointer */
|
||||
@ -1648,7 +1628,7 @@ do_fcall_common:
|
||||
} else { /* ZEND_OVERLOADED_FUNCTION */
|
||||
ALLOC_ZVAL(Ts[opline->result.u.var].var.ptr);
|
||||
INIT_ZVAL(*(Ts[opline->result.u.var].var.ptr));
|
||||
call_overloaded_function(opline->extended_value, Ts[opline->result.u.var].var.ptr ELS_CC);
|
||||
call_overloaded_function(&Ts[fbc->overloaded_function.var], opline->extended_value, Ts[opline->result.u.var].var.ptr ELS_CC);
|
||||
efree(fbc);
|
||||
if (!return_value_used) {
|
||||
zval_ptr_dtor(&Ts[opline->result.u.var].var.ptr);
|
||||
|
@ -38,8 +38,7 @@ typedef union _temp_variable {
|
||||
zval *str;
|
||||
int offset;
|
||||
} str_offset;
|
||||
// struct {
|
||||
// } overloaded_object;
|
||||
zend_property_reference overloaded_element;
|
||||
} data;
|
||||
|
||||
unsigned char type;
|
||||
|
@ -85,7 +85,6 @@ void init_executor(CLS_D ELS_DC)
|
||||
EG(uninitialized_zval_ptr)=&EG(uninitialized_zval);
|
||||
EG(error_zval_ptr)=&EG(error_zval);
|
||||
zend_ptr_stack_init(&EG(arg_types_stack));
|
||||
zend_stack_init(&EG(overloaded_objects_stack));
|
||||
/* destroys stack frame, therefore makes core dumps worthless */
|
||||
#if 0&&ZEND_DEBUG
|
||||
original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
|
||||
@ -123,7 +122,6 @@ void shutdown_executor(ELS_D)
|
||||
{
|
||||
zval_dtor(&EG(global_return_value));
|
||||
zend_ptr_stack_destroy(&EG(arg_types_stack));
|
||||
zend_stack_destroy(&EG(overloaded_objects_stack));
|
||||
|
||||
while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
|
||||
zend_hash_destroy(*EG(symtable_cache_ptr));
|
||||
|
@ -131,7 +131,6 @@ struct _zend_executor_globals {
|
||||
|
||||
zend_function_state *function_state_ptr;
|
||||
zend_ptr_stack arg_types_stack;
|
||||
zend_stack overloaded_objects_stack;
|
||||
|
||||
/* for global return() support */
|
||||
zval *global_return_value_ptr;
|
||||
|
@ -1047,6 +1047,7 @@ ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2)
|
||||
return FAILURE;
|
||||
}
|
||||
if (result->type == IS_LONG) {
|
||||
result->type = IS_BOOL;
|
||||
if (result->value.lval < 0) {
|
||||
result->value.lval = 1;
|
||||
} else {
|
||||
@ -1055,7 +1056,7 @@ ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2)
|
||||
return SUCCESS;
|
||||
}
|
||||
if (result->type == IS_DOUBLE) {
|
||||
result->type = IS_LONG;
|
||||
result->type = IS_BOOL;
|
||||
if (result->value.dval < 0) {
|
||||
result->value.lval = 1;
|
||||
} else {
|
||||
@ -1074,6 +1075,7 @@ ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2)
|
||||
return FAILURE;
|
||||
}
|
||||
if (result->type == IS_LONG) {
|
||||
result->type = IS_BOOL;
|
||||
if (result->value.lval <= 0) {
|
||||
result->value.lval = 1;
|
||||
} else {
|
||||
@ -1082,7 +1084,7 @@ ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2)
|
||||
return SUCCESS;
|
||||
}
|
||||
if (result->type == IS_DOUBLE) {
|
||||
result->type = IS_LONG;
|
||||
result->type = IS_BOOL;
|
||||
if (result->value.dval <= 0) {
|
||||
result->value.lval = 1;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user