ZEND_FETCH_*_R operations simplified and can't be used with EXT_TYPE_UNUSED flag any more. Thit is very rare and useless case. ZEND_FREE might be required after them instead.

This commit is contained in:
Dmitry Stogov 2010-07-16 13:38:09 +00:00
parent 8aad91d14a
commit ca4de03eed
7 changed files with 487 additions and 721 deletions

3
NEWS
View File

@ -22,6 +22,9 @@ PHP NEWS
. $GLOBALS became a JIT autoglobal, so it's initialized only if used
(this may affect opcode caches)
. simplified string ofset reading. $str[1][0] now is a legal construct.
. ZEND_FETCH_*_R operations simplified and can't be used with EXT_TYPE_UNUSED
flag any more. Thit is very rare and useless case. ZEND_FREE might be
required after them instead.
- Added concept of interned strings. All strings constants known at compile
time are allocated in a single copy and never changed. (Dmitry)
- Added an optimization which saves memory and emalloc/efree calls for empty

View File

@ -63,10 +63,18 @@ print "\nDone\n";
?>
--EXPECTF--
Notice: Uninitialized string offset: %i in %s on line 6
Notice: Uninitialized string offset: 0 in %s on line 10
Notice: Uninitialized string offset: 0 in %s on line 12
Notice: Uninitialized string offset: %i in %s on line 14
Notice: Uninitialized string offset: %i in %s on line 16
Notice: Uninitialized string offset: 0 in %s on line 18
Notice: Uninitialized string offset: 4 in %s on line 28
Notice: Uninitialized string offset: 4 in %s on line 34
@ -77,6 +85,8 @@ Notice: Uninitialized string offset: 4 in %s on line 42
Notice: Uninitialized string offset: 4 in %s on line 46
Notice: Uninitialized string offset: 12 in %s on line 50
Notice: Uninitialized string offset: 12 in %s on line 52
b
Done

View File

@ -0,0 +1,29 @@
--TEST--
Unused result of fetch operations
--FILE--
<?php
$x = array(1);
$a = "x";
$$a;
$x = array(array(2));
$x[0];
$x = "str";
$x[0];
$x[3];
class Foo {
public $prop = array(3);
function __get($name) {
return array(4);
}
}
$x = new Foo();
$x->prop;
$x->y;
echo "ok\n";
--EXPECTF--
Notice: Uninitialized string offset: 3 in %sresult_unused.php on line 11
ok

View File

@ -1422,7 +1422,19 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
}
if (opline->result_type == IS_VAR
&& opline->result.var == op1->u.op.var) {
opline->result_type |= EXT_TYPE_UNUSED;
if (opline->opcode == ZEND_FETCH_R ||
opline->opcode == ZEND_FETCH_DIM_R ||
opline->opcode == ZEND_FETCH_OBJ_R) {
/* It's very rare and useless case. It's better to use
additional FREE opcode and simplify the FETCH handlers
their selves */
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_FREE;
SET_NODE(opline->op1, op1);
SET_UNUSED(opline->op2);
} else {
opline->result_type |= EXT_TYPE_UNUSED;
}
} else {
while (opline>CG(active_op_array)->opcodes) {
if (opline->opcode == ZEND_FETCH_DIM_R
@ -6065,7 +6077,7 @@ int zend_register_auto_global(const char *name, uint name_len, zend_bool jit, ze
{
zend_auto_global auto_global;
auto_global.name = zend_new_interned_string(name, name_len + 1, 0 TSRMLS_CC);
auto_global.name = zend_new_interned_string((char*)name, name_len + 1, 0 TSRMLS_CC);
auto_global.name_len = name_len;
auto_global.auto_global_callback = auto_global_callback;
auto_global.jit = jit;

View File

@ -1218,23 +1218,18 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
case IS_ARRAY:
retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC);
if (result) {
AI_SET_PTR(result, *retval);
PZVAL_LOCK(*retval);
}
AI_SET_PTR(result, *retval);
PZVAL_LOCK(*retval);
return;
break;
case IS_NULL:
if (result) {
AI_SET_PTR(result, &EG(uninitialized_zval));
PZVAL_LOCK(&EG(uninitialized_zval));
}
AI_SET_PTR(result, &EG(uninitialized_zval));
PZVAL_LOCK(&EG(uninitialized_zval));
return;
break;
case IS_STRING: {
zval tmp;
zval *ptr;
if (Z_TYPE_P(dim) != IS_LONG) {
switch(Z_TYPE_P(dim)) {
@ -1255,25 +1250,22 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
convert_to_long(&tmp);
dim = &tmp;
}
if (result) {
zval *ptr;
ALLOC_ZVAL(ptr);
INIT_PZVAL(ptr);
Z_TYPE_P(ptr) = IS_STRING;
ALLOC_ZVAL(ptr);
INIT_PZVAL(ptr);
Z_TYPE_P(ptr) = IS_STRING;
if (Z_LVAL_P(dim) < 0 || Z_STRLEN_P(container) <= Z_LVAL_P(dim)) {
zend_error(E_NOTICE, "Uninitialized string offset: %ld", Z_LVAL_P(dim));
Z_STRVAL_P(ptr) = STR_EMPTY_ALLOC();
Z_STRLEN_P(ptr) = 0;
} else {
Z_STRVAL_P(ptr) = (char*)emalloc(2);
Z_STRVAL_P(ptr)[0] = Z_STRVAL_P(container)[Z_LVAL_P(dim)];
Z_STRVAL_P(ptr)[1] = 0;
Z_STRLEN_P(ptr) = 1;
}
AI_SET_PTR(result, ptr);
if (Z_LVAL_P(dim) < 0 || Z_STRLEN_P(container) <= Z_LVAL_P(dim)) {
zend_error(E_NOTICE, "Uninitialized string offset: %ld", Z_LVAL_P(dim));
Z_STRVAL_P(ptr) = STR_EMPTY_ALLOC();
Z_STRLEN_P(ptr) = 0;
} else {
Z_STRVAL_P(ptr) = (char*)emalloc(2);
Z_STRVAL_P(ptr)[0] = Z_STRVAL_P(container)[Z_LVAL_P(dim)];
Z_STRVAL_P(ptr)[1] = 0;
Z_STRLEN_P(ptr) = 1;
}
AI_SET_PTR(result, ptr);
return;
}
break;
@ -1292,14 +1284,8 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim, type TSRMLS_CC);
if (overloaded_result) {
if (result) {
AI_SET_PTR(result, 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);
}
AI_SET_PTR(result, overloaded_result);
PZVAL_LOCK(overloaded_result);
} else if (result) {
AI_SET_PTR(result, &EG(uninitialized_zval));
PZVAL_LOCK(&EG(uninitialized_zval));
@ -1309,15 +1295,11 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
}
}
return;
break;
default:
if (result) {
AI_SET_PTR(result, &EG(uninitialized_zval));
PZVAL_LOCK(&EG(uninitialized_zval));
}
AI_SET_PTR(result, &EG(uninitialized_zval));
PZVAL_LOCK(&EG(uninitialized_zval));
return;
break;
}
}

View File

@ -1105,31 +1105,29 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMP|VAR|CV, UNUSED|CONST|
if (OP1_TYPE != IS_CONST && varname == &tmp_varname) {
zval_dtor(&tmp_varname);
}
if (RETURN_VALUE_USED(opline)) {
if (opline->extended_value & ZEND_FETCH_MAKE_REF) {
SEPARATE_ZVAL_TO_MAKE_IS_REF(retval);
}
PZVAL_LOCK(*retval);
switch (type) {
case BP_VAR_R:
case BP_VAR_IS:
AI_SET_PTR(&EX_T(opline->result.var), *retval);
break;
case BP_VAR_UNSET: {
zend_free_op free_res;
if (opline->extended_value & ZEND_FETCH_MAKE_REF) {
SEPARATE_ZVAL_TO_MAKE_IS_REF(retval);
}
PZVAL_LOCK(*retval);
switch (type) {
case BP_VAR_R:
case BP_VAR_IS:
AI_SET_PTR(&EX_T(opline->result.var), *retval);
break;
case BP_VAR_UNSET: {
zend_free_op free_res;
PZVAL_UNLOCK(*retval, &free_res);
if (retval != &EG(uninitialized_zval_ptr)) {
SEPARATE_ZVAL_IF_NOT_REF(retval);
}
PZVAL_LOCK(*retval);
FREE_OP_VAR_PTR(free_res);
PZVAL_UNLOCK(*retval, &free_res);
if (retval != &EG(uninitialized_zval_ptr)) {
SEPARATE_ZVAL_IF_NOT_REF(retval);
}
/* break missing intentionally */
default:
EX_T(opline->result.var).var.ptr_ptr = retval;
break;
PZVAL_LOCK(*retval);
FREE_OP_VAR_PTR(free_res);
}
/* break missing intentionally */
default:
EX_T(opline->result.var).var.ptr_ptr = retval;
break;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
@ -1182,7 +1180,7 @@ ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, VAR|CV, CONST|TMP|VAR|CV)
PZVAL_LOCK(*EX_T(opline->op1.var).var.ptr_ptr);
}
container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
zend_fetch_dimension_address_read(!RETURN_VALUE_USED(opline)?NULL:&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC);
zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC);
FREE_OP2();
FREE_OP1_VAR_PTR();
CHECK_EXCEPTION();
@ -1345,10 +1343,8 @@ ZEND_VM_HELPER(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|TMP
if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) ||
UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) {
zend_error(E_NOTICE, "Trying to get property of non-object");
if (RETURN_VALUE_USED(opline)) {
PZVAL_LOCK(&EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
}
PZVAL_LOCK(&EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
FREE_OP2();
} else {
zval *retval;
@ -1360,16 +1356,8 @@ ZEND_VM_HELPER(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|TMP
/* here we are sure we are dealing with an object */
retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC);
if (!RETURN_VALUE_USED(opline)) {
if (Z_REFCOUNT_P(retval) == 0) {
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
zval_dtor(retval);
FREE_ZVAL(retval);
}
} else {
PZVAL_LOCK(retval);
AI_SET_PTR(&EX_T(opline->result.var), retval);
}
PZVAL_LOCK(retval);
AI_SET_PTR(&EX_T(opline->result.var), retval);
if (IS_OP2_TMP_FREE()) {
zval_ptr_dtor(&offset);
@ -1480,10 +1468,8 @@ ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) ||
UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) {
if (RETURN_VALUE_USED(opline)) {
PZVAL_LOCK(&EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
}
PZVAL_LOCK(&EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
FREE_OP2();
} else {
zval *retval;
@ -1495,16 +1481,8 @@ ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
/* here we are sure we are dealing with an object */
retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC);
if (!RETURN_VALUE_USED(opline)) {
if (Z_REFCOUNT_P(retval) == 0) {
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
zval_dtor(retval);
FREE_ZVAL(retval);
}
} else {
PZVAL_LOCK(retval);
AI_SET_PTR(&EX_T(opline->result.var), retval);
}
PZVAL_LOCK(retval);
AI_SET_PTR(&EX_T(opline->result.var), retval);
if (IS_OP2_TMP_FREE()) {
zval_ptr_dtor(&offset);
@ -1608,10 +1586,8 @@ ZEND_VM_HANDLER(98, ZEND_FETCH_DIM_TMP_VAR, CONST|TMP, CONST)
container = GET_OP1_ZVAL_PTR(BP_VAR_R);
if (UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) {
if (RETURN_VALUE_USED(opline)) {
PZVAL_LOCK(&EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
}
PZVAL_LOCK(&EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
} else {
zend_free_op free_op2;
zval *value = *zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC);
@ -2008,12 +1984,16 @@ ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMP|VAR|CV, ANY)
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(70, ZEND_FREE, TMP, ANY)
ZEND_VM_HANDLER(70, ZEND_FREE, TMP|VAR, ANY)
{
USE_OPLINE
SAVE_OPLINE();
zendi_zval_dtor(EX_T(opline->op1.var).tmp_var);
if (OP1_TYPE == IS_TMP_VAR) {
zendi_zval_dtor(EX_T(opline->op1.var).tmp_var);
} else {
zval_ptr_dtor(&EX_T(opline->op1.var).var.ptr);
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}

File diff suppressed because it is too large Load Diff