Removed IS_STR_OFFSET type and corresponding macros. Optimized string offset handling in ASSIGN_DIM opcode.

This commit is contained in:
Dmitry Stogov 2014-09-08 15:46:45 +04:00
parent be835b2d70
commit e85545eca5
4 changed files with 689 additions and 869 deletions

View File

@ -755,42 +755,8 @@ static inline void zend_assign_to_object(zval *retval, zval *object_ptr, zval *p
FREE_OP_IF_VAR(free_value);
}
static zend_always_inline zend_long zend_fetch_dimension_str_offset(zval *dim, int type TSRMLS_DC)
static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *value, int value_type, zval *result TSRMLS_DC)
{
zend_long offset;
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
switch(Z_TYPE_P(dim)) {
case IS_STRING:
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
break;
}
if (type != BP_VAR_UNSET) {
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
}
break;
case IS_DOUBLE:
case IS_NULL:
case IS_FALSE:
case IS_TRUE:
zend_error(E_NOTICE, "String offset cast occurred");
break;
default:
zend_error(E_WARNING, "Illegal offset type");
break;
}
offset = zval_get_long(dim);
} else {
offset = Z_LVAL_P(dim);
}
return offset;
}
static void zend_assign_to_string_offset(zval *str_offset, zend_long offset, zval *value, int value_type, zval *result TSRMLS_DC)
{
zval *str = Z_STR_OFFSET_STR_P(str_offset);
zend_string *old_str;
if (offset < 0) {
@ -1135,7 +1101,7 @@ str_index:
return retval;
}
static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *container_ptr, zval *dim, int dim_type, int type, int is_ref TSRMLS_DC)
static zend_always_inline zval *zend_fetch_dimension_address(zval *result, zval *container_ptr, zval *dim, int dim_type, int type, int is_ref, int allow_str_offset TSRMLS_DC)
{
zval *retval;
zval *container = container_ptr;
@ -1175,17 +1141,40 @@ convert_to_array:
zend_error_noreturn(E_ERROR, "[] operator not supported for strings");
}
if (type != BP_VAR_UNSET) {
SEPARATE_STRING(container);
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
switch(Z_TYPE_P(dim)) {
case IS_STRING:
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
break;
}
if (type != BP_VAR_UNSET) {
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
}
break;
case IS_DOUBLE:
case IS_NULL:
case IS_FALSE:
case IS_TRUE:
zend_error(E_NOTICE, "String offset cast occurred");
break;
default:
zend_error(E_WARNING, "Illegal offset type");
break;
}
offset = zval_get_long(dim);
} else {
offset = Z_LVAL_P(dim);
}
/* This is a dummy, the offset is broken if we're here.
What matters is merely the IS_STR_OFFSET type set below.*/
offset = zend_fetch_dimension_str_offset(dim, type TSRMLS_CC);
if (!IS_INTERNED(Z_STR_P(container))) zend_string_addref(Z_STR_P(container));
ZVAL_STR_OFFSET(result, container, offset);
if (allow_str_offset) {
SEPARATE_STRING(container);
if (!IS_INTERNED(Z_STR_P(container))) zend_string_addref(Z_STR_P(container));
ZVAL_LONG(result, offset);
return container; /* assignment to string offset */
} else {
ZVAL_INDIRECT(result, NULL); /* wrong string offset */
}
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
if (!Z_OBJ_HT_P(container)->read_dimension) {
zend_error_noreturn(E_ERROR, "Cannot use object as array");
@ -1250,26 +1239,32 @@ convert_to_array:
ZVAL_INDIRECT(result, &EG(error_zval));
}
}
return NULL; /* not an assignment to string offset */
}
static zend_never_inline void zend_fetch_dimension_address_W(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC)
{
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 0 TSRMLS_CC);
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 0, 0 TSRMLS_CC);
}
static zend_never_inline zval *zend_fetch_dimension_address_W_str(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC)
{
return zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 0, 1 TSRMLS_CC);
}
static zend_never_inline void zend_fetch_dimension_address_W_ref(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC)
{
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 1 TSRMLS_CC);
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 1, 0 TSRMLS_CC);
}
static zend_never_inline void zend_fetch_dimension_address_RW(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC)
{
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW, 0 TSRMLS_CC);
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW, 0, 0 TSRMLS_CC);
}
static zend_never_inline void zend_fetch_dimension_address_UNSET(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC)
{
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET, 0 TSRMLS_CC);
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET, 0, 0 TSRMLS_CC);
}
static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type TSRMLS_DC)

View File

@ -239,7 +239,6 @@ struct _zend_ast_ref {
/* internal types */
#define IS_INDIRECT 15
#define IS_STR_OFFSET 16
#define IS_PTR 17
static inline zend_uchar zval_get_type(const zval* pz) {
@ -651,15 +650,6 @@ static inline zend_uchar zval_get_type(const zval* pz) {
Z_TYPE_INFO_P(z) = IS_PTR; \
} while (0)
#define Z_STR_OFFSET_STR(zval) Z_INDIRECT(zval)
#define Z_STR_OFFSET_STR_P(zval_p) Z_STR_OFFSET_STR(*(zval_p))
#define ZVAL_STR_OFFSET(z, s, i) do { \
Z_STR_OFFSET_STR_P(z) = (s); \
Z_TYPE_INFO_P(z) = IS_STR_OFFSET; \
} while (0)
#endif /* ZEND_TYPES_H */
/*

View File

@ -335,7 +335,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
zval *value;
int have_get_ptr = 0;
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(object) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(object == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
}
@ -430,7 +430,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMP|VAR
SAVE_OPLINE();
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
} else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
if (OP1_TYPE == IS_VAR && !OP1_FREE) {
@ -445,7 +445,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMP|VAR
var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
}
if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) {
if (UNEXPECTED(var_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets");
}
@ -497,7 +497,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU
value = GET_OP2_ZVAL_PTR(BP_VAR_R);
var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets");
}
@ -692,7 +692,7 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR|
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
retval = EX_VAR(opline->result.var);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(object) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(object == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
@ -784,7 +784,7 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
retval = EX_VAR(opline->result.var);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(object) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(object == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
@ -867,6 +867,10 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY)
SAVE_OPLINE();
var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW);
if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
fast_increment_function(var_ptr);
if (RETURN_VALUE_USED(opline)) {
@ -875,9 +879,6 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY)
ZEND_VM_NEXT_OPCODE();
}
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) {
if (RETURN_VALUE_USED(opline)) {
ZVAL_NULL(EX_VAR(opline->result.var));
@ -922,6 +923,10 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY)
SAVE_OPLINE();
var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW);
if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
fast_decrement_function(var_ptr);
if (RETURN_VALUE_USED(opline)) {
@ -930,9 +935,6 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY)
ZEND_VM_NEXT_OPCODE();
}
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) {
if (RETURN_VALUE_USED(opline)) {
ZVAL_NULL(EX_VAR(opline->result.var));
@ -977,15 +979,16 @@ ZEND_VM_HANDLER(36, ZEND_POST_INC, VAR|CV, ANY)
SAVE_OPLINE();
var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW);
if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
fast_increment_function(var_ptr);
ZEND_VM_NEXT_OPCODE();
}
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) {
ZVAL_NULL(EX_VAR(opline->result.var));
FREE_OP1_VAR_PTR();
@ -1031,15 +1034,16 @@ ZEND_VM_HANDLER(37, ZEND_POST_DEC, VAR|CV, ANY)
SAVE_OPLINE();
var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW);
if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
fast_decrement_function(var_ptr);
ZEND_VM_NEXT_OPCODE();
}
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) {
ZVAL_NULL(EX_VAR(opline->result.var));
FREE_OP1_VAR_PTR();
@ -1279,7 +1283,7 @@ ZEND_VM_HANDLER(84, ZEND_FETCH_DIM_W, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
SAVE_OPLINE();
container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
if (EXPECTED(opline->extended_value == 0)) {
@ -1305,7 +1309,7 @@ ZEND_VM_HANDLER(87, ZEND_FETCH_DIM_RW, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
SAVE_OPLINE();
container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC);
@ -1377,7 +1381,7 @@ ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMP|VAR|CV)
SAVE_OPLINE();
container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_UNSET);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC);
@ -1439,7 +1443,7 @@ ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
}
@ -1464,7 +1468,7 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
}
zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC);
@ -1526,7 +1530,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|
if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) {
zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context");
}
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
}
zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC);
@ -1552,7 +1556,7 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET);
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
}
zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC);
@ -1598,7 +1602,7 @@ ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W);
property_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(object) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(object == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_OBJ, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC);
@ -1619,7 +1623,7 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
SAVE_OPLINE();
object_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(object_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) {
@ -1635,57 +1639,38 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
zend_free_op free_op2, free_op_data1, free_op_data2;
zval *value;
zval *dim = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R);
zval *variable_ptr = EX_VAR((opline+1)->op2.var);
zend_long offset = 0;
zval *variable_ptr;
if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) || (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_STRING)) {
ZVAL_DEREF(object_ptr);
if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) {
goto string_failed;
}
if (dim == NULL) {
zend_error_noreturn(E_ERROR, "[] operator not supported for strings");
}
SEPARATE_STRING(object_ptr);
offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC);
if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr));
ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset);
} else {
string_failed:
zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, OP2_TYPE TSRMLS_CC);
}
variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, OP2_TYPE TSRMLS_CC);
FREE_OP2();
value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
} else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
if (IS_TMP_FREE(free_op_data1)) {
zval_dtor(value);
}
if (RETURN_VALUE_USED(opline)) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
FREE_OP_VAR_PTR(free_op_data2);
if (UNEXPECTED(variable_ptr != NULL)) {
zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
} else {
if ((opline+1)->op1_type == IS_TMP_VAR) {
value = zend_assign_tmp_to_variable(variable_ptr, value TSRMLS_CC);
} else if ((opline+1)->op1_type == IS_CONST) {
value = zend_assign_const_to_variable(variable_ptr, value TSRMLS_CC);
variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
if (IS_TMP_FREE(free_op_data1)) {
zval_dtor(value);
}
if (RETURN_VALUE_USED(opline)) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
FREE_OP_VAR_PTR(free_op_data2);
} else {
value = zend_assign_to_variable(variable_ptr, value TSRMLS_CC);
if ((opline+1)->op1_type == IS_TMP_VAR) {
value = zend_assign_tmp_to_variable(variable_ptr, value TSRMLS_CC);
} else if ((opline+1)->op1_type == IS_CONST) {
value = zend_assign_const_to_variable(variable_ptr, value TSRMLS_CC);
} else {
value = zend_assign_to_variable(variable_ptr, value TSRMLS_CC);
}
if (RETURN_VALUE_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), value);
}
FREE_OP_VAR_PTR(free_op_data2);
}
if (RETURN_VALUE_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), value);
}
FREE_OP_VAR_PTR(free_op_data2);
}
FREE_OP_IF_VAR(free_op_data1);
FREE_OP_IF_VAR(free_op_data1);
}
FREE_OP1_VAR_PTR();
/* assign_dim has two opcodes! */
@ -1768,8 +1753,8 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV)
UNEXPECTED(!Z_ISREF_P(variable_ptr))) {
zend_error_noreturn(E_ERROR, "Cannot assign by reference to overloaded object");
}
if ((OP2_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(value_ptr) == IS_STR_OFFSET)) ||
(OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET))) {
if ((OP2_TYPE == IS_VAR && UNEXPECTED(value_ptr == NULL)) ||
(OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == NULL))) {
zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects");
}
if ((OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) ||
@ -2898,7 +2883,7 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY)
retval_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(retval_ptr) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(retval_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot return string offsets by reference");
}
@ -3134,7 +3119,7 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY)
SAVE_OPLINE();
varptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(varptr) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(varptr == NULL)) {
zend_error_noreturn(E_ERROR, "Only variables can be passed by reference");
}
@ -3933,7 +3918,7 @@ ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMP|VAR|UNUS
if ((OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) &&
(opline->extended_value & ZEND_ARRAY_ELEMENT_REF)) {
expr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(expr_ptr) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(expr_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets");
}
ZVAL_MAKE_REF(expr_ptr);
@ -4357,6 +4342,9 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
SAVE_OPLINE();
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET);
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot unset string offsets");
}
if (OP1_TYPE != IS_UNUSED) {
ZVAL_DEREF(container);
SEPARATE_ZVAL_NOREF(container);
@ -4435,7 +4423,6 @@ ZEND_VM_C_LABEL(numeric_index_dim):
FREE_OP2();
break;
case IS_STRING:
case IS_STR_OFFSET:
zend_error_noreturn(E_ERROR, "Cannot unset string offsets");
ZEND_VM_CONTINUE(); /* bailed out before */
default:
@ -4456,7 +4443,7 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
SAVE_OPLINE();
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET);
if (OP1_TYPE == IS_VAR && Z_TYPE_P(container) == IS_STR_OFFSET) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot unset string offsets");
}
offset = GET_OP2_ZVAL_PTR(BP_VAR_R);
@ -5667,7 +5654,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
} else {
zval *value_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(value_ptr) == IS_STR_OFFSET)) {
if (OP1_TYPE == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
}

File diff suppressed because it is too large Load Diff