summaryrefslogtreecommitdiff
path: root/Zend/zend_execute.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@php.net>2007-12-14 14:14:50 +0000
committerDmitry Stogov <dmitry@php.net>2007-12-14 14:14:50 +0000
commitf817a1ce6a18a7751f69d7d52781b54a399080e5 (patch)
tree1ae937ea964fff6c68cbc3858b893cc697acef14 /Zend/zend_execute.c
parentf85ca56b252288d07c2c477415f5b3967dcd39cb (diff)
downloadphp-git-f817a1ce6a18a7751f69d7d52781b54a399080e5.tar.gz
executor optimization
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r--Zend/zend_execute.c598
1 files changed, 317 insertions, 281 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 508cc974c5..5d41457623 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -102,6 +102,10 @@ static inline void zend_pzval_unlock_free_func(zval *z)
(ai).ptr = NULL; \
}
+#define AI_SET_PTR(ai, val) \
+ (ai).ptr = (val); \
+ (ai).ptr_ptr = &((ai).ptr);
+
#define FREE_OP(should_free) \
if (should_free.var) { \
if ((zend_uintptr_t)should_free.var & 1L) { \
@@ -198,9 +202,7 @@ static inline zval *_get_zval_ptr_var(znode *node, temp_variable *Ts, zend_free_
ptr->value.str.val = STR_EMPTY_ALLOC();
ptr->value.str.len = 0;
} else {
- char c = str->value.str.val[T->str_offset.offset];
-
- ptr->value.str.val = estrndup(&c, 1);
+ ptr->value.str.val = estrndup(str->value.str.val + T->str_offset.offset, 1);
ptr->value.str.len = 1;
}
PZVAL_UNLOCK_FREE(str);
@@ -367,27 +369,22 @@ static inline zval *_get_obj_zval_ptr(znode *op, temp_variable *Ts, zend_free_op
return get_zval_ptr(op, Ts, should_free, type);
}
-static inline void zend_switch_free(zend_op *opline, temp_variable *Ts TSRMLS_DC)
+static inline void zend_switch_free(temp_variable *T, int type, int extended_value TSRMLS_DC)
{
- switch (opline->op1.op_type) {
- case IS_VAR:
- if (!T(opline->op1.u.var).var.ptr_ptr) {
- temp_variable *T = &T(opline->op1.u.var);
- /* perform the equivalent of equivalent of a
- * quick & silent get_zval_ptr, and FREE_OP
- */
- PZVAL_UNLOCK_FREE(T->str_offset.str);
- } else if (T(opline->op1.u.var).var.ptr) {
- zval_ptr_dtor(&T(opline->op1.u.var).var.ptr);
- if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { /* foreach() free */
- zval_ptr_dtor(&T(opline->op1.u.var).var.ptr);
- }
+ if (type == IS_VAR) {
+ if (T->var.ptr) {
+ if (extended_value & ZEND_FE_RESET_VARIABLE) { /* foreach() free */
+ Z_DELREF_P(T->var.ptr);
}
- break;
- case IS_TMP_VAR:
- zendi_zval_dtor(T(opline->op1.u.var).tmp_var);
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
+ zval_ptr_dtor(&T->var.ptr);
+ } else if (!T->var.ptr_ptr) {
+ /* perform the equivalent of equivalent of a
+ * quick & silent get_zval_ptr, and FREE_OP
+ */
+ PZVAL_UNLOCK_FREE(T->str_offset.str);
+ }
+ } else { /* IS_TMP_VAR */
+ zendi_zval_dtor(T->tmp_var);
}
}
@@ -532,11 +529,10 @@ static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zva
}
-static inline void zend_assign_to_object(znode *result, zval **object_ptr, znode *op2, znode *value_op, temp_variable *Ts, int opcode TSRMLS_DC)
+static inline void zend_assign_to_object(znode *result, zval **object_ptr, zval *property_name, znode *value_op, temp_variable *Ts, int opcode TSRMLS_DC)
{
zval *object;
- zend_free_op free_op2, free_value;
- zval *property_name = get_zval_ptr(op2, Ts, &free_op2, BP_VAR_R);
+ zend_free_op free_value;
zval *value = get_zval_ptr(value_op, Ts, &free_value, BP_VAR_R);
zval **retval = &T(result->u.var).var.ptr;
@@ -544,31 +540,35 @@ static inline void zend_assign_to_object(znode *result, zval **object_ptr, znode
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
- if (*object_ptr == EG(error_zval_ptr)) {
- FREE_OP(free_op2);
- if (!RETURN_VALUE_UNUSED(result)) {
- *retval = EG(uninitialized_zval_ptr);
- PZVAL_LOCK(*retval);
+ if (Z_TYPE_P(*object_ptr) != IS_OBJECT) {
+ if (*object_ptr == EG(error_zval_ptr)) {
+ if (!RETURN_VALUE_UNUSED(result)) {
+ *retval = EG(uninitialized_zval_ptr);
+ PZVAL_LOCK(*retval);
+ }
+ FREE_OP(free_value);
+ return;
}
- FREE_OP(free_value);
- return;
- }
-
- make_real_object(object_ptr TSRMLS_CC); /* this should modify object only if it's empty */
- object = *object_ptr;
-
- if (Z_TYPE_P(object) != IS_OBJECT || (opcode == ZEND_ASSIGN_OBJ && !Z_OBJ_HT_P(object)->write_property)) {
- zend_error(E_WARNING, "Attempt to assign property of non-object");
- FREE_OP(free_op2);
- if (!RETURN_VALUE_UNUSED(result)) {
- *retval = EG(uninitialized_zval_ptr);
- PZVAL_LOCK(*retval);
+ if (Z_TYPE_PP(object_ptr) == IS_NULL ||
+ (Z_TYPE_PP(object_ptr) == IS_BOOL && Z_LVAL_PP(object_ptr) == 0) ||
+ (Z_TYPE_PP(object_ptr) == IS_STRING && Z_STRLEN_PP(object_ptr) == 0)) {
+ zend_error(E_STRICT, "Creating default object from empty value");
+ SEPARATE_ZVAL_IF_NOT_REF(object_ptr);
+ zval_dtor(*object_ptr);
+ object_init(*object_ptr);
+ } else {
+ zend_error(E_WARNING, "Attempt to assign property of non-object");
+ if (!RETURN_VALUE_UNUSED(result)) {
+ *retval = EG(uninitialized_zval_ptr);
+ PZVAL_LOCK(*retval);
+ }
+ FREE_OP(free_value);
+ return;
}
- FREE_OP(free_value);
- return;
}
/* here we are sure we are dealing with an object */
+ object = *object_ptr;
/* separate our value if necessary */
if (EG(ze1_compatibility_mode) && Z_TYPE_P(value) == IS_OBJECT) {
@@ -610,8 +610,14 @@ static inline void zend_assign_to_object(znode *result, zval **object_ptr, znode
Z_ADDREF_P(value);
if (opcode == ZEND_ASSIGN_OBJ) {
- if (IS_TMP_FREE(free_op2)) {
- MAKE_REAL_ZVAL_PTR(property_name);
+ if (!Z_OBJ_HT_P(object)->write_property) {
+ zend_error(E_WARNING, "Attempt to assign property of non-object");
+ if (!RETURN_VALUE_UNUSED(result)) {
+ *retval = EG(uninitialized_zval_ptr);
+ PZVAL_LOCK(*retval);
+ }
+ FREE_OP(free_value);
+ return;
}
Z_OBJ_HT_P(object)->write_property(object, property_name, value TSRMLS_CC);
} else {
@@ -619,118 +625,83 @@ static inline void zend_assign_to_object(znode *result, zval **object_ptr, znode
if (!Z_OBJ_HT_P(object)->write_dimension) {
zend_error_noreturn(E_ERROR, "Cannot use object as array");
}
- if (IS_TMP_FREE(free_op2)) {
- MAKE_REAL_ZVAL_PTR(property_name);
- }
Z_OBJ_HT_P(object)->write_dimension(object, property_name, value TSRMLS_CC);
}
- if (result && !RETURN_VALUE_UNUSED(result) && !EG(exception)) {
- T(result->u.var).var.ptr = value;
- T(result->u.var).var.ptr_ptr = &T(result->u.var).var.ptr; /* this is so that we could use it in FETCH_DIM_R, etc. - see bug #27876 */
+ if (!RETURN_VALUE_UNUSED(result) && !EG(exception)) {
+ AI_SET_PTR(T(result->u.var).var, value);
PZVAL_LOCK(value);
}
- if (IS_TMP_FREE(free_op2)) {
- zval_ptr_dtor(&property_name);
- } else {
- FREE_OP(free_op2);
- }
zval_ptr_dtor(&value);
FREE_OP_IF_VAR(free_value);
}
-
-static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2, zval *value, int type, temp_variable *Ts TSRMLS_DC)
+static inline void zend_assign_to_string_offset(temp_variable *T, zval *value, int value_type TSRMLS_DC)
{
- zend_free_op free_op1;
- zval **variable_ptr_ptr = get_zval_ptr_ptr(op1, Ts, &free_op1, BP_VAR_W);
- zval *variable_ptr;
-
- if (!variable_ptr_ptr) {
- temp_variable *T = &T(op1->u.var);
+ if (Z_TYPE_P(T->str_offset.str) == IS_STRING) {
+ zval tmp;
+ zval *final_value = value;
- if (Z_TYPE_P(T->str_offset.str) == IS_STRING)
- do {
- zval tmp;
- zval *final_value = value;
+ if (((int)T->str_offset.offset < 0)) {
+ zend_error(E_WARNING, "Illegal string offset: %d", T->str_offset.offset);
+ return;
+ }
+ if (T->str_offset.offset >= Z_STRLEN_P(T->str_offset.str)) {
+ zend_uint i;
- if (((int)T->str_offset.offset < 0)) {
- zend_error(E_WARNING, "Illegal string offset: %d", T->str_offset.offset);
- break;
+ if (Z_STRLEN_P(T->str_offset.str)==0) {
+ STR_FREE(Z_STRVAL_P(T->str_offset.str));
+ Z_STRVAL_P(T->str_offset.str) = (char *) emalloc(T->str_offset.offset+1+1);
+ } else {
+ Z_STRVAL_P(T->str_offset.str) = (char *) erealloc(Z_STRVAL_P(T->str_offset.str), T->str_offset.offset+1+1);
}
- if (T->str_offset.offset >= Z_STRLEN_P(T->str_offset.str)) {
- zend_uint i;
-
- if (Z_STRLEN_P(T->str_offset.str)==0) {
- STR_FREE(Z_STRVAL_P(T->str_offset.str));
- Z_STRVAL_P(T->str_offset.str) = (char *) emalloc(T->str_offset.offset+1+1);
- } else {
- Z_STRVAL_P(T->str_offset.str) = (char *) erealloc(Z_STRVAL_P(T->str_offset.str), T->str_offset.offset+1+1);
- }
- for (i=Z_STRLEN_P(T->str_offset.str); i<T->str_offset.offset; i++) {
- Z_STRVAL_P(T->str_offset.str)[i] = ' ';
- }
- Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset+1] = 0;
- Z_STRLEN_P(T->str_offset.str) = T->str_offset.offset+1;
+ for (i=Z_STRLEN_P(T->str_offset.str); i<T->str_offset.offset; i++) {
+ Z_STRVAL_P(T->str_offset.str)[i] = ' ';
}
+ Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset+1] = 0;
+ Z_STRLEN_P(T->str_offset.str) = T->str_offset.offset+1;
+ }
- if (Z_TYPE_P(value)!=IS_STRING) {
- tmp = *value;
- if (op2->op_type & (IS_VAR|IS_CV)) {
- zval_copy_ctor(&tmp);
- }
- convert_to_string(&tmp);
- final_value = &tmp;
+ if (Z_TYPE_P(value)!=IS_STRING) {
+ tmp = *value;
+ if (value_type & (IS_VAR|IS_CV)) {
+ zval_copy_ctor(&tmp);
}
+ convert_to_string(&tmp);
+ final_value = &tmp;
+ }
- Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset] = Z_STRVAL_P(final_value)[0];
+ Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset] = Z_STRVAL_P(final_value)[0];
- if (op2->op_type == IS_TMP_VAR) {
- if (final_value == &T(op2->u.var).tmp_var) {
- /* we can safely free final_value here
- * because separation is done only
- * in case op2->op_type == IS_VAR */
- STR_FREE(Z_STRVAL_P(final_value));
- }
- }
- if (final_value == &tmp) {
- zval_dtor(final_value);
- }
- /*
- * the value of an assignment to a string offset is undefined
- T(result->u.var).var = &T->str_offset.str;
- */
- } while (0);
- /* zval_ptr_dtor(&T->str_offset.str); Nuke this line if it doesn't cause a leak */
-
-/* T(result->u.var).var.ptr_ptr = &EG(uninitialized_zval_ptr); */
- if (!RETURN_VALUE_UNUSED(result)) {
- T(result->u.var).var.ptr_ptr = &value;
- PZVAL_LOCK(*T(result->u.var).var.ptr_ptr);
- AI_USE_PTR(T(result->u.var).var);
+ if (final_value == &tmp) {
+ zval_dtor(final_value);
+ } else if (value_type == IS_TMP_VAR) {
+ /* we can safely free final_value here
+ * because separation is done only
+ * in case value_type == IS_VAR */
+ STR_FREE(Z_STRVAL_P(final_value));
}
- FREE_OP_VAR_PTR(free_op1);
- return;
+ /*
+ * the value of an assignment to a string offset is undefined
+ T(result->u.var).var = &T->str_offset.str;
+ */
}
+}
- variable_ptr = *variable_ptr_ptr;
+static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value, int is_tmp_var TSRMLS_DC)
+{
+ zval *variable_ptr = *variable_ptr_ptr;
if (variable_ptr == EG(error_zval_ptr)) {
- if (result && !RETURN_VALUE_UNUSED(result)) {
- T(result->u.var).var.ptr_ptr = &EG(uninitialized_zval_ptr);
- PZVAL_LOCK(*T(result->u.var).var.ptr_ptr);
- AI_USE_PTR(T(result->u.var).var);
- }
- if (type==IS_TMP_VAR) {
+ if (is_tmp_var) {
zval_dtor(value);
}
- FREE_OP_VAR_PTR(free_op1);
- return;
+ return EG(uninitialized_zval_ptr);
}
if (Z_TYPE_P(variable_ptr) == IS_OBJECT && Z_OBJ_HANDLER_P(variable_ptr, set)) {
Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
- goto done_setting_var;
+ return value;
}
if (EG(ze1_compatibility_mode) && Z_TYPE_P(value) == IS_OBJECT) {
@@ -747,7 +718,7 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2
zend_uint refcount = Z_REFCOUNT_P(variable_ptr);
zval garbage;
- if (type != IS_TMP_VAR) {
+ if (!is_tmp_var) {
Z_ADDREF_P(value);
}
garbage = *variable_ptr;
@@ -756,7 +727,7 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2
Z_SET_ISREF_P(variable_ptr);
zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name);
variable_ptr->value.obj = Z_OBJ_HANDLER_P(value, clone_obj)(value TSRMLS_CC);
- if (type != IS_TMP_VAR) {
+ if (!is_tmp_var) {
Z_DELREF_P(value);
}
zendi_zval_dtor(garbage);
@@ -786,86 +757,65 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2
zend_uint refcount = Z_REFCOUNT_P(variable_ptr);
zval garbage;
- if (type!=IS_TMP_VAR) {
+ if (!is_tmp_var) {
Z_ADDREF_P(value);
}
garbage = *variable_ptr;
*variable_ptr = *value;
Z_SET_REFCOUNT_P(variable_ptr, refcount);
Z_SET_ISREF_P(variable_ptr);
- if (type!=IS_TMP_VAR) {
+ if (!is_tmp_var) {
zendi_zval_copy_ctor(*variable_ptr);
Z_DELREF_P(value);
}
zendi_zval_dtor(garbage);
}
} else {
- Z_DELREF_P(variable_ptr);
- if (Z_REFCOUNT_P(variable_ptr)==0) {
- switch (type) {
- case IS_CV:
- case IS_VAR:
- /* break missing intentionally */
- case IS_CONST:
- if (variable_ptr==value) {
- Z_ADDREF_P(variable_ptr);
- } else if (PZVAL_IS_REF(value)) {
- zval tmp;
-
- tmp = *value;
- zval_copy_ctor(&tmp);
- Z_SET_REFCOUNT(tmp, 1);
- zendi_zval_dtor(*variable_ptr);
- *variable_ptr = tmp;
- } else {
- Z_ADDREF_P(value);
- zendi_zval_dtor(*variable_ptr);
- safe_free_zval_ptr(variable_ptr);
- *variable_ptr_ptr = value;
- }
- break;
- case IS_TMP_VAR:
+ if (Z_DELREF_P(variable_ptr)==0) {
+ if (!is_tmp_var) {
+ if (variable_ptr==value) {
+ Z_ADDREF_P(variable_ptr);
+ } else if (PZVAL_IS_REF(value)) {
+ zval tmp;
+
+ tmp = *value;
+ zval_copy_ctor(&tmp);
+ Z_SET_REFCOUNT(tmp, 1);
zendi_zval_dtor(*variable_ptr);
- Z_SET_REFCOUNT_P(value, 1);
- *variable_ptr = *value;
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
+ *variable_ptr = tmp;
+ } else {
+ Z_ADDREF_P(value);
+ zendi_zval_dtor(*variable_ptr);
+ safe_free_zval_ptr(variable_ptr);
+ *variable_ptr_ptr = value;
+ }
+ } else {
+ zendi_zval_dtor(*variable_ptr);
+ Z_SET_REFCOUNT_P(value, 1);
+ *variable_ptr = *value;
+ }
} else { /* we need to split */
- switch (type) {
- case IS_CV:
- case IS_VAR:
- /* break missing intentionally */
- case IS_CONST:
- if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) {
- ALLOC_ZVAL(variable_ptr);
- *variable_ptr_ptr = variable_ptr;
- *variable_ptr = *value;
- zval_copy_ctor(variable_ptr);
- Z_SET_REFCOUNT_P(variable_ptr, 1);
- break;
- }
+ if (!is_tmp_var) {
+ if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) {
+ ALLOC_ZVAL(variable_ptr);
+ *variable_ptr_ptr = variable_ptr;
+ *variable_ptr = *value;
+ zval_copy_ctor(variable_ptr);
+ Z_SET_REFCOUNT_P(variable_ptr, 1);
+ } else {
*variable_ptr_ptr = value;
Z_ADDREF_P(value);
- break;
- case IS_TMP_VAR:
- ALLOC_ZVAL(*variable_ptr_ptr);
- Z_SET_REFCOUNT_P(value, 1);
- **variable_ptr_ptr = *value;
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
+ }
+ } else {
+ ALLOC_ZVAL(*variable_ptr_ptr);
+ Z_SET_REFCOUNT_P(value, 1);
+ **variable_ptr_ptr = *value;
+ }
}
Z_UNSET_ISREF_PP(variable_ptr_ptr);
}
-done_setting_var:
- if (result && !RETURN_VALUE_UNUSED(result)) {
- T(result->u.var).var.ptr_ptr = variable_ptr_ptr;
- PZVAL_LOCK(*variable_ptr_ptr);
- AI_USE_PTR(T(result->u.var).var);
- }
- FREE_OP_VAR_PTR(free_op1);
+ return *variable_ptr_ptr;
}
@@ -1055,7 +1005,7 @@ static void zend_fetch_dimension_address(temp_variable *result, zval **container
switch (Z_TYPE_P(container)) {
case IS_ARRAY:
- if ((type==BP_VAR_W || type==BP_VAR_RW) && Z_REFCOUNT_P(container)>1 && !PZVAL_IS_REF(container)) {
+ if (type != BP_VAR_UNSET && Z_REFCOUNT_P(container)>1 && !PZVAL_IS_REF(container)) {
SEPARATE_ZVAL(container_ptr);
container = *container_ptr;
}
@@ -1075,9 +1025,6 @@ fetch_from_array:
if (result) {
result->var.ptr_ptr = retval;
PZVAL_LOCK(*retval);
- if (type == BP_VAR_R || type == BP_VAR_IS) {
- AI_USE_PTR(result->var);
- }
}
return;
break;
@@ -1087,11 +1034,8 @@ fetch_from_array:
if (result) {
result->var.ptr_ptr = &EG(error_zval_ptr);
PZVAL_LOCK(EG(error_zval_ptr));
- if (type == BP_VAR_R || type == BP_VAR_IS) {
- AI_USE_PTR(result->var);
- }
}
- } else if (type == BP_VAR_RW || type == BP_VAR_W) {
+ } else if (type != BP_VAR_UNSET) {
convert_to_array:
if (!PZVAL_IS_REF(container)) {
SEPARATE_ZVAL(container_ptr);
@@ -1101,12 +1045,9 @@ convert_to_array:
array_init(container);
goto fetch_from_array;
} else if (result) {
- /* for read-mode only */
+ /* for read-mode only */
result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
PZVAL_LOCK(EG(uninitialized_zval_ptr));
- if (type == BP_VAR_R || type == BP_VAR_IS) {
- AI_USE_PTR(result->var);
- }
}
return;
break;
@@ -1114,7 +1055,7 @@ convert_to_array:
case IS_STRING: {
zval tmp;
- if ((type == BP_VAR_RW || type == BP_VAR_W) && Z_STRLEN_P(container)==0) {
+ if (type != BP_VAR_UNSET && Z_STRLEN_P(container)==0) {
goto convert_to_array;
}
if (dim == NULL) {
@@ -1140,15 +1081,8 @@ convert_to_array:
convert_to_long(&tmp);
dim = &tmp;
}
- switch (type) {
- case BP_VAR_R:
- case BP_VAR_IS:
- case BP_VAR_UNSET:
- /* do nothing... */
- break;
- default:
- SEPARATE_ZVAL_IF_NOT_REF(container_ptr);
- break;
+ if (type != BP_VAR_UNSET) {
+ SEPARATE_ZVAL_IF_NOT_REF(container_ptr);
}
if (result) {
container = *container_ptr;
@@ -1156,9 +1090,7 @@ convert_to_array:
PZVAL_LOCK(container);
result->str_offset.offset = Z_LVAL_P(dim);
result->var.ptr_ptr = NULL;
- if (type == BP_VAR_R || type == BP_VAR_IS) {
- AI_USE_PTR(result->var);
- }
+ result->var.ptr = NULL;
}
return;
}
@@ -1178,8 +1110,7 @@ convert_to_array:
overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim, type TSRMLS_CC);
if (overloaded_result) {
- if (!Z_ISREF_P(overloaded_result) &&
- (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)) {
+ if (!Z_ISREF_P(overloaded_result)) {
if (Z_REFCOUNT_P(overloaded_result) > 0) {
zval *tmp = overloaded_result;
@@ -1199,9 +1130,8 @@ convert_to_array:
retval = &EG(error_zval_ptr);
}
if (result) {
- result->var.ptr_ptr = retval;
- AI_USE_PTR(result->var);
- PZVAL_LOCK(*result->var.ptr_ptr);
+ AI_SET_PTR(result->var, *retval);
+ PZVAL_LOCK(*retval);
} else if (Z_REFCOUNT_PP(retval) == 0) {
/* Destroy unused result from offsetGet() magic method */
Z_SET_REFCOUNT_PP(retval, 1);
@@ -1215,37 +1145,150 @@ convert_to_array:
break;
case IS_BOOL:
- if ((type == BP_VAR_RW || type == BP_VAR_W) && Z_LVAL_P(container)==0) {
+ if (type != BP_VAR_UNSET && Z_LVAL_P(container)==0) {
goto convert_to_array;
}
/* break missing intentionally */
default:
- switch (type) {
- case BP_VAR_UNSET:
- zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
- /* break missing intentionally */
- case BP_VAR_R:
- case BP_VAR_IS:
- if (result) {
- result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
- PZVAL_LOCK(EG(uninitialized_zval_ptr));
- AI_USE_PTR(result->var);
+ if (type == BP_VAR_UNSET) {
+ zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
+ if (result) {
+ AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
+ PZVAL_LOCK(EG(uninitialized_zval_ptr));
+ }
+ } else {
+ zend_error(E_WARNING, "Cannot use a scalar value as an array");
+ if (result) {
+ result->var.ptr_ptr = &EG(error_zval_ptr);
+ PZVAL_LOCK(EG(error_zval_ptr));
+ }
+ }
+ break;
+ }
+}
+
+static void zend_fetch_dimension_address_read(temp_variable *result, zval **container_ptr, zval *dim, int dim_is_tmp_var, int type TSRMLS_DC)
+{
+ zval *container;
+ zval **retval;
+
+ if (!container_ptr) {
+ zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
+ }
+
+ container = *container_ptr;
+ switch (Z_TYPE_P(container)) {
+
+ case IS_ARRAY:
+ if (dim == NULL) {
+ zval *new_zval = &EG(uninitialized_zval);
+
+ Z_ADDREF_P(new_zval);
+ if (zend_hash_next_index_insert(Z_ARRVAL_P(container), &new_zval, sizeof(zval *), (void **) &retval) == FAILURE) {
+ zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
+ retval = &EG(error_zval_ptr);
+ Z_DELREF_P(new_zval);
+ }
+ } else {
+ retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, type TSRMLS_CC);
+ }
+ if (result) {
+ AI_SET_PTR(result->var, *retval);
+ PZVAL_LOCK(*retval);
+ }
+ return;
+ break;
+
+ case IS_NULL:
+ if (container == EG(error_zval_ptr)) {
+ if (result) {
+ AI_SET_PTR(result->var, EG(error_zval_ptr));
+ PZVAL_LOCK(EG(error_zval_ptr));
+ }
+ } else if (result) {
+ AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
+ PZVAL_LOCK(EG(uninitialized_zval_ptr));
+ }
+ return;
+ break;
+
+ case IS_STRING: {
+ zval tmp;
+
+ if (dim == NULL) {
+ zend_error_noreturn(E_ERROR, "[] operator not supported for strings");
+ }
+
+ if (Z_TYPE_P(dim) != IS_LONG) {
+ switch(Z_TYPE_P(dim)) {
+ /* case IS_LONG: */
+ case IS_STRING:
+ case IS_DOUBLE:
+ case IS_NULL:
+ case IS_BOOL:
+ /* do nothing */
+ break;
+ default:
+ zend_error(E_WARNING, "Illegal offset type");
+ break;
}
- return;
- break;
- case BP_VAR_W:
- case BP_VAR_RW:
- zend_error(E_WARNING, "Cannot use a scalar value as an array");
- /* break missing intentionally */
- default:
+
+ tmp = *dim;
+ zval_copy_ctor(&tmp);
+ convert_to_long(&tmp);
+ dim = &tmp;
+ }
+ if (result) {
+ result->str_offset.str = container;
+ PZVAL_LOCK(container);
+ result->str_offset.offset = Z_LVAL_P(dim);
+ result->var.ptr_ptr = NULL;
+ result->var.ptr = NULL;
+ }
+ return;
+ }
+ break;
+
+ case IS_OBJECT:
+ if (!Z_OBJ_HT_P(container)->read_dimension) {
+ zend_error_noreturn(E_ERROR, "Cannot use object as array");
+ } else {
+ zval *overloaded_result;
+
+ if (dim_is_tmp_var) {
+ zval *orig = dim;
+ MAKE_REAL_ZVAL_PTR(dim);
+ ZVAL_NULL(orig);
+ }
+ overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim, type TSRMLS_CC);
+
+ if (overloaded_result) {
if (result) {
- result->var.ptr_ptr = &EG(error_zval_ptr);
- PZVAL_LOCK(EG(error_zval_ptr));
+ AI_SET_PTR(result->var, overloaded_result);
+ PZVAL_LOCK(overloaded_result);
+ } else if (Z_REFCOUNT_P(overloaded_result) == 0) {
+ /* Destroy unused result from offsetGet() magic method */
+ Z_SET_REFCOUNT_P(overloaded_result, 1);
+ zval_ptr_dtor(&overloaded_result);
}
- return;
- break;
+ } else if (result) {
+ AI_SET_PTR(result->var, EG(error_zval_ptr));
+ PZVAL_LOCK(EG(error_zval_ptr));
+ }
+ if (dim_is_tmp_var) {
+ zval_ptr_dtor(&dim);
+ }
}
+ return;
+ break;
+
+ default:
+ if (result) {
+ AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
+ PZVAL_LOCK(EG(uninitialized_zval_ptr));
+ }
+ return;
break;
}
}
@@ -1264,39 +1307,32 @@ static void zend_fetch_property_address(temp_variable *result, zval **container_
}
container = *container_ptr;
- if (container == EG(error_zval_ptr)) {
- if (result) {
- result->var.ptr_ptr = &EG(error_zval_ptr);
- PZVAL_LOCK(*result->var.ptr_ptr);
- }
- return;
- }
- /* this should modify object only if it's empty */
- if (Z_TYPE_P(container) == IS_NULL
- || (Z_TYPE_P(container) == IS_BOOL && Z_LVAL_P(container)==0)
- || (Z_TYPE_P(container) == IS_STRING && Z_STRLEN_P(container)==0)) {
- switch (type) {
- case BP_VAR_RW:
- case BP_VAR_W:
- if (!PZVAL_IS_REF(container)) {
- SEPARATE_ZVAL(container_ptr);
- container = *container_ptr;
- }
- object_init(container);
- break;
+ if (Z_TYPE_P(container) != IS_OBJECT) {
+ if (container == EG(error_zval_ptr)) {
+ if (result) {
+ result->var.ptr_ptr = &EG(error_zval_ptr);
+ PZVAL_LOCK(*result->var.ptr_ptr);
+ }
+ return;
}
- }
- if (Z_TYPE_P(container) != IS_OBJECT) {
- if (result) {
- if (type == BP_VAR_R || type == BP_VAR_IS) {
- result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
- } else {
+ /* this should modify object only if it's empty */
+ if (type != BP_VAR_UNSET &&
+ ((Z_TYPE_P(container) == IS_NULL ||
+ (Z_TYPE_P(container) == IS_BOOL && Z_LVAL_P(container)==0) ||
+ (Z_TYPE_P(container) == IS_STRING && Z_STRLEN_P(container)==0)))) {
+ if (!PZVAL_IS_REF(container)) {
+ SEPARATE_ZVAL(container_ptr);
+ container = *container_ptr;
+ }
+ object_init(container);
+ } else {
+ if (result) {
result->var.ptr_ptr = &EG(error_zval_ptr);
+ PZVAL_LOCK(EG(error_zval_ptr));
}
- PZVAL_LOCK(*result->var.ptr_ptr);
+ return;
}
- return;
}
if (Z_OBJ_HT_P(container)->get_property_ptr_ptr) {
@@ -1307,30 +1343,30 @@ static void zend_fetch_property_address(temp_variable *result, zval **container_
if (Z_OBJ_HT_P(container)->read_property &&
(ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type TSRMLS_CC)) != NULL) {
if (result) {
- result->var.ptr = ptr;
- result->var.ptr_ptr = &result->var.ptr;
+ AI_SET_PTR(result->var, ptr);
+ PZVAL_LOCK(ptr);
}
} else {
zend_error(E_ERROR, "Cannot access undefined property for object with overloaded property access");
}
} else if (result) {
result->var.ptr_ptr = ptr_ptr;
+ PZVAL_LOCK(*ptr_ptr);
}
} else if (Z_OBJ_HT_P(container)->read_property) {
+ zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type TSRMLS_CC);
+
if (result) {
- result->var.ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type TSRMLS_CC);
- result->var.ptr_ptr = &result->var.ptr;
+ AI_SET_PTR(result->var, ptr);
+ PZVAL_LOCK(ptr);
}
} else {
zend_error(E_WARNING, "This object doesn't support property references");
if (result) {
result->var.ptr_ptr = &EG(error_zval_ptr);
+ PZVAL_LOCK(EG(error_zval_ptr));
}
}
-
- if (result) {
- PZVAL_LOCK(*result->var.ptr_ptr);
- }
}
static inline zend_brk_cont_element* zend_brk_cont(zval *nest_levels_zval, int array_offset, zend_op_array *op_array, temp_variable *Ts TSRMLS_DC)
@@ -1358,7 +1394,7 @@ static inline zend_brk_cont_element* zend_brk_cont(zval *nest_levels_zval, int a
switch (brk_opline->opcode) {
case ZEND_SWITCH_FREE:
- zend_switch_free(brk_opline, Ts TSRMLS_CC);
+ zend_switch_free(&T(brk_opline->op1.u.var), brk_opline->op1.op_type, brk_opline->extended_value TSRMLS_CC);
break;
case ZEND_FREE:
zendi_zval_dtor(T(brk_opline->op1.u.var).tmp_var);