Fixed issues related to optimization and persitence of classes linked with interfaces, traits or internal classes.

This commit is contained in:
Dmitry Stogov 2018-11-14 16:32:07 +03:00
parent 53ea09e84d
commit ba99aa133c
6 changed files with 93 additions and 24 deletions

View file

@ -260,7 +260,7 @@ typedef struct _zend_oparray_context {
/* User class has methods with static variables | | | */ /* User class has methods with static variables | | | */
#define ZEND_HAS_STATIC_IN_METHODS (1 << 15) /* X | | | */ #define ZEND_HAS_STATIC_IN_METHODS (1 << 15) /* X | | | */
/* | | | */ /* | | | */
/* Function Flags (unused: 26...30) | | | */ /* Function Flags (unused: 27...30) | | | */
/* ============== | | | */ /* ============== | | | */
/* | | | */ /* | | | */
/* deprecation flag | | | */ /* deprecation flag | | | */
@ -310,6 +310,9 @@ typedef struct _zend_oparray_context {
/* internal function is allocated at arena (int only) | | | */ /* internal function is allocated at arena (int only) | | | */
#define ZEND_ACC_ARENA_ALLOCATED (1 << 25) /* | X | | */ #define ZEND_ACC_ARENA_ALLOCATED (1 << 25) /* | X | | */
/* | | | */ /* | | | */
/* op_array is a clone of trait method | | | */
#define ZEND_ACC_TRAIT_CLONE (1 << 26) /* | X | | */
/* | | | */
/* op_array uses strict mode types | | | */ /* op_array uses strict mode types | | | */
#define ZEND_ACC_STRICT_TYPES (1 << 31) /* | X | | */ #define ZEND_ACC_STRICT_TYPES (1 << 31) /* | X | | */

View file

@ -1308,6 +1308,7 @@ static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_s
} else { } else {
new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
memcpy(new_fn, fn, sizeof(zend_op_array)); memcpy(new_fn, fn, sizeof(zend_op_array));
new_fn->op_array.fn_flags |= ZEND_ACC_TRAIT_CLONE;
new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE; new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
} }
function_add_ref(new_fn); function_add_ref(new_fn);

View file

@ -95,6 +95,8 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
{ {
if (func->type == ZEND_USER_FUNCTION if (func->type == ZEND_USER_FUNCTION
&& !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS)) && !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS))
/* TODO: function copied from trait may be inconsistent ??? */
&& !(func->op_array.fn_flags & (ZEND_ACC_TRAIT_CLONE))
&& fcall->extended_value >= func->op_array.required_num_args && fcall->extended_value >= func->op_array.required_num_args
&& func->op_array.opcodes[func->op_array.num_args].opcode == ZEND_RETURN) { && func->op_array.opcodes[func->op_array.num_args].opcode == ZEND_RETURN) {

View file

@ -53,6 +53,7 @@ static int zend_op_array_collect(zend_call_graph *call_graph, zend_op_array *op_
static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *script, zend_op_array_func_t func) static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *script, zend_op_array_func_t func)
{ {
zend_class_entry *ce; zend_class_entry *ce;
zend_string *key;
zend_op_array *op_array; zend_op_array *op_array;
if (func(call_graph, &script->main_op_array) != SUCCESS) { if (func(call_graph, &script->main_op_array) != SUCCESS) {
@ -65,9 +66,12 @@ static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *scrip
} }
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) { ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
if (op_array->scope == ce) { if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
if (func(call_graph, op_array) != SUCCESS) { if (func(call_graph, op_array) != SUCCESS) {
return FAILURE; return FAILURE;
} }

View file

@ -1421,6 +1421,7 @@ static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level) int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level)
{ {
zend_class_entry *ce; zend_class_entry *ce;
zend_string *key;
zend_op_array *op_array; zend_op_array *op_array;
zend_string *name; zend_string *name;
zend_optimizer_ctx ctx; zend_optimizer_ctx ctx;
@ -1440,9 +1441,12 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
zend_optimize_op_array(op_array, &ctx); zend_optimize_op_array(op_array, &ctx);
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) { ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
if (op_array->scope == ce) { if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
zend_optimize_op_array(op_array, &ctx); zend_optimize_op_array(op_array, &ctx);
} }
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
@ -1544,16 +1548,22 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
zend_adjust_fcall_stack_size(op_array, &ctx); zend_adjust_fcall_stack_size(op_array, &ctx);
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) { ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
if (op_array->scope == ce) { if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
zend_adjust_fcall_stack_size(op_array, &ctx); zend_adjust_fcall_stack_size(op_array, &ctx);
} }
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
} }
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) { ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
if (op_array->scope != ce && op_array->type == ZEND_USER_FUNCTION) { if (op_array->scope != ce && op_array->type == ZEND_USER_FUNCTION) {
zend_op_array *orig_op_array = zend_op_array *orig_op_array =
@ -1561,10 +1571,12 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
ZEND_ASSERT(orig_op_array != NULL); ZEND_ASSERT(orig_op_array != NULL);
if (orig_op_array != op_array) { if (orig_op_array != op_array) {
uint32_t fn_flags = op_array->fn_flags;
zend_function *prototype = op_array->prototype; zend_function *prototype = op_array->prototype;
HashTable *ht = op_array->static_variables; HashTable *ht = op_array->static_variables;
*op_array = *orig_op_array; *op_array = *orig_op_array;
op_array->fn_flags = fn_flags;
op_array->prototype = prototype; op_array->prototype = prototype;
op_array->static_variables = ht; op_array->static_variables = ht;
} }
@ -1582,7 +1594,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) { ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
if (op_array->scope == ce) { if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
zend_dump_op_array(op_array, ZEND_DUMP_RT_CONSTANTS, "after optimizer", NULL); zend_dump_op_array(op_array, ZEND_DUMP_RT_CONSTANTS, "after optimizer", NULL);
} }
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();

View file

@ -719,6 +719,7 @@ static void zend_persist_class_method(zval *zv)
static void zend_persist_property_info(zval *zv) static void zend_persist_property_info(zval *zv)
{ {
zend_property_info *prop = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv)); zend_property_info *prop = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv));
zend_class_entry *ce;
if (prop) { if (prop) {
Z_PTR_P(zv) = prop; Z_PTR_P(zv) = prop;
@ -729,7 +730,10 @@ static void zend_persist_property_info(zval *zv)
} else { } else {
prop = Z_PTR_P(zv) = zend_shared_memdup_arena_put(Z_PTR_P(zv), sizeof(zend_property_info)); prop = Z_PTR_P(zv) = zend_shared_memdup_arena_put(Z_PTR_P(zv), sizeof(zend_property_info));
} }
prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce); ce = zend_shared_alloc_get_xlat_entry(prop->ce);
if (ce) {
prop->ce = ce;
}
zend_accel_store_interned_string(prop->name); zend_accel_store_interned_string(prop->name);
if (prop->doc_comment) { if (prop->doc_comment) {
if (ZCG(accel_directives).save_comments) { if (ZCG(accel_directives).save_comments) {
@ -747,6 +751,7 @@ static void zend_persist_property_info(zval *zv)
static void zend_persist_class_constant(zval *zv) static void zend_persist_class_constant(zval *zv)
{ {
zend_class_constant *c = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv)); zend_class_constant *c = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv));
zend_class_entry *ce;
if (c) { if (c) {
Z_PTR_P(zv) = c; Z_PTR_P(zv) = c;
@ -758,7 +763,10 @@ static void zend_persist_class_constant(zval *zv)
c = Z_PTR_P(zv) = zend_shared_memdup_arena_put(Z_PTR_P(zv), sizeof(zend_class_constant)); c = Z_PTR_P(zv) = zend_shared_memdup_arena_put(Z_PTR_P(zv), sizeof(zend_class_constant));
} }
zend_persist_zval(&c->value); zend_persist_zval(&c->value);
c->ce = zend_shared_alloc_get_xlat_entry(c->ce); ce = zend_shared_alloc_get_xlat_entry(c->ce);
if (ce) {
c->ce = ce;
}
if (c->doc_comment) { if (c->doc_comment) {
if (ZCG(accel_directives).save_comments) { if (ZCG(accel_directives).save_comments) {
zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment); zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
@ -982,43 +990,82 @@ static int zend_update_parent_ce(zval *zv)
/* update methods */ /* update methods */
if (ce->constructor) { if (ce->constructor) {
ce->constructor = zend_shared_alloc_get_xlat_entry(ce->constructor); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->constructor);
if (tmp != NULL) {
ce->constructor = tmp;
}
} }
if (ce->destructor) { if (ce->destructor) {
ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->destructor);
if (tmp != NULL) {
ce->destructor = tmp;
}
} }
if (ce->clone) { if (ce->clone) {
ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->clone);
if (tmp != NULL) {
ce->clone = tmp;
}
} }
if (ce->__get) { if (ce->__get) {
ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__get);
if (tmp != NULL) {
ce->__get = tmp;
}
} }
if (ce->__set) { if (ce->__set) {
ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__set);
if (tmp != NULL) {
ce->__set = tmp;
}
} }
if (ce->__call) { if (ce->__call) {
ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__call);
if (tmp != NULL) {
ce->__call = tmp;
}
} }
if (ce->serialize_func) { if (ce->serialize_func) {
ce->serialize_func = zend_shared_alloc_get_xlat_entry(ce->serialize_func); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->serialize_func);
if (tmp != NULL) {
ce->serialize_func = tmp;
}
} }
if (ce->unserialize_func) { if (ce->unserialize_func) {
ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->unserialize_func);
if (tmp != NULL) {
ce->unserialize_func = tmp;
}
} }
if (ce->__isset) { if (ce->__isset) {
ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__isset);
if (tmp != NULL) {
ce->__isset = tmp;
}
} }
if (ce->__unset) { if (ce->__unset) {
ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__unset);
if (tmp != NULL) {
ce->__unset = tmp;
}
} }
if (ce->__tostring) { if (ce->__tostring) {
ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__tostring);
if (tmp != NULL) {
ce->__tostring = tmp;
}
} }
if (ce->__callstatic) { if (ce->__callstatic) {
ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
if (tmp != NULL) {
ce->__callstatic = tmp;
}
} }
if (ce->__debugInfo) { if (ce->__debugInfo) {
ce->__debugInfo = zend_shared_alloc_get_xlat_entry(ce->__debugInfo); zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__debugInfo);
if (tmp != NULL) {
ce->__debugInfo = tmp;
}
} }
// zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce); // zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce);
return 0; return 0;