Speed up fetching of class entries for self:: parent:: and static::

This is generalized solution for Bob's idea of speed up self::method() calls without ZEND_FETCH_CLASS.

At first, it adds few new opcodes to separate class related behaviour:
	FETCH_STATIC_PROP_R
	FETCH_STATIC_PROP_W
	FETCH_STATIC_PROP_RW
	FETCH_STATIC_PROP_FUNC_ARG
	FETCH_STATIC_PROP_UNSET
	FETCH_STATIC_PROP_IS
	UNSET_STATIC_PROP
	ISSET_ISEMPTY_STATIC_PROP
	FETCH_CLASS_CONSTANT

At seconds, it enables IS_UNUSED operand to fetch (self, parent or static without separate FETCH_CLASS) for new opcodes and the following ones:
	INIT_STATIC_METHOD_CALL
	NEW
	END_INSTANCEOF

Finaly, opcache optimizer had to be fixed to support new opcodes.
This commit is contained in:
Dmitry Stogov 2015-10-27 15:47:58 +03:00
parent ff0ec06562
commit eb7be5379d
10 changed files with 3556 additions and 2656 deletions

View File

@ -627,7 +627,8 @@ void zend_do_free(znode *op1) /* {{{ */
&& opline->result.var == op1->u.op.var) {
if (opline->opcode == ZEND_FETCH_R ||
opline->opcode == ZEND_FETCH_DIM_R ||
opline->opcode == ZEND_FETCH_OBJ_R) {
opline->opcode == ZEND_FETCH_OBJ_R ||
opline->opcode == ZEND_FETCH_STATIC_PROP_R) {
/* It's very rare and useless case. It's better to use
additional FREE opcode and simplify the FETCH handlers
their selves */
@ -1807,25 +1808,27 @@ ZEND_API size_t zend_dirname(char *path, size_t len)
static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */
{
zend_uchar factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3;
switch (type & BP_VAR_MASK) {
case BP_VAR_R:
return;
case BP_VAR_W:
case BP_VAR_REF:
opline->opcode += 3;
opline->opcode += 1 * factor;
return;
case BP_VAR_RW:
opline->opcode += 6;
opline->opcode += 2 * factor;
return;
case BP_VAR_IS:
opline->opcode += 9;
opline->opcode += 3 * factor;
return;
case BP_VAR_FUNC_ARG:
opline->opcode += 12;
opline->opcode += 4 * factor;
opline->extended_value |= type >> BP_VAR_SHIFT;
return;
case BP_VAR_UNSET:
opline->opcode += 15;
opline->opcode += 5 * factor;
return;
EMPTY_SWITCH_DEFAULT_CASE()
}
@ -2158,6 +2161,62 @@ static zend_op *zend_compile_class_ref(znode *result, zend_ast *name_ast, int th
}
/* }}} */
static void zend_compile_class_ref_ex(znode *result, zend_ast *name_ast, uint32_t fetch_flags) /* {{{ */
{
uint32_t fetch_type;
if (name_ast->kind != ZEND_AST_ZVAL) {
znode name_node;
zend_compile_expr(&name_node, name_ast);
if (name_node.op_type == IS_CONST) {
zend_string *name;
if (Z_TYPE(name_node.u.constant) != IS_STRING) {
zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
}
name = Z_STR(name_node.u.constant);
fetch_type = zend_get_class_fetch_type(name);
if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
result->op_type = IS_CONST;
ZVAL_STR(&result->u.constant, zend_resolve_class_name(name, ZEND_NAME_FQ));
} else {
zend_ensure_valid_class_fetch_type(fetch_type);
result->op_type = IS_UNUSED;
result->u.op.num = fetch_type | fetch_flags;
}
zend_string_release(name);
} else {
zend_op *opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, &name_node);
opline->extended_value = ZEND_FETCH_CLASS_DEFAULT | fetch_flags;
}
return;
}
/* Fully qualified names are always default refs */
if (name_ast->attr == ZEND_NAME_FQ) {
result->op_type = IS_CONST;
ZVAL_STR(&result->u.constant, zend_resolve_class_name_ast(name_ast));
return;
}
fetch_type = zend_get_class_fetch_type(zend_ast_get_str(name_ast));
if (ZEND_FETCH_CLASS_DEFAULT == fetch_type) {
result->op_type = IS_CONST;
ZVAL_STR(&result->u.constant, zend_resolve_class_name_ast(name_ast));
} else {
zend_ensure_valid_class_fetch_type(fetch_type);
result->op_type = IS_UNUSED;
result->u.op.num = fetch_type | fetch_flags;
return 0;
}
}
/* }}} */
static int zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *name_ast = ast->child[0];
@ -2364,19 +2423,14 @@ zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, uint32_t
znode class_node, prop_node;
zend_op *opline;
if (zend_is_const_default_class_ref(class_ast)) {
class_node.op_type = IS_CONST;
ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast));
} else {
zend_compile_class_ref(&class_node, class_ast, 1);
}
zend_compile_class_ref_ex(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
zend_compile_expr(&prop_node, prop_ast);
if (delayed) {
opline = zend_delayed_emit_op(result, ZEND_FETCH_R, &prop_node, NULL);
opline = zend_delayed_emit_op(result, ZEND_FETCH_STATIC_PROP_R, &prop_node, NULL);
} else {
opline = zend_emit_op(result, ZEND_FETCH_R, &prop_node, NULL);
opline = zend_emit_op(result, ZEND_FETCH_STATIC_PROP_R, &prop_node, NULL);
}
if (opline->op1_type == IS_CONST) {
zend_alloc_polymorphic_cache_slot(opline->op1.constant);
@ -3296,15 +3350,8 @@ void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{
znode class_node, method_node;
zend_op *opline;
zend_ulong extended_value = 0;
if (zend_is_const_default_class_ref(class_ast)) {
class_node.op_type = IS_CONST;
ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast));
} else {
opline = zend_compile_class_ref(&class_node, class_ast, 1);
extended_value = opline->extended_value;
}
zend_compile_class_ref_ex(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
zend_compile_expr(&method_node, method_ast);
if (method_node.op_type == IS_CONST) {
@ -3320,7 +3367,6 @@ void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{
opline = get_next_op(CG(active_op_array));
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
opline->extended_value = extended_value;
zend_set_class_name_op1(opline, &class_node);
@ -3352,10 +3398,7 @@ void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */
zend_op *opline;
uint32_t opnum;
if (zend_is_const_default_class_ref(class_ast)) {
class_node.op_type = IS_CONST;
ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast));
} else if (class_ast->kind == ZEND_AST_CLASS) {
if (class_ast->kind == ZEND_AST_CLASS) {
uint32_t dcl_opnum = get_next_op_number(CG(active_op_array));
zend_compile_class_decl(class_ast);
/* jump over anon class declaration */
@ -3367,7 +3410,7 @@ void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */
class_node.u.op.var = opline->result.var;
opline->op1.opline_num = get_next_op_number(CG(active_op_array));
} else {
zend_compile_class_ref(&class_node, class_ast, 1);
zend_compile_class_ref_ex(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
}
opnum = get_next_op_number(CG(active_op_array));
@ -3507,7 +3550,7 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */
return;
case ZEND_AST_STATIC_PROP:
opline = zend_compile_static_prop_common(NULL, var_ast, BP_VAR_UNSET, 0);
opline->opcode = ZEND_UNSET_VAR;
opline->opcode = ZEND_UNSET_STATIC_PROP;
return;
EMPTY_SWITCH_DEFAULT_CASE()
}
@ -6301,13 +6344,7 @@ void zend_compile_instanceof(znode *result, zend_ast *ast) /* {{{ */
"instanceof expects an object instance, constant given");
}
if (zend_is_const_default_class_ref(class_ast)) {
class_node.op_type = IS_CONST;
ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast));
} else {
opline = zend_compile_class_ref(&class_node, class_ast, 0);
opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD;
}
zend_compile_class_ref_ex(&class_node, class_ast, ZEND_FETCH_CLASS_NO_AUTOLOAD);
opline = zend_emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, NULL);
@ -6379,7 +6416,7 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
break;
case ZEND_AST_STATIC_PROP:
opline = zend_compile_static_prop_common(result, var_ast, BP_VAR_IS, 0);
opline->opcode = ZEND_ISSET_ISEMPTY_VAR;
opline->opcode = ZEND_ISSET_ISEMPTY_STATIC_PROP;
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
@ -6559,7 +6596,6 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
znode class_node, const_node;
zend_op *opline;
zend_string *resolved_name;
if (zend_try_compile_const_expr_resolve_class_name(&result->u.constant, class_ast, const_ast, 0)) {
if (Z_TYPE(result->u.constant) == IS_NULL) {
@ -6575,31 +6611,26 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
zend_eval_const_expr(&const_ast);
if (class_ast->kind == ZEND_AST_ZVAL) {
zend_string *resolved_name;
resolved_name = zend_resolve_class_name_ast(class_ast);
if (const_ast->kind == ZEND_AST_ZVAL && zend_try_ct_eval_class_const(&result->u.constant, resolved_name, zend_ast_get_str(const_ast))) {
result->op_type = IS_CONST;
zend_string_release(resolved_name);
return;
}
zend_string_release(resolved_name);
}
if (const_ast->kind == ZEND_AST_ZVAL && zend_string_equals_literal_ci(zend_ast_get_str(const_ast), "class")) {
zend_error_noreturn(E_COMPILE_ERROR,
"Dynamic class names are not allowed in compile-time ::class fetch");
}
if (zend_is_const_default_class_ref(class_ast)) {
class_node.op_type = IS_CONST;
ZVAL_STR(&class_node.u.constant, resolved_name);
} else {
if (class_ast->kind == ZEND_AST_ZVAL) {
zend_string_release(resolved_name);
}
zend_compile_class_ref(&class_node, class_ast, 1);
}
zend_compile_class_ref_ex(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
zend_compile_expr(&const_node, const_ast);
opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, &const_node);
opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_CONSTANT, NULL, &const_node);
zend_set_class_name_op1(opline, &class_node);

View File

@ -1470,7 +1470,7 @@ ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMPVAR|CV, ANY)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED|CONST|VAR, int type)
ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type)
{
USE_OPLINE
zend_free_op free_op1;
@ -1494,61 +1494,30 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED|CONST|V
name = zval_get_string(varname);
}
if (OP2_TYPE != IS_UNUSED) {
zend_class_entry *ce;
if (OP2_TYPE == IS_CONST) {
if (OP1_TYPE == IS_CONST && EXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)))) != NULL)) {
retval = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)) + sizeof(void*));
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
FREE_OP1();
HANDLE_EXCEPTION();
}
ZEND_VM_C_GOTO(fetch_var_return);
} else if (UNEXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) == NULL)) {
ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op2)), EX_CONSTANT(opline->op2) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(ce == NULL)) {
if (OP1_TYPE != IS_CONST) {
zend_string_release(name);
}
FREE_OP1();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce);
}
} else {
ce = Z_CE_P(EX_VAR(opline->op2.var));
if (OP1_TYPE == IS_CONST &&
(retval = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce)) != NULL) {
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
FREE_OP1();
HANDLE_EXCEPTION();
}
ZEND_VM_C_GOTO(fetch_var_return);
}
target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK);
retval = zend_hash_find(target_symbol_table, name);
if (retval == NULL) {
switch (type) {
case BP_VAR_R:
case BP_VAR_UNSET:
zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name));
/* break missing intentionally */
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name));
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
break;
case BP_VAR_W:
retval = zend_hash_add_new(target_symbol_table, name, &EG(uninitialized_zval));
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
retval = zend_std_get_static_property(ce, name, 0);
if (UNEXPECTED(EG(exception))) {
FREE_OP1();
HANDLE_EXCEPTION();
}
if (OP1_TYPE == IS_CONST && retval) {
CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce, retval);
}
FREE_OP1();
} else {
target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK);
retval = zend_hash_find(target_symbol_table, name);
if (retval == NULL) {
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
retval = Z_INDIRECT_P(retval);
if (Z_TYPE_P(retval) == IS_UNDEF) {
switch (type) {
case BP_VAR_R:
case BP_VAR_UNSET:
@ -1559,52 +1528,30 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED|CONST|V
break;
case BP_VAR_RW:
zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name));
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
break;
/* break missing intentionally */
case BP_VAR_W:
retval = zend_hash_add_new(target_symbol_table, name, &EG(uninitialized_zval));
ZVAL_NULL(retval);
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
retval = Z_INDIRECT_P(retval);
if (Z_TYPE_P(retval) == IS_UNDEF) {
switch (type) {
case BP_VAR_R:
case BP_VAR_UNSET:
zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name));
/* break missing intentionally */
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name));
/* break missing intentionally */
case BP_VAR_W:
ZVAL_NULL(retval);
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
}
if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) {
if (Z_CONSTANT_P(retval)) {
if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) {
FREE_OP1();
HANDLE_EXCEPTION();
}
}
if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) {
if (Z_CONSTANT_P(retval)) {
if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) {
FREE_OP1();
HANDLE_EXCEPTION();
}
}
} else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) {
FREE_OP1();
}
} else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) {
FREE_OP1();
}
if (OP1_TYPE != IS_CONST) {
zend_string_release(name);
}
ZEND_VM_C_LABEL(fetch_var_return):
ZEND_ASSERT(retval != NULL);
if (type == BP_VAR_R || type == BP_VAR_IS) {
if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) {
@ -1617,22 +1564,22 @@ ZEND_VM_C_LABEL(fetch_var_return):
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HANDLER(80, ZEND_FETCH_R, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
ZEND_VM_HANDLER(80, ZEND_FETCH_R, CONST|TMPVAR|CV, UNUSED)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_R);
}
ZEND_VM_HANDLER(83, ZEND_FETCH_W, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
ZEND_VM_HANDLER(83, ZEND_FETCH_W, CONST|TMPVAR|CV, UNUSED)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_W);
}
ZEND_VM_HANDLER(86, ZEND_FETCH_RW, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
ZEND_VM_HANDLER(86, ZEND_FETCH_RW, CONST|TMPVAR|CV, UNUSED)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_RW);
}
ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMPVAR|CV, UNUSED)
{
USE_OPLINE
@ -1643,16 +1590,146 @@ ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
}
}
ZEND_VM_HANDLER(95, ZEND_FETCH_UNSET, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
ZEND_VM_HANDLER(95, ZEND_FETCH_UNSET, CONST|TMPVAR|CV, UNUSED)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_UNSET);
}
ZEND_VM_HANDLER(89, ZEND_FETCH_IS, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
ZEND_VM_HANDLER(89, ZEND_FETCH_IS, CONST|TMPVAR|CV, UNUSED)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_IS);
}
ZEND_VM_HELPER_EX(zend_fetch_static_prop_helper, CONST|TMPVAR|CV, UNUSED|CONST|VAR, int type)
{
USE_OPLINE
zend_free_op free_op1;
zval *varname;
zval *retval;
zend_string *name;
zend_class_entry *ce;
SAVE_OPLINE();
varname = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
if (OP1_TYPE == IS_CONST) {
name = Z_STR_P(varname);
} else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) {
name = Z_STR_P(varname);
zend_string_addref(name);
} else {
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) {
GET_OP1_UNDEF_CV(varname, BP_VAR_R);
}
name = zval_get_string(varname);
}
if (OP2_TYPE == IS_CONST) {
if (OP1_TYPE == IS_CONST && EXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)))) != NULL)) {
retval = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)) + sizeof(void*));
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
FREE_OP1();
HANDLE_EXCEPTION();
}
ZEND_VM_C_GOTO(fetch_static_prop_return);
} else if (UNEXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) == NULL)) {
ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op2)), EX_CONSTANT(opline->op2) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(ce == NULL)) {
if (OP1_TYPE != IS_CONST) {
zend_string_release(name);
}
FREE_OP1();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce);
}
} else {
if (OP2_TYPE == IS_UNUSED) {
ce = zend_fetch_class(NULL, opline->op2.num);
} else {
ce = Z_CE_P(EX_VAR(opline->op2.var));
}
if (OP1_TYPE == IS_CONST &&
(retval = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce)) != NULL) {
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
FREE_OP1();
HANDLE_EXCEPTION();
}
ZEND_VM_C_GOTO(fetch_static_prop_return);
}
}
retval = zend_std_get_static_property(ce, name, 0);
if (UNEXPECTED(EG(exception))) {
FREE_OP1();
HANDLE_EXCEPTION();
}
if (OP1_TYPE == IS_CONST && retval) {
CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce, retval);
}
FREE_OP1();
if (OP1_TYPE != IS_CONST) {
zend_string_release(name);
}
ZEND_VM_C_LABEL(fetch_static_prop_return):
ZEND_ASSERT(retval != NULL);
if (type == BP_VAR_R || type == BP_VAR_IS) {
if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) {
ZVAL_UNREF(retval);
}
ZVAL_COPY(EX_VAR(opline->result.var), retval);
} else {
ZVAL_INDIRECT(EX_VAR(opline->result.var), retval);
}
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HANDLER(173, ZEND_FETCH_STATIC_PROP_R, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_static_prop_helper, type, BP_VAR_R);
}
ZEND_VM_HANDLER(174, ZEND_FETCH_STATIC_PROP_W, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_static_prop_helper, type, BP_VAR_W);
}
ZEND_VM_HANDLER(175, ZEND_FETCH_STATIC_PROP_RW, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_static_prop_helper, type, BP_VAR_RW);
}
ZEND_VM_HANDLER(177, ZEND_FETCH_STATIC_PROP_FUNC_ARG, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
{
USE_OPLINE
if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) {
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_static_prop_helper, type, BP_VAR_W);
} else {
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_static_prop_helper, type, BP_VAR_R);
}
}
ZEND_VM_HANDLER(178, ZEND_FETCH_STATIC_PROP_UNSET, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_static_prop_helper, type, BP_VAR_UNSET);
}
ZEND_VM_HANDLER(176, ZEND_FETCH_STATIC_PROP_IS, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
{
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_static_prop_helper, type, BP_VAR_IS);
}
ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
{
USE_OPLINE
@ -3007,7 +3084,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|CV, CONST|TMPVAR
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMPVAR|UNUSED|CV)
ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CONST|VAR, CONST|TMPVAR|UNUSED|CV)
{
USE_OPLINE
zval *function_name;
@ -3032,6 +3109,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMPVAR|UNUSE
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce);
}
} else if (OP1_TYPE == IS_UNUSED) {
ce = zend_fetch_class(NULL, opline->op1.num);
} else {
ce = Z_CE_P(EX_VAR(opline->op1.var));
}
@ -3125,10 +3204,10 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMPVAR|UNUSE
}
}
if (OP1_TYPE != IS_CONST) {
if (OP1_TYPE == IS_UNUSED) {
/* previous opcode is ZEND_FETCH_CLASS */
if (((opline-1)->extended_value & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT ||
((opline-1)->extended_value & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
if ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT ||
(opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
ce = EX(called_scope);
}
}
@ -4892,7 +4971,7 @@ ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HANDLER(68, ZEND_NEW, CONST|VAR, ANY)
ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CONST|VAR, ANY)
{
USE_OPLINE
zval object_zval;
@ -4909,6 +4988,8 @@ ZEND_VM_HANDLER(68, ZEND_NEW, CONST|VAR, ANY)
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce);
}
} else if (OP1_TYPE == IS_UNUSED) {
ce = zend_fetch_class(NULL, opline->op1.num);
} else {
ce = Z_CE_P(EX_VAR(opline->op1.var));
}
@ -5025,110 +5106,122 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|CV, ANY)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST)
ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED, CONST)
{
USE_OPLINE
zend_constant *c;
SAVE_OPLINE();
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) {
c = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else if ((c = zend_quick_get_constant(EX_CONSTANT(opline->op2) + 1, opline->extended_value)) == NULL) {
if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
char *actual = (char *)zend_memrchr(Z_STRVAL_P(EX_CONSTANT(opline->op2)), '\\', Z_STRLEN_P(EX_CONSTANT(opline->op2)));
if (!actual) {
ZVAL_STR_COPY(EX_VAR(opline->result.var), Z_STR_P(EX_CONSTANT(opline->op2)));
} else {
actual++;
ZVAL_STRINGL(EX_VAR(opline->result.var),
actual, Z_STRLEN_P(EX_CONSTANT(opline->op2)) - (actual - Z_STRVAL_P(EX_CONSTANT(opline->op2))));
}
/* non-qualified constant - allow text substitution */
zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
Z_STRVAL_P(EX_VAR(opline->result.var)), Z_STRVAL_P(EX_VAR(opline->result.var)));
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
} else {
zend_throw_error(NULL, "Undefined constant '%s'", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
HANDLE_EXCEPTION();
}
} else {
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), c);
}
#ifdef ZTS
if (c->flags & CONST_PERSISTENT) {
ZVAL_DUP(EX_VAR(opline->result.var), &c->value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), &c->value);
}
#else
ZVAL_COPY(EX_VAR(opline->result.var), &c->value);
#endif
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED, CONST)
{
zend_class_entry *ce;
zval *value;
USE_OPLINE
SAVE_OPLINE();
if (OP1_TYPE == IS_UNUSED) {
zend_constant *c;
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) {
c = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else if ((c = zend_quick_get_constant(EX_CONSTANT(opline->op2) + 1, opline->extended_value)) == NULL) {
if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
char *actual = (char *)zend_memrchr(Z_STRVAL_P(EX_CONSTANT(opline->op2)), '\\', Z_STRLEN_P(EX_CONSTANT(opline->op2)));
if (!actual) {
ZVAL_STR_COPY(EX_VAR(opline->result.var), Z_STR_P(EX_CONSTANT(opline->op2)));
} else {
actual++;
ZVAL_STRINGL(EX_VAR(opline->result.var),
actual, Z_STRLEN_P(EX_CONSTANT(opline->op2)) - (actual - Z_STRVAL_P(EX_CONSTANT(opline->op2))));
}
/* non-qualified constant - allow text substitution */
zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
Z_STRVAL_P(EX_VAR(opline->result.var)), Z_STRVAL_P(EX_VAR(opline->result.var)));
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
do {
if (OP1_TYPE == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
ZVAL_DEREF(value);
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
#endif
break;
} else if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1))))) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
} else {
zend_throw_error(NULL, "Undefined constant '%s'", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
HANDLE_EXCEPTION();
ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op1)), EX_CONSTANT(opline->op1) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(ce == NULL)) {
if (EXPECTED(!EG(exception))) {
zend_throw_error(NULL, "Class '%s' not found", Z_STRVAL_P(EX_CONSTANT(opline->op1)));
}
HANDLE_EXCEPTION();
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce);
}
} else {
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), c);
}
#ifdef ZTS
if (c->flags & CONST_PERSISTENT) {
ZVAL_DUP(EX_VAR(opline->result.var), &c->value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), &c->value);
}
#else
ZVAL_COPY(EX_VAR(opline->result.var), &c->value);
#endif
} else {
/* class constant */
zend_class_entry *ce;
zval *value;
do {
if (OP1_TYPE == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
ZVAL_DEREF(value);
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
#endif
break;
} else if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1))))) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
} else {
ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op1)), EX_CONSTANT(opline->op1) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(ce == NULL)) {
if (EXPECTED(!EG(exception))) {
zend_throw_error(NULL, "Class '%s' not found", Z_STRVAL_P(EX_CONSTANT(opline->op1)));
}
HANDLE_EXCEPTION();
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce);
}
if (OP1_TYPE == IS_UNUSED) {
ce = zend_fetch_class(NULL, opline->op1.num);
} else {
ce = Z_CE_P(EX_VAR(opline->op1.var));
if ((value = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce)) != NULL) {
ZVAL_DEREF(value);
break;
}
}
if (EXPECTED((value = zend_hash_find(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
if ((value = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce)) != NULL) {
ZVAL_DEREF(value);
if (Z_CONSTANT_P(value)) {
EG(scope) = ce;
zval_update_constant_ex(value, 1, NULL);
EG(scope) = EX(func)->op_array.scope;
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
}
if (OP1_TYPE == IS_CONST) {
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), value);
} else {
CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce, value);
}
} else {
zend_throw_error(NULL, "Undefined class constant '%s'", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
HANDLE_EXCEPTION();
break;
}
} while (0);
#ifdef ZTS
if (ce->type == ZEND_INTERNAL_CLASS) {
ZVAL_DUP(EX_VAR(opline->result.var), value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), value);
}
#else
if (EXPECTED((value = zend_hash_find(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
ZVAL_DEREF(value);
if (Z_CONSTANT_P(value)) {
EG(scope) = ce;
zval_update_constant_ex(value, 1, NULL);
EG(scope) = EX(func)->op_array.scope;
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
}
if (OP1_TYPE == IS_CONST) {
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), value);
} else {
CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce, value);
}
} else {
zend_throw_error(NULL, "Undefined class constant '%s'", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
HANDLE_EXCEPTION();
}
} while (0);
#ifdef ZTS
if (ce->type == ZEND_INTERNAL_CLASS) {
ZVAL_DUP(EX_VAR(opline->result.var), value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), value);
#endif
}
#else
ZVAL_COPY(EX_VAR(opline->result.var), value);
#endif
ZEND_VM_NEXT_OPCODE();
}
@ -5493,7 +5586,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY)
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED)
{
USE_OPLINE
zval tmp, *varname;
@ -5502,7 +5595,6 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
SAVE_OPLINE();
if (OP1_TYPE == IS_CV &&
OP2_TYPE == IS_UNUSED &&
(opline->extended_value & ZEND_QUICK_SET)) {
zval *var = EX_VAR(opline->op1.var);
@ -5533,33 +5625,58 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
varname = &tmp;
}
if (OP2_TYPE != IS_UNUSED) {
zend_class_entry *ce;
target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK);
zend_hash_del_ind(target_symbol_table, Z_STR_P(varname));
if (OP2_TYPE == IS_CONST) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
if (UNEXPECTED(ce == NULL)) {
ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op2)), EX_CONSTANT(opline->op2) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(ce == NULL)) {
if (EXPECTED(!EG(exception))) {
zend_throw_error(NULL, "Class '%s' not found", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
}
if (OP1_TYPE != IS_CONST && Z_TYPE(tmp) != IS_UNDEF) {
zend_string_release(Z_STR(tmp));
}
FREE_OP1();
HANDLE_EXCEPTION();
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce);
}
} else {
ce = Z_CE_P(EX_VAR(opline->op2.var));
}
zend_std_unset_static_property(ce, Z_STR_P(varname));
} else {
target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK);
zend_hash_del_ind(target_symbol_table, Z_STR_P(varname));
if (OP1_TYPE != IS_CONST && Z_TYPE(tmp) != IS_UNDEF) {
zend_string_release(Z_STR(tmp));
}
FREE_OP1();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HANDLER(179, ZEND_UNSET_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
{
USE_OPLINE
zval tmp, *varname;
zend_class_entry *ce;
zend_free_op free_op1;
SAVE_OPLINE();
varname = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
ZVAL_UNDEF(&tmp);
if (OP1_TYPE != IS_CONST && Z_TYPE_P(varname) != IS_STRING) {
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) {
varname = GET_OP1_UNDEF_CV(varname, BP_VAR_R);
}
ZVAL_STR(&tmp, zval_get_string(varname));
varname = &tmp;
}
if (OP2_TYPE == IS_CONST) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
if (UNEXPECTED(ce == NULL)) {
ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op2)), EX_CONSTANT(opline->op2) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(ce == NULL)) {
if (EXPECTED(!EG(exception))) {
zend_throw_error(NULL, "Class '%s' not found", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
}
if (OP1_TYPE != IS_CONST && Z_TYPE(tmp) != IS_UNDEF) {
zend_string_release(Z_STR(tmp));
}
FREE_OP1();
HANDLE_EXCEPTION();
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce);
}
} else if (OP2_TYPE == IS_UNUSED) {
ce = zend_fetch_class(NULL, opline->op2.num);
} else {
ce = Z_CE_P(EX_VAR(opline->op2.var));
}
zend_std_unset_static_property(ce, Z_STR_P(varname));
if (OP1_TYPE != IS_CONST && Z_TYPE(tmp) != IS_UNDEF) {
zend_string_release(Z_STR(tmp));
@ -6358,14 +6475,13 @@ ZEND_VM_C_LABEL(fe_fetch_w_exit):
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED)
{
USE_OPLINE
zval *value;
int result;
if (OP1_TYPE == IS_CV &&
OP2_TYPE == IS_UNUSED &&
(opline->extended_value & ZEND_QUICK_SET)) {
value = EX_VAR(opline->op1.var);
if (opline->extended_value & ZEND_ISSET) {
@ -6386,6 +6502,7 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
} else {
zend_free_op free_op1;
zval tmp, *varname;
HashTable *target_symbol_table;
SAVE_OPLINE();
varname = GET_OP1_ZVAL_PTR(BP_VAR_IS);
@ -6395,56 +6512,14 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
varname = &tmp;
}
if (OP2_TYPE != IS_UNUSED) {
zend_class_entry *ce;
if (OP2_TYPE == IS_CONST) {
if (OP1_TYPE == IS_CONST && EXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)))) != NULL)) {
value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)) + sizeof(void*));
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
value = NULL;
}
ZEND_VM_C_GOTO(is_var_return);
} else if (UNEXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) == NULL)) {
ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op2)), EX_CONSTANT(opline->op2) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(ce == NULL)) {
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce);
}
} else {
ce = Z_CE_P(EX_VAR(opline->op2.var));
if (OP1_TYPE == IS_CONST &&
(value = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce)) != NULL) {
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
value = NULL;
}
ZEND_VM_C_GOTO(is_var_return);
}
}
value = zend_std_get_static_property(ce, Z_STR_P(varname), 1);
if (OP1_TYPE == IS_CONST && value) {
CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce, value);
}
} else {
HashTable *target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK);
value = zend_hash_find_ind(target_symbol_table, Z_STR_P(varname));
}
target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK);
value = zend_hash_find_ind(target_symbol_table, Z_STR_P(varname));
if (OP1_TYPE != IS_CONST && Z_TYPE(tmp) != IS_UNDEF) {
zend_string_release(Z_STR(tmp));
}
FREE_OP1();
ZEND_VM_C_LABEL(is_var_return):
if (opline->extended_value & ZEND_ISSET) {
result = value && Z_TYPE_P(value) > IS_NULL &&
(!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL);
@ -6458,6 +6533,82 @@ ZEND_VM_C_LABEL(is_var_return):
}
}
ZEND_VM_HANDLER(180, ZEND_ISSET_ISEMPTY_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
{
USE_OPLINE
zval *value;
int result;
zend_free_op free_op1;
zval tmp, *varname;
zend_class_entry *ce;
SAVE_OPLINE();
varname = GET_OP1_ZVAL_PTR(BP_VAR_IS);
ZVAL_UNDEF(&tmp);
if (OP1_TYPE != IS_CONST && Z_TYPE_P(varname) != IS_STRING) {
ZVAL_STR(&tmp, zval_get_string(varname));
varname = &tmp;
}
if (OP2_TYPE == IS_CONST) {
if (OP1_TYPE == IS_CONST && EXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)))) != NULL)) {
value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)) + sizeof(void*));
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
value = NULL;
}
ZEND_VM_C_GOTO(is_static_prop_return);
} else if (UNEXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) == NULL)) {
ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op2)), EX_CONSTANT(opline->op2) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(ce == NULL)) {
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce);
}
} else {
if (OP2_TYPE == IS_UNUSED) {
ce = zend_fetch_class(NULL, opline->op2.num);
} else {
ce = Z_CE_P(EX_VAR(opline->op2.var));
}
if (OP1_TYPE == IS_CONST &&
(value = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce)) != NULL) {
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
value = NULL;
}
ZEND_VM_C_GOTO(is_static_prop_return);
}
}
value = zend_std_get_static_property(ce, Z_STR_P(varname), 1);
if (OP1_TYPE == IS_CONST && value) {
CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce, value);
}
if (OP1_TYPE != IS_CONST && Z_TYPE(tmp) != IS_UNDEF) {
zend_string_release(Z_STR(tmp));
}
FREE_OP1();
ZEND_VM_C_LABEL(is_static_prop_return):
if (opline->extended_value & ZEND_ISSET) {
result = value && Z_TYPE_P(value) > IS_NULL &&
(!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL);
} else /* if (opline->extended_value & ZEND_ISEMPTY) */ {
result = !value || !i_zend_is_true(value);
}
ZEND_VM_SMART_BRANCH(result, 1);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMPVAR|UNUSED|CV, CONST|TMPVAR|CV)
{
USE_OPLINE
@ -6959,7 +7110,7 @@ ZEND_VM_HANDLER(105, ZEND_TICKS, ANY, ANY)
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(138, ZEND_INSTANCEOF, TMPVAR|CV, CONST|VAR)
ZEND_VM_HANDLER(138, ZEND_INSTANCEOF, TMPVAR|CV, UNUSED|CONST|VAR)
{
USE_OPLINE
zend_free_op free_op1;
@ -6984,6 +7135,8 @@ ZEND_VM_C_LABEL(try_instanceof):
}
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce);
}
} else if (OP2_TYPE == IS_UNUSED) {
ce = zend_fetch_class(NULL, opline->op2.num);
} else {
ce = Z_CE_P(EX_VAR(opline->op2.var));
}

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@
#include <stdio.h>
#include <zend.h>
const char *zend_vm_opcodes_map[173] = {
const char *zend_vm_opcodes_map[182] = {
"ZEND_NOP",
"ZEND_ADD",
"ZEND_SUB",
@ -195,6 +195,15 @@ const char *zend_vm_opcodes_map[173] = {
"ZEND_SPACESHIP",
"ZEND_DECLARE_ANON_CLASS",
"ZEND_DECLARE_ANON_INHERITED_CLASS",
"ZEND_FETCH_STATIC_PROP_R",
"ZEND_FETCH_STATIC_PROP_W",
"ZEND_FETCH_STATIC_PROP_RW",
"ZEND_FETCH_STATIC_PROP_IS",
"ZEND_FETCH_STATIC_PROP_FUNC_ARG",
"ZEND_FETCH_STATIC_PROP_UNSET",
"ZEND_UNSET_STATIC_PROP",
"ZEND_ISSET_ISEMPTY_STATIC_PROP",
"ZEND_FETCH_CLASS_CONSTANT",
};
ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) {

View File

@ -202,5 +202,14 @@ END_EXTERN_C()
#define ZEND_SPACESHIP 170
#define ZEND_DECLARE_ANON_CLASS 171
#define ZEND_DECLARE_ANON_INHERITED_CLASS 172
#define ZEND_FETCH_STATIC_PROP_R 173
#define ZEND_FETCH_STATIC_PROP_W 174
#define ZEND_FETCH_STATIC_PROP_RW 175
#define ZEND_FETCH_STATIC_PROP_IS 176
#define ZEND_FETCH_STATIC_PROP_FUNC_ARG 177
#define ZEND_FETCH_STATIC_PROP_UNSET 178
#define ZEND_UNSET_STATIC_PROP 179
#define ZEND_ISSET_ISEMPTY_STATIC_PROP 180
#define ZEND_FETCH_CLASS_CONSTANT 181
#endif

View File

@ -1091,13 +1091,15 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
VAR_SOURCE(opline->op1) &&
(VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT ||
VAR_SOURCE(opline->op1)->opcode == ZEND_ROPE_END ||
VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CONSTANT))) &&
VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CONSTANT ||
VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CLASS_CONSTANT))) &&
(opline->op2_type == IS_CONST ||
(opline->op2_type == IS_TMP_VAR &&
VAR_SOURCE(opline->op2) &&
(VAR_SOURCE(opline->op2)->opcode == ZEND_FAST_CONCAT ||
VAR_SOURCE(opline->op2)->opcode == ZEND_ROPE_END ||
VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CONSTANT)))) {
VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CONSTANT ||
VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CLASS_CONSTANT)))) {
opline->opcode = ZEND_FAST_CONCAT;
}
} else if (opline->opcode == ZEND_QM_ASSIGN &&
@ -1116,6 +1118,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
VAR_SOURCE(opline->op1)->opcode == ZEND_IS_IDENTICAL ||
VAR_SOURCE(opline->op1)->opcode == ZEND_IS_NOT_IDENTICAL ||
VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_VAR ||
VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_STATIC_PROP ||
VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ) &&
!zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var))) {
/* T = IS_SMALLER(X, Y), T1 = BOOL(T) => T = IS_SMALLER(X, Y), T1 = QM_ASSIGN(T) */
@ -1414,6 +1417,7 @@ static void zend_jmp_optimization(zend_code_block *block, zend_op_array *op_arra
if (src &&
src->opcode != ZEND_FETCH_R &&
src->opcode != ZEND_FETCH_STATIC_PROP_R &&
src->opcode != ZEND_FETCH_DIM_R &&
src->opcode != ZEND_FETCH_OBJ_R) {
ZEND_RESULT_TYPE(src) |= EXT_TYPE_UNUSED;

View File

@ -177,25 +177,24 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 1, 1, 2);
break;
case ZEND_FETCH_CONSTANT:
if (ZEND_OP1_TYPE(opline) == IS_UNUSED) {
if ((opline->extended_value & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 5);
} else {
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 3);
}
if ((opline->extended_value & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 5);
} else {
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
}
optimizer_literal_class_info(
info,
opline->op1_type,
opline->op1,
opline->op2.constant,
LITERAL_CLASS_CONST, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 1,
op_array);
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 3);
}
break;
case ZEND_FETCH_CLASS_CONSTANT:
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
}
optimizer_literal_class_info(
info,
opline->op1_type,
opline->op1,
opline->op2.constant,
LITERAL_CLASS_CONST, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 1,
op_array);
break;
case ZEND_FETCH_R:
case ZEND_FETCH_W:
case ZEND_FETCH_RW:
@ -204,23 +203,29 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_FETCH_FUNC_ARG:
case ZEND_UNSET_VAR:
case ZEND_ISSET_ISEMPTY_VAR:
if (ZEND_OP2_TYPE(opline) == IS_UNUSED) {
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
}
} else {
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
}
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
optimizer_literal_class_info(
info,
opline->op2_type,
opline->op2,
opline->op1.constant,
LITERAL_STATIC_PROPERTY, 2, 1,
op_array);
}
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
}
break;
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 (ZEND_OP2_TYPE(opline) == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
}
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
optimizer_literal_class_info(
info,
opline->op2_type,
opline->op2,
opline->op1.constant,
LITERAL_STATIC_PROPERTY, 2, 1,
op_array);
}
break;
case ZEND_FETCH_CLASS:

View File

@ -105,15 +105,24 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
call_stack[call].opline = NULL;
break;
case ZEND_FETCH_FUNC_ARG:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
case ZEND_FETCH_OBJ_FUNC_ARG:
case ZEND_FETCH_DIM_FUNC_ARG:
if (call_stack[call - 1].func) {
if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
opline->extended_value &= ZEND_FETCH_TYPE_MASK;
opline->opcode -= 9;
if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) {
opline->opcode -= 9;
} else {
opline->opcode = ZEND_FETCH_STATIC_PROP_W;
}
} else {
opline->extended_value &= ZEND_FETCH_TYPE_MASK;
opline->opcode -= 12;
if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) {
opline->opcode -= 12;
} else {
opline->opcode = ZEND_FETCH_STATIC_PROP_R;
}
}
}
break;

View File

@ -238,8 +238,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
#endif
case ZEND_FETCH_CONSTANT:
if (ZEND_OP1_TYPE(opline) == IS_UNUSED &&
ZEND_OP2_TYPE(opline) == IS_CONST &&
if (ZEND_OP2_TYPE(opline) == IS_CONST &&
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 &&
memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) {
@ -263,8 +262,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break;
}
if (ZEND_OP1_TYPE(opline) == IS_UNUSED &&
ZEND_OP2_TYPE(opline) == IS_CONST &&
if (ZEND_OP2_TYPE(opline) == IS_CONST &&
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
/* substitute persistent constants */
uint32_t tv = ZEND_RESULT(opline).var;
@ -283,10 +281,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
MAKE_NOP(opline);
}
}
break;
/* class constant */
if (ZEND_OP1_TYPE(opline) != IS_UNUSED &&
ZEND_OP2_TYPE(opline) == IS_CONST &&
case ZEND_FETCH_CLASS_CONSTANT:
if (ZEND_OP2_TYPE(opline) == IS_CONST &&
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
zend_class_entry *ce = NULL;
@ -308,6 +306,11 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break;
}
}
} else if (op_array->scope &&
ZEND_OP1_TYPE(opline) == IS_UNUSED &&
(opline->op1.num & ~ZEND_FETCH_CLASS_NO_AUTOLOAD) == ZEND_FETCH_CLASS_SELF) {
/* for self::B */
ce = op_array->scope;
} else if (op_array->scope &&
ZEND_OP1_TYPE(opline) == IS_VAR &&
(opline - 1)->opcode == ZEND_FETCH_CLASS &&

View File

@ -131,6 +131,7 @@ void zend_optimizer_update_op1_const(zend_op_array *op_array,
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);
@ -179,20 +180,20 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
if (Z_TYPE_P(val) == IS_STRING) {
zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
switch (opline->opcode) {
case ZEND_FETCH_R:
case ZEND_FETCH_W:
case ZEND_FETCH_RW:
case ZEND_FETCH_IS:
case ZEND_FETCH_UNSET:
case ZEND_FETCH_FUNC_ARG:
case ZEND_FETCH_CLASS:
case ZEND_INIT_FCALL_BY_NAME:
/*case ZEND_INIT_NS_FCALL_BY_NAME:*/
case ZEND_UNSET_VAR:
case ZEND_ISSET_ISEMPTY_VAR:
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:
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));
@ -213,7 +214,7 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1]));
/* break missing intentionally */
/*case ZEND_FETCH_CONSTANT:*/
/*case ZEND_FETCH_CLASS_CONSTANT:*/
case ZEND_ASSIGN_OBJ:
case ZEND_FETCH_OBJ_R:
case ZEND_FETCH_OBJ_W: