summaryrefslogtreecommitdiff
path: root/Zend/zend_execute.c
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2002-03-10 13:42:37 +0000
committerStanislav Malyshev <stas@php.net>2002-03-10 13:42:37 +0000
commit04ed2b520f83f04ba9aa752bb3953bd825821b77 (patch)
tree0344c084e369b0061efb68bff94c949f011177b4 /Zend/zend_execute.c
parent68976a35cefe23ccfd32843e9d846b840bbdd543 (diff)
downloadphp-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.c304
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);