Merge branch 'PHP-7.0'

Conflicts:
	ext/opcache/Optimizer/zend_optimizer.c
This commit is contained in:
Nikita Popov 2015-11-07 12:09:20 +01:00
commit 603c172269
6 changed files with 157 additions and 76 deletions

View File

@ -0,0 +1,13 @@
--TEST--
Accessing a static property on a statically evaluable class expression
--FILE--
<?php
class A {
public static $b = 42;
}
var_dump(('A' . (string) '')::$b);
?>
--EXPECT--
int(42)

View File

@ -0,0 +1,13 @@
--TEST--
Static property on constexpr class with leading backslash
--FILE--
<?php
class A {
public static $b = 42;
}
var_dump(('\A' . (string) '')::$b);
?>
--EXPECT--
int(42)

View File

@ -0,0 +1,11 @@
--TEST--
Static property access on constexpr class evaluating to integer
--FILE--
<?php
((int)1)::$b;
?>
--EXPECTF--
Fatal error: Uncaught Error: Class name must be a valid object or a string in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

View File

@ -643,13 +643,15 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
(opline->opcode != ZEND_FE_RESET_R || opline->opcode != ZEND_FE_RESET_RW) &&
opline->opcode != ZEND_FREE
) {
zend_op *src = VAR_SOURCE(opline->op1);
znode_op op1 = opline->op1;
zend_op *src = VAR_SOURCE(op1);
zval c = ZEND_OP1_LITERAL(src);
VAR_UNSET(opline->op1);
zval_copy_ctor(&c);
zend_optimizer_update_op1_const(op_array, opline, &c);
literal_dtor(&ZEND_OP1_LITERAL(src));
MAKE_NOP(src);
if (zend_optimizer_update_op1_const(op_array, opline, &c)) {
VAR_SOURCE(op1) = NULL;
literal_dtor(&ZEND_OP1_LITERAL(src));
MAKE_NOP(src);
}
}
/* T = QM_ASSIGN(C), F(T) => NOP, F(C) */
@ -657,13 +659,15 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
VAR_SOURCE(opline->op2) &&
VAR_SOURCE(opline->op2)->opcode == ZEND_QM_ASSIGN &&
ZEND_OP1_TYPE(VAR_SOURCE(opline->op2)) == IS_CONST) {
zend_op *src = VAR_SOURCE(opline->op2);
znode_op op2 = opline->op2;
zend_op *src = VAR_SOURCE(op2);
zval c = ZEND_OP1_LITERAL(src);
VAR_UNSET(opline->op2);
zval_copy_ctor(&c);
zend_optimizer_update_op2_const(op_array, opline, &c);
literal_dtor(&ZEND_OP1_LITERAL(src));
MAKE_NOP(src);
if (zend_optimizer_update_op2_const(op_array, opline, &c)) {
VAR_SOURCE(op2) = NULL;
literal_dtor(&ZEND_OP1_LITERAL(src));
MAKE_NOP(src);
}
}
/* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */

View File

@ -110,6 +110,13 @@ int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv)
return i;
}
static inline int zend_optimizer_add_literal_string(zend_op_array *op_array, zend_string *str) {
zval zv;
ZVAL_STR(&zv, str);
zend_string_hash_val(str);
return zend_optimizer_add_literal(op_array, &zv);
}
int zend_optimizer_is_disabled_func(const char *name, size_t len) {
zend_function *fbc = (zend_function *)zend_hash_str_find_ptr(EG(function_table), name, len);
@ -117,65 +124,104 @@ int zend_optimizer_is_disabled_func(const char *name, size_t len) {
fbc->internal_function.handler == ZEND_FN(display_disabled_function));
}
void zend_optimizer_update_op1_const(zend_op_array *op_array,
zend_op *opline,
zval *val)
{
if (opline->opcode == ZEND_FREE) {
MAKE_NOP(opline);
static inline void drop_leading_backslash(zval *val) {
if (Z_STRVAL_P(val)[0] == '\\') {
zend_string *str = zend_string_init(Z_STRVAL_P(val) + 1, Z_STRLEN_P(val) - 1, 0);
zval_dtor(val);
} else {
ZEND_OP1_TYPE(opline) = IS_CONST;
if (Z_TYPE_P(val) == IS_STRING) {
switch (opline->opcode) {
case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_CATCH:
case ZEND_FETCH_CONSTANT:
case ZEND_FETCH_CLASS_CONSTANT:
case ZEND_DEFINED:
case ZEND_NEW:
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(op_array->literals[opline->op1.constant+1]));
break;
default:
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
break;
}
} else {
if (opline->opcode == ZEND_CONCAT ||
opline->opcode == ZEND_FAST_CONCAT) {
convert_to_string(val);
}
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
}
ZVAL_STR(val, str);
}
}
void zend_optimizer_update_op2_const(zend_op_array *op_array,
zend_op *opline,
zval *val)
int zend_optimizer_update_op1_const(zend_op_array *op_array,
zend_op *opline,
zval *val)
{
switch (opline->opcode) {
case ZEND_FREE:
MAKE_NOP(opline);
zval_dtor(val);
break;
case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_CATCH:
case ZEND_FETCH_CONSTANT:
case ZEND_FETCH_CLASS_CONSTANT:
case ZEND_DEFINED:
case ZEND_NEW:
if (Z_TYPE_P(val) != IS_STRING) {
zval_dtor(val);
return 0;
}
ZEND_OP1_TYPE(opline) = IS_CONST;
drop_leading_backslash(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
break;
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
convert_to_string(val);
/* break missing intentionally */
default:
ZEND_OP1_TYPE(opline) = IS_CONST;
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
if (Z_TYPE_P(val) == IS_STRING) {
zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
}
break;
}
return 1;
}
int zend_optimizer_update_op2_const(zend_op_array *op_array,
zend_op *opline,
zval *val)
{
ZEND_OP2_TYPE(opline) = IS_CONST;
if (opline->opcode == ZEND_INIT_FCALL) {
ZEND_OP2_TYPE(opline) = IS_CONST;
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
return;
} else if (opline->opcode == ZEND_ROPE_INIT ||
opline->opcode == ZEND_ROPE_ADD ||
opline->opcode == ZEND_ROPE_END ||
opline->opcode == ZEND_CONCAT ||
opline->opcode == ZEND_FAST_CONCAT) {
convert_to_string(val);
return 1;
}
switch (opline->opcode) {
case ZEND_ROPE_INIT:
case ZEND_ROPE_ADD:
case ZEND_ROPE_END:
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
convert_to_string(val);
break;
case ZEND_FETCH_CLASS:
case ZEND_INIT_FCALL_BY_NAME:
/*case ZEND_INIT_NS_FCALL_BY_NAME:*/
case ZEND_ADD_INTERFACE:
case ZEND_ADD_TRAIT:
case ZEND_INSTANCEOF:
case ZEND_FETCH_STATIC_PROP_R:
case ZEND_FETCH_STATIC_PROP_W:
case ZEND_FETCH_STATIC_PROP_RW:
case ZEND_FETCH_STATIC_PROP_IS:
case ZEND_FETCH_STATIC_PROP_UNSET:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
case ZEND_UNSET_STATIC_PROP:
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
if (Z_TYPE_P(val) != IS_STRING) {
zval_dtor(val);
return 0;
}
/* break missing intentionally */
case ZEND_INIT_DYNAMIC_CALL:
drop_leading_backslash(val);
break;
}
ZEND_OP2_TYPE(opline) = IS_CONST;
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
if (Z_TYPE_P(val) == IS_STRING) {
zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
@ -196,23 +242,17 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1]));
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
break;
case ZEND_INIT_DYNAMIC_CALL:
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1]));
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
break;
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_STATIC_METHOD_CALL:
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1]));
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
/* break missing intentionally */
/*case ZEND_FETCH_CLASS_CONSTANT:*/
case ZEND_ASSIGN_OBJ:
@ -293,6 +333,8 @@ check_numeric:
break;
}
}
return 1;
}
int zend_optimizer_replace_by_const(zend_op_array *op_array,
@ -400,8 +442,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
default:
break;
}
zend_optimizer_update_op1_const(op_array, opline, val);
break;
return zend_optimizer_update_op1_const(op_array, opline, val);
}
if (ZEND_OP2_TYPE(opline) == type &&
@ -413,8 +454,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
default:
break;
}
zend_optimizer_update_op2_const(op_array, opline, val);
break;
return zend_optimizer_update_op2_const(op_array, opline, val);
}
opline++;
}

View File

@ -118,12 +118,12 @@ int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int
void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value);
int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value);
int zend_optimizer_lookup_cv(zend_op_array *op_array, zend_string* name);
void zend_optimizer_update_op1_const(zend_op_array *op_array,
zend_op *opline,
zval *val);
void zend_optimizer_update_op2_const(zend_op_array *op_array,
zend_op *opline,
zval *val);
int zend_optimizer_update_op1_const(zend_op_array *op_array,
zend_op *opline,
zval *val);
int zend_optimizer_update_op2_const(zend_op_array *op_array,
zend_op *opline,
zval *val);
int zend_optimizer_replace_by_const(zend_op_array *op_array,
zend_op *opline,
zend_uchar type,