Browse Source

executor optimization

PECL
Dmitry Stogov 19 years ago
parent
commit
f817a1ce6a
  1. 598
      Zend/zend_execute.c
  2. 228
      Zend/zend_vm_def.h
  3. 1947
      Zend/zend_vm_execute.h

598
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);

228
Zend/zend_vm_def.h

@ -291,7 +291,6 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
zval *property = GET_OP2_ZVAL_PTR(BP_VAR_R);
zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_op_data1, BP_VAR_R);
znode *result = &opline->result;
zval **retval = &EX_T(result->u.var).var.ptr;
int have_get_ptr = 0;
EX_T(result->u.var).var.ptr_ptr = NULL;
@ -304,8 +303,9 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
FREE_OP(free_op_data1);
if (!RETURN_VALUE_UNUSED(result)) {
*retval = EG(uninitialized_zval_ptr);
PZVAL_LOCK(*retval);
EX_T(result->u.var).var.ptr = EG(uninitialized_zval_ptr);
EX_T(result->u.var).var.ptr_ptr = NULL;
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
} else {
/* here we are sure we are dealing with an object */
@ -323,8 +323,9 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
have_get_ptr = 1;
binary_op(*zptr, *zptr, value TSRMLS_CC);
if (!RETURN_VALUE_UNUSED(result)) {
*retval = *zptr;
PZVAL_LOCK(*retval);
EX_T(result->u.var).var.ptr = *zptr;
EX_T(result->u.var).var.ptr_ptr = NULL;
PZVAL_LOCK(*zptr);
}
}
}
@ -366,15 +367,17 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
break;
}
if (!RETURN_VALUE_UNUSED(result)) {
*retval = z;
PZVAL_LOCK(*retval);
EX_T(result->u.var).var.ptr = z;
EX_T(result->u.var).var.ptr_ptr = NULL;
PZVAL_LOCK(z);
}
zval_ptr_dtor(&z);
} 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);
EX_T(result->u.var).var.ptr = EG(uninitialized_zval_ptr);
EX_T(result->u.var).var.ptr_ptr = NULL;
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
}
}
@ -420,7 +423,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU
zend_fetch_dimension_address(&EX_T(op_data->op2.u.var), GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW), dim, IS_OP2_TMP_FREE(), BP_VAR_RW TSRMLS_CC);
value = get_zval_ptr(&op_data->op1, EX(Ts), &free_op_data1, BP_VAR_R);
var_ptr = get_zval_ptr_ptr(&op_data->op2, EX(Ts), &free_op_data2, BP_VAR_RW);
var_ptr = _get_zval_ptr_ptr_var(&op_data->op2, EX(Ts), &free_op_data2 TSRMLS_CC);
increment_opline = 1;
}
}
@ -438,9 +441,8 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU
if (*var_ptr == EG(error_zval_ptr)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = &EG(uninitialized_zval_ptr);
PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr);
AI_USE_PTR(EX_T(opline->result.u.var).var);
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
FREE_OP2();
FREE_OP1_VAR_PTR();
@ -465,9 +467,8 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU
}
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = var_ptr;
AI_SET_PTR(EX_T(opline->result.u.var).var, *var_ptr);
PZVAL_LOCK(*var_ptr);
AI_USE_PTR(EX_T(opline->result.u.var).var);
}
FREE_OP2();
@ -729,9 +730,8 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY)
}
if (*var_ptr == EG(error_zval_ptr)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = &EG(uninitialized_zval_ptr);
PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr);
AI_USE_PTR(EX_T(opline->result.u.var).var);
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
FREE_OP1_VAR_PTR();
ZEND_VM_NEXT_OPCODE();
@ -752,9 +752,8 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY)
}
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = var_ptr;
AI_SET_PTR(EX_T(opline->result.u.var).var, *var_ptr);
PZVAL_LOCK(*var_ptr);
AI_USE_PTR(EX_T(opline->result.u.var).var);
}
FREE_OP1_VAR_PTR();
@ -772,9 +771,8 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY)
}
if (*var_ptr == EG(error_zval_ptr)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = &EG(uninitialized_zval_ptr);
PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr);
AI_USE_PTR(EX_T(opline->result.u.var).var);
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
FREE_OP1_VAR_PTR();
ZEND_VM_NEXT_OPCODE();
@ -795,9 +793,8 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY)
}
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = var_ptr;
AI_SET_PTR(EX_T(opline->result.u.var).var, *var_ptr);
PZVAL_LOCK(*var_ptr);
AI_USE_PTR(EX_T(opline->result.u.var).var);
}
FREE_OP1_VAR_PTR();
@ -984,16 +981,16 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMP|VAR|CV, ANY, int type
if (opline->extended_value & ZEND_FETCH_MAKE_REF) {
SEPARATE_ZVAL_TO_MAKE_IS_REF(retval);
}
EX_T(opline->result.u.var).var.ptr_ptr = retval;
PZVAL_LOCK(*retval);
switch (type) {
case BP_VAR_R:
case BP_VAR_IS:
AI_USE_PTR(EX_T(opline->result.u.var).var);
AI_SET_PTR(EX_T(opline->result.u.var).var, *retval);
break;
case BP_VAR_UNSET: {
zend_free_op free_res;
EX_T(opline->result.u.var).var.ptr_ptr = retval;
PZVAL_UNLOCK(*EX_T(opline->result.u.var).var.ptr_ptr, &free_res);
if (EX_T(opline->result.u.var).var.ptr_ptr != &EG(uninitialized_zval_ptr)) {
SEPARATE_ZVAL_IF_NOT_REF(EX_T(opline->result.u.var).var.ptr_ptr);
@ -1001,6 +998,9 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMP|VAR|CV, ANY, int type
PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr);
FREE_OP_VAR_PTR(free_res);
break;
default:
EX_T(opline->result.u.var).var.ptr_ptr = retval;
break;
}
}
}
@ -1049,7 +1049,7 @@ ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, VAR|CV, CONST|TMP|VAR|CV)
EX_T(opline->op1.u.var).var.ptr_ptr) {
PZVAL_LOCK(*EX_T(opline->op1.u.var).var.ptr_ptr);
}
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var), GET_OP1_ZVAL_PTR_PTR(BP_VAR_R), dim, IS_OP2_TMP_FREE(), BP_VAR_R TSRMLS_CC);
zend_fetch_dimension_address_read(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var), GET_OP1_ZVAL_PTR_PTR(BP_VAR_R), dim, IS_OP2_TMP_FREE(), BP_VAR_R TSRMLS_CC);
FREE_OP2();
FREE_OP1_VAR_PTR();
ZEND_VM_NEXT_OPCODE();
@ -1111,7 +1111,7 @@ ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, VAR|CV, CONST|TMP|VAR|CV)
zend_free_op free_op1, free_op2;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var), GET_OP1_ZVAL_PTR_PTR(BP_VAR_IS), dim, IS_OP2_TMP_FREE(), BP_VAR_IS TSRMLS_CC);
zend_fetch_dimension_address_read(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var), GET_OP1_ZVAL_PTR_PTR(BP_VAR_IS), dim, IS_OP2_TMP_FREE(), BP_VAR_IS TSRMLS_CC);
FREE_OP2();
FREE_OP1_VAR_PTR();
ZEND_VM_NEXT_OPCODE();
@ -1121,24 +1121,26 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
{
zend_op *opline = EX(opline);
zend_free_op free_op1, free_op2;
int type = ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->extended_value)?BP_VAR_W:BP_VAR_R;
zval *dim;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (OP2_TYPE == IS_UNUSED && type == BP_VAR_R) {
zend_error_noreturn(E_ERROR, "Cannot use [] for reading");
}
dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var), GET_OP1_ZVAL_PTR_PTR(type), dim, IS_OP2_TMP_FREE(), type TSRMLS_CC);
FREE_OP2();
if (OP1_TYPE == IS_VAR && type == BP_VAR_W && OP1_FREE &&
READY_TO_DESTROY(free_op1.var) &&
!RETURN_VALUE_UNUSED(&opline->result)) {
AI_USE_PTR(EX_T(opline->result.u.var).var);
if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) &&
Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) {
SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr);
if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->extended_value)) {
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var), GET_OP1_ZVAL_PTR_PTR(BP_VAR_W), dim, IS_OP2_TMP_FREE(), BP_VAR_W TSRMLS_CC);
if (OP1_TYPE == IS_VAR && OP1_FREE &&
READY_TO_DESTROY(free_op1.var) &&
!RETURN_VALUE_UNUSED(&opline->result)) {
AI_USE_PTR(EX_T(opline->result.u.var).var);
if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) &&
Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) {
SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr);
}
}
} else {
if (OP2_TYPE == IS_UNUSED) {
zend_error_noreturn(E_ERROR, "Cannot use [] for reading");
}
zend_fetch_dimension_address_read(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var), GET_OP1_ZVAL_PTR_PTR(BP_VAR_R), dim, IS_OP2_TMP_FREE(), BP_VAR_R TSRMLS_CC);
}
FREE_OP2();
FREE_OP1_VAR_PTR();
ZEND_VM_NEXT_OPCODE();
}
@ -1190,20 +1192,13 @@ ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMP|VAR|CV)
ZEND_VM_HELPER_EX(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|TMP|VAR|CV, int type)
{
zend_op *opline = EX(opline);
zval *container;
zval **retval;
zend_free_op free_op1;
retval = &EX_T(opline->result.u.var).var.ptr;
EX_T(opline->result.u.var).var.ptr_ptr = retval;
container = GET_OP1_OBJ_ZVAL_PTR(type);
zval *container = GET_OP1_OBJ_ZVAL_PTR(type);
if (container == EG(error_zval_ptr)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
*retval = EG(error_zval_ptr);
PZVAL_LOCK(*retval);
AI_USE_PTR(EX_T(opline->result.u.var).var);
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(error_zval_ptr));
PZVAL_LOCK(EG(error_zval_ptr));
}
FREE_OP1();
ZEND_VM_NEXT_OPCODE();
@ -1214,26 +1209,30 @@ ZEND_VM_HELPER_EX(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|
if (type != BP_VAR_IS) {
zend_error(E_NOTICE, "Trying to get property of non-object");
}
*retval = EG(uninitialized_zval_ptr);
SELECTIVE_PZVAL_LOCK(*retval, &opline->result);
AI_USE_PTR(EX_T(opline->result.u.var).var);
if (!RETURN_VALUE_UNUSED(&opline->result)) {
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
} else {
zend_free_op free_op2;
zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R);
zval *retval;
if (IS_OP2_TMP_FREE()) {
MAKE_REAL_ZVAL_PTR(offset);
}
/* here we are sure we are dealing with an object */
*retval = Z_OBJ_HT_P(container)->read_property(container, offset, type TSRMLS_CC);
retval = Z_OBJ_HT_P(container)->read_property(container, offset, type TSRMLS_CC);
if (RETURN_VALUE_UNUSED(&opline->result) && (Z_REFCOUNT_PP(retval) == 0)) {
zval_dtor(*retval);
FREE_ZVAL(*retval);
if (RETURN_VALUE_UNUSED(&opline->result)) {
if (Z_REFCOUNT_P(retval) == 0) {
zval_dtor(retval);
FREE_ZVAL(retval);
}
} else {
SELECTIVE_PZVAL_LOCK(*retval, &opline->result);
AI_USE_PTR(EX_T(opline->result.u.var).var);
AI_SET_PTR(EX_T(opline->result.u.var).var, retval);
PZVAL_LOCK(retval);
}
if (IS_OP2_TMP_FREE()) {
@ -1409,18 +1408,17 @@ ZEND_VM_HANDLER(98, ZEND_FETCH_DIM_TMP_VAR, CONST|TMP, CONST)
if (Z_TYPE_P(container) != IS_ARRAY) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = &EG(uninitialized_zval_ptr);
PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr);
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
} else {
zend_free_op free_op2;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
EX_T(opline->result.u.var).var.ptr_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, BP_VAR_R TSRMLS_CC);
SELECTIVE_PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr, &opline->result);
AI_SET_PTR(EX_T(opline->result.u.var).var, *zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, BP_VAR_R TSRMLS_CC));
SELECTIVE_PZVAL_LOCK(EX_T(opline->result.u.var).var.ptr, &opline->result);
FREE_OP2();
}
AI_USE_PTR(EX_T(opline->result.u.var).var);
ZEND_VM_NEXT_OPCODE();
}
@ -1428,10 +1426,19 @@ ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
{
zend_op *opline = EX(opline);
zend_op *op_data = opline+1;
zend_free_op free_op1;
zend_free_op free_op1, free_op2;
zval **object_ptr = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W);
zval *property_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
zend_assign_to_object(&opline->result, object_ptr, &opline->op2, &op_data->op1, EX(Ts), ZEND_ASSIGN_OBJ TSRMLS_CC);
if (IS_OP2_TMP_FREE()) {
MAKE_REAL_ZVAL_PTR(property_name);
}
zend_assign_to_object(&opline->result, object_ptr, property_name, &op_data->op1, EX(Ts), ZEND_ASSIGN_OBJ TSRMLS_CC);
if (IS_OP2_TMP_FREE()) {
zval_ptr_dtor(&property_name);
} else {
FREE_OP2();
}
FREE_OP1_VAR_PTR();
/* assign_obj has two opcodes! */
ZEND_VM_INC_OPCODE();
@ -1453,17 +1460,39 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
}
if (object_ptr && Z_TYPE_PP(object_ptr) == IS_OBJECT) {
zend_assign_to_object(&opline->result, object_ptr, &opline->op2, &op_data->op1, EX(Ts), ZEND_ASSIGN_DIM TSRMLS_CC);
zend_free_op free_op2;
zval *property_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (IS_OP2_TMP_FREE()) {
MAKE_REAL_ZVAL_PTR(property_name);
}
zend_assign_to_object(&opline->result, object_ptr, property_name, &op_data->op1, EX(Ts), ZEND_ASSIGN_DIM TSRMLS_CC);
if (IS_OP2_TMP_FREE()) {
zval_ptr_dtor(&property_name);
} else {
FREE_OP2();
}
} else {
zend_free_op free_op2, free_op_data1;
zend_free_op free_op2, free_op_data1, free_op_data2;
zval *value;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
zval **variable_ptr_ptr;
zend_fetch_dimension_address(&EX_T(op_data->op2.u.var), object_ptr, dim, IS_OP2_TMP_FREE(), BP_VAR_W TSRMLS_CC);
FREE_OP2();
value = get_zval_ptr(&op_data->op1, EX(Ts), &free_op_data1, BP_VAR_R);
zend_assign_to_variable(&opline->result, &op_data->op2, &op_data->op1, value, (IS_TMP_FREE(free_op_data1)?IS_TMP_VAR:op_data->op1.op_type), EX(Ts) TSRMLS_CC);
variable_ptr_ptr = _get_zval_ptr_ptr_var(&op_data->op2, EX(Ts), &free_op_data2 TSRMLS_CC);
if (!variable_ptr_ptr) {
zend_assign_to_string_offset(&EX_T(op_data->op2.u.var), value, op_data->op1.op_type TSRMLS_CC);
} else {
value = zend_assign_to_variable(variable_ptr_ptr, value, IS_TMP_FREE(free_op_data1) TSRMLS_CC);
}
if (!RETURN_VALUE_UNUSED(&opline->result)) {
AI_SET_PTR(EX_T(opline->result.u.var).var, value);
PZVAL_LOCK(value);
}
FREE_OP_VAR_PTR(free_op_data2);
FREE_OP_IF_VAR(free_op_data1);
}
FREE_OP1_VAR_PTR();
@ -1475,10 +1504,23 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV)
{
zend_op *opline = EX(opline);
zend_free_op free_op2;
zend_free_op free_op1, free_op2;
zval *value = GET_OP2_ZVAL_PTR(BP_VAR_R);
zval **variable_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (!variable_ptr_ptr) {
zend_assign_to_string_offset(&EX_T(opline->op1.u.var), value, OP2_TYPE TSRMLS_CC);
} else {
value = zend_assign_to_variable(variable_ptr_ptr, value, IS_OP2_TMP_FREE() TSRMLS_CC);
}
if (!RETURN_VALUE_UNUSED(&opline->result)) {
AI_SET_PTR(EX_T(opline->result.u.var).var, value);
PZVAL_LOCK(value);
}
FREE_OP1_VAR_PTR();
zend_assign_to_variable(&opline->result, &opline->op1, &opline->op2, value, (IS_OP2_TMP_FREE()?IS_TMP_VAR:OP2_TYPE), EX(Ts) TSRMLS_CC);
/* zend_assign_to_variable() always takes care of op2, never free it! */
FREE_OP2_IF_VAR();
@ -1511,9 +1553,8 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV)
zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC);
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = variable_ptr_ptr;
AI_SET_PTR(EX_T(opline->result.u.var).var, *variable_ptr_ptr);
PZVAL_LOCK(*variable_ptr_ptr);
AI_USE_PTR(EX_T(opline->result.u.var).var);
}
FREE_OP1_VAR_PTR();
@ -2456,7 +2497,7 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
{
zend_op *opline = EX(opline);
zval **param, *assignment_value;
zval **param, *assignment_value, **var_ptr;
zend_uint arg_num = Z_LVAL(opline->op1.u.constant);
zend_free_op free_res;
@ -2480,10 +2521,11 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
assignment_value = &opline->op2.u.constant;
}
zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
zend_assign_to_variable(NULL, &opline->result, NULL, assignment_value, IS_VAR, EX(Ts) TSRMLS_CC);
var_ptr = get_zval_ptr_ptr(&opline->result, EX(Ts), &free_res, BP_VAR_W);
zend_assign_to_variable(var_ptr, assignment_value, 0 TSRMLS_CC);
} else {
zval **var_ptr = get_zval_ptr_ptr(&opline->result, EX(Ts), &free_res, BP_VAR_W);
var_ptr = get_zval_ptr_ptr(&opline->result, EX(Ts), &free_res, BP_VAR_W);
assignment_value = *param;
zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
if (PZVAL_IS_REF(assignment_value)) {
@ -2560,14 +2602,14 @@ ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)
*/
FREE_OP1();
EX_T(opline->op1.u.var).var.ptr_ptr = NULL;
AI_USE_PTR(EX_T(opline->op1.u.var).var);
EX_T(opline->op1.u.var).var.ptr = NULL;
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(49, ZEND_SWITCH_FREE, TMP|VAR, ANY)
{
zend_switch_free(EX(opline), EX(Ts) TSRMLS_CC);
zend_switch_free(&EX_T(EX(opline)->op1.u.var), OP1_TYPE, EX(opline)->extended_value TSRMLS_CC);
ZEND_VM_NEXT_OPCODE();
}
@ -2595,16 +2637,16 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY)
if (constructor == NULL) {
if (RETURN_VALUE_USED(opline)) {
EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
EX_T(opline->result.u.var).var.ptr = object_zval;
AI_SET_PTR(EX_T(opline->result.u.var).var, object_zval);
} else {
zval_ptr_dtor(&object_zval);
}
ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.u.opline_num);
} else {
SELECTIVE_PZVAL_LOCK(object_zval, &opline->result);
EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
EX_T(opline->result.u.var).var.ptr = object_zval;
if (RETURN_VALUE_USED(opline)) {
AI_SET_PTR(EX_T(opline->result.u.var).var, object_zval);
PZVAL_LOCK(object_zval);
}
zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline)));
@ -3292,9 +3334,8 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
}
}
AI_SET_PTR(EX_T(opline->result.u.var).var, array_ptr);
PZVAL_LOCK(array_ptr);
EX_T(opline->result.u.var).var.ptr = array_ptr;
EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
if (iter) {
iter->index = 0;
@ -3478,9 +3519,8 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
EX_T(opline->result.u.var).var.ptr_ptr = value;
Z_ADDREF_PP(value);
} else {
EX_T(opline->result.u.var).var.ptr_ptr = value;
PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr);
AI_USE_PTR(EX_T(opline->result.u.var).var);
AI_SET_PTR(EX_T(opline->result.u.var).var, *value);
PZVAL_LOCK(*value);
}
if (use_key) {
@ -3948,7 +3988,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
switch (brk_opline->opcode) {
case ZEND_SWITCH_FREE:
zend_switch_free(brk_opline, EX(Ts) TSRMLS_CC);
zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->op1.op_type, brk_opline->extended_value TSRMLS_CC);
break;
case ZEND_FREE:
zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var);

1947
Zend/zend_vm_execute.h
File diff suppressed because it is too large
View File

Loading…
Cancel
Save