diff options
| author | Stanislav Malyshev <stas@php.net> | 2002-03-10 13:42:37 +0000 |
|---|---|---|
| committer | Stanislav Malyshev <stas@php.net> | 2002-03-10 13:42:37 +0000 |
| commit | 04ed2b520f83f04ba9aa752bb3953bd825821b77 (patch) | |
| tree | 0344c084e369b0061efb68bff94c949f011177b4 /Zend/zend_execute.c | |
| parent | 68976a35cefe23ccfd32843e9d846b840bbdd543 (diff) | |
| download | php-git-04ed2b520f83f04ba9aa752bb3953bd825821b77.tar.gz | |
New stuff for objects API:
- Better assignment handling
- More flexible operations with zval-containing objects
Diffstat (limited to 'Zend/zend_execute.c')
| -rw-r--r-- | Zend/zend_execute.c | 304 |
1 files changed, 303 insertions, 1 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 4c9dea3cb5..2a44352254 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -39,10 +39,14 @@ switch (opcode) { \ case ZEND_PRE_INC: \ case ZEND_POST_INC: \ + case ZEND_PRE_INC_OBJ: \ + case ZEND_POST_INC_OBJ: \ (op) = increment_function; \ break; \ case ZEND_PRE_DEC: \ case ZEND_POST_DEC: \ + case ZEND_PRE_DEC_OBJ: \ + case ZEND_POST_DEC_OBJ: \ (op) = decrement_function; \ break; \ default: \ @@ -184,7 +188,12 @@ static inline zval **zend_fetch_property_address_inner(zval *object, znode *op2, break; } - retval = Z_OBJ_HT_P(object)->get_property_ptr(object, prop_ptr TSRMLS_CC); + if(Z_OBJ_HT_P(object)->get_property_ptr != NULL) { + retval = Z_OBJ_HT_P(object)->get_property_ptr(object, prop_ptr TSRMLS_CC); + } else { + zend_error(E_WARNING, "This object doesn't support property references"); + retval = &EG(error_zval_ptr); + } if (prop_ptr == &tmp) { zval_dtor(prop_ptr); @@ -268,6 +277,134 @@ void zend_assign_to_variable_reference(znode *result, zval **variable_ptr_ptr, z } } +static inline void make_real_object(zval **object_ptr) { + if ((*object_ptr)->type == IS_NULL + || ((*object_ptr)->type == IS_BOOL && (*object_ptr)->value.lval==0) + || ((*object_ptr)->type == IS_STRING && (*object_ptr)->value.str.len == 0)) { + if (!PZVAL_IS_REF(*object_ptr)) { + SEPARATE_ZVAL(object_ptr); + } + zend_error(E_NOTICE, "Creating default object from empty value"); + object_init(*object_ptr); + } +} + +static inline void zend_assign_to_object(znode *result, znode *op1, znode *op2, zval *value, temp_variable *Ts TSRMLS_DC) +{ + zval **object_ptr = get_zval_ptr_ptr(op1, Ts, BP_VAR_W); + zval *object; + zval *property = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); + zval tmp; + zval **retval = &Ts[result->u.var].var.ptr; + + make_real_object(object_ptr); + object = *object_ptr; + + if (object->type != IS_OBJECT) { + zend_error(E_WARNING, "Attempt to assign property of non-object"); + FREE_OP(Ts, op2, EG(free_op2)); + *retval = EG(uninitialized_zval_ptr); + + SELECTIVE_PZVAL_LOCK(*retval, result); + return; + } + + /* here we are sure we are dealing with an object */ + switch (op2->op_type) { + case IS_CONST: + /* already a constant string */ + break; + case IS_VAR: + tmp = *property; + zval_copy_ctor(&tmp); + convert_to_string(&tmp); + property = &tmp; + break; + case IS_TMP_VAR: + convert_to_string(property); + break; + } + + /* here property is a string */ + PZVAL_UNLOCK(value); + + Z_OBJ_HT_P(object)->write_property(object, property, value TSRMLS_CC); + if (property == &tmp) { + zval_dtor(property); + } + + FREE_OP(Ts, op2, EG(free_op2)); + if (result) { + Ts[result->u.var].var.ptr = value; + Ts[result->u.var].var.ptr_ptr = NULL; /* see if we can nuke this */ + SELECTIVE_PZVAL_LOCK(value, result); + } +} + +static inline void zend_assign_to_object_op(znode *result, znode *op1, znode *op2, zval *value, temp_variable *Ts, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC) TSRMLS_DC) { + zval **object_ptr = get_zval_ptr_ptr(op1, Ts, BP_VAR_W); + zval *object; + zval *property = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); + zval tmp; + zval **retval = &Ts[result->u.var].var.ptr; + + Ts[result->u.var].var.ptr_ptr = NULL; + make_real_object(object_ptr); + object = *object_ptr; + + if (object->type != IS_OBJECT) { + zend_error(E_WARNING, "Attempt to assign property of non-object"); + FREE_OP(Ts, op2, EG(free_op2)); + *retval = EG(uninitialized_zval_ptr); + + SELECTIVE_PZVAL_LOCK(*retval, result); + return; + } + + /* here we are sure we are dealing with an object */ + switch (op2->op_type) { + case IS_CONST: + /* already a constant string */ + break; + case IS_VAR: + tmp = *property; + zval_copy_ctor(&tmp); + convert_to_string(&tmp); + property = &tmp; + break; + case IS_TMP_VAR: + convert_to_string(property); + break; + } + + /* here property is a string */ + PZVAL_UNLOCK(value); + + if(Z_OBJ_HT_P(object)->get_property_zval_ptr) { + zval **zptr = Z_OBJ_HT_P(object)->get_property_zval_ptr(object, property TSRMLS_CC); + SEPARATE_ZVAL_IF_NOT_REF(zptr); + + binary_op(*zptr, *zptr, value); + *retval = *zptr; + SELECTIVE_PZVAL_LOCK(*retval, result); + } else { + zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_RW TSRMLS_CC); + SEPARATE_ZVAL_IF_NOT_REF(&z); + binary_op(z, z, value); + Z_OBJ_HT_P(object)->write_property(object, property, z TSRMLS_CC); + *retval = z; + SELECTIVE_PZVAL_LOCK(*retval, result); + if(z->refcount <= 1) { + zval_dtor(z); + } + } + + if (property == &tmp) { + zval_dtor(property); + } + + FREE_OP(Ts, op2, EG(free_op2)); +} static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2, zval *value, int type, temp_variable *Ts TSRMLS_DC) { @@ -884,6 +1021,89 @@ static void zend_fetch_property_address_read(znode *result, znode *op1, znode *o return; } +static void zend_pre_incdec_property(znode *result, znode *op1, znode *op2, temp_variable * Ts, int (*incdec_op)(zval *) TSRMLS_DC) +{ + zval **object_ptr = get_zval_ptr_ptr(op1, Ts, BP_VAR_W); + zval *object; + zval *property = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); + zval **retval = &Ts[result->u.var].var.ptr; + + make_real_object(object_ptr); + object = *object_ptr; + + if (object->type != IS_OBJECT) { + zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); + FREE_OP(Ts, op2, EG(free_op2)); + *retval = EG(uninitialized_zval_ptr); + + SELECTIVE_PZVAL_LOCK(*retval, result); + return; + } + + /* here we are sure we are dealing with an object */ + + if(Z_OBJ_HT_P(object)->get_property_zval_ptr) { + zval **zptr = Z_OBJ_HT_P(object)->get_property_zval_ptr(object, property TSRMLS_CC); + SEPARATE_ZVAL_IF_NOT_REF(zptr); + + incdec_op(*zptr); + *retval = *zptr; + SELECTIVE_PZVAL_LOCK(*retval, result); + } else { + zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_RW TSRMLS_CC); + SEPARATE_ZVAL_IF_NOT_REF(&z); + incdec_op(z); + Z_OBJ_HT_P(object)->write_property(object, property, z TSRMLS_CC); + if(z->refcount <= 1) { + zval_dtor(z); + } + } + + FREE_OP(Ts, op2, EG(free_op2)); +} + +static void zend_post_incdec_property(znode *result, znode *op1, znode *op2, temp_variable * Ts, int (*incdec_op)(zval *) TSRMLS_DC) +{ + zval **object_ptr = get_zval_ptr_ptr(op1, Ts, BP_VAR_W); + zval *object; + zval *property = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); + zval *retval = &Ts[result->u.var].tmp_var; + + make_real_object(object_ptr); + object = *object_ptr; + + if (object->type != IS_OBJECT) { + zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); + FREE_OP(Ts, op2, EG(free_op2)); + *retval = *EG(uninitialized_zval_ptr); + return; + } + + /* here we are sure we are dealing with an object */ + + if(Z_OBJ_HT_P(object)->get_property_zval_ptr) { + zval **zptr = Z_OBJ_HT_P(object)->get_property_zval_ptr(object, property TSRMLS_CC); + SEPARATE_ZVAL_IF_NOT_REF(zptr); + + *retval = **zptr; + zendi_zval_copy_ctor(*retval); + + incdec_op(*zptr); + } else { + zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_RW TSRMLS_CC); + SEPARATE_ZVAL_IF_NOT_REF(&z); + *retval = *z; + zendi_zval_copy_ctor(*retval); + incdec_op(z); + Z_OBJ_HT_P(object)->write_property(object, property, z TSRMLS_CC); + if(z->refcount <= 1) { + zval_dtor(z); + } + } + + FREE_OP(Ts, op2, EG(free_op2)); +} + #if ZEND_INTENSIVE_DEBUGGING @@ -1102,6 +1322,59 @@ binary_assign_op_addr: { AI_USE_PTR(EX(Ts)[EX(opline)->result.u.var].var); } NEXT_OPCODE(); + + case ZEND_ASSIGN_ADD_OBJ: + EG(binary_op) = add_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_SUB_OBJ: + EG(binary_op) = sub_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_MUL_OBJ: + EG(binary_op) = mul_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_DIV_OBJ: + EG(binary_op) = div_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_MOD_OBJ: + EG(binary_op) = mod_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_SL_OBJ: + EG(binary_op) = shift_left_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_SR_OBJ: + EG(binary_op) = shift_right_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_CONCAT_OBJ: + EG(binary_op) = concat_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_BW_OR_OBJ: + EG(binary_op) = bitwise_or_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_BW_AND_OBJ: + EG(binary_op) = bitwise_and_function; + goto binary_assign_op_addr_obj; + case ZEND_ASSIGN_BW_XOR_OBJ: + EG(binary_op) = bitwise_xor_function; + /* Fall through */ +binary_assign_op_addr_obj: + zend_assign_to_object_op(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts)[EX(opline)->extended_value].var.ptr, EX(Ts), EG(binary_op) TSRMLS_CC); + NEXT_OPCODE(); + case ZEND_PRE_INC_OBJ: + case ZEND_PRE_DEC_OBJ: { + int (*incdec_op)(zval *op); + + get_incdec_op(incdec_op, EX(opline)->opcode); + zend_pre_incdec_property(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), incdec_op TSRMLS_CC); + } + NEXT_OPCODE(); + case ZEND_POST_INC_OBJ: + case ZEND_POST_DEC_OBJ: { + int (*incdec_op)(zval *op); + + get_incdec_op(incdec_op, EX(opline)->opcode); + zend_post_incdec_property(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), incdec_op TSRMLS_CC); + } + NEXT_OPCODE(); case ZEND_PRE_INC: case ZEND_PRE_DEC: case ZEND_POST_INC: @@ -1261,6 +1534,35 @@ binary_assign_op_addr: { zend_fetch_dimension_address_from_tmp_var(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts) TSRMLS_CC); AI_USE_PTR(EX(Ts)[EX(opline)->result.u.var].var); NEXT_OPCODE(); + case ZEND_MAKE_VAR: { + zval *value, *value2; + + value = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R); + switch(EX(opline)->op1.op_type) { + case IS_TMP_VAR: + value2 = value; + ALLOC_ZVAL(value); + *value = *value2; + value->is_ref = 0; + value->refcount = 0; /* lock will increase this */ + break; + case IS_CONST: + value2 = value; + ALLOC_ZVAL(value); + *value = *value2; + zval_copy_ctor(value); + value->is_ref = 0; + value->refcount = 0; /* lock will increase this */ + break; + } + + EX(Ts)[EX(opline)->result.u.var].var.ptr = value; + PZVAL_LOCK(EX(Ts)[EX(opline)->result.u.var].var.ptr); + } + NEXT_OPCODE(); + case ZEND_ASSIGN_OBJ: + zend_assign_to_object(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts)[EX(opline)->extended_value].var.ptr, EX(Ts) TSRMLS_CC); + NEXT_OPCODE(); case ZEND_ASSIGN: { zval *value; value = get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2), BP_VAR_R); |
