struct _zend_class_entry {
char type;
zend_string *name;
- zend_class_entry *parent;
+ union {
+ zend_class_entry *parent;
+ zend_string *parent_name;
+ };
int refcount;
uint32_t ce_flags;
if (extends_ast) {
znode extends_node;
- zend_string *extends_name;
+ zend_string *extends_name, *parent_name;
if (!zend_is_const_default_class_ref(extends_ast)) {
extends_name = zend_ast_get_str(extends_ast);
zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
}
extends_name = Z_STR(extends_node.u.constant);
- extends_const = zend_add_class_name_literal(CG(active_op_array),
- zend_resolve_class_name(extends_name,
- extends_ast->kind == ZEND_AST_ZVAL ? extends_ast->attr : ZEND_NAME_FQ));
+ parent_name = zend_resolve_class_name(extends_name,
+ extends_ast->kind == ZEND_AST_ZVAL ? extends_ast->attr : ZEND_NAME_FQ);
+ extends_const = zend_add_class_name_literal(CG(active_op_array), parent_name);
+ ce->parent_name = zend_string_copy(parent_name);
zend_string_release_ex(extends_name, 0);
- ce->ce_flags |= ZEND_ACC_INHERITED;
+ ce->ce_flags |= ZEND_ACC_INHERITED | ZEND_ACC_UNRESOLVED_PARENT;
}
opline = get_next_op(CG(active_op_array));
/* Class extends another class | | | */
#define ZEND_ACC_INHERITED (1 << 10) /* X | | | */
/* | | | */
+/* Class extends another class | | | */
+#define ZEND_ACC_UNRESOLVED_PARENT (1 << 11) /* X | | | */
+/* | | | */
/* Class implements interface(s) | | | */
#define ZEND_ACC_IMPLEMENT_INTERFACES (1 << 19) /* X | | | */
/* | | | */
}
}
+ if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+ zend_string_release_ex(ce->parent_name, 0);
+ ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_PARENT;
+ }
ce->parent = parent_ce;
/* Inherit interfaces */
}
switch (ce->type) {
case ZEND_USER_CLASS:
+ if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+ zend_string_release_ex(ce->parent_name, 0);
+ }
if (ce->default_properties_table) {
zval *p = ce->default_properties_table;
zval *end = p + ce->default_properties_count;
}
break;
case ZEND_FETCH_CLASS_PARENT:
- if (op_array->scope && op_array->scope->parent) {
+ if (op_array->scope && op_array->scope->parent && !(op_array->scope->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) {
UPDATE_SSA_OBJ_TYPE(op_array->scope->parent, 0, ssa_ops[i].result_def);
} else {
UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].result_def);
static uint32_t get_class_entry_rank(zend_class_entry *ce) {
uint32_t rank = 0;
- while (ce->parent) {
- rank++;
- ce = ce->parent;
+ if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) {
+ while (ce->parent) {
+ rank++;
+ ce = ce->parent;
+ }
}
return rank;
}
while (rank1 != rank2) {
if (rank1 > rank2) {
- ce1 = ce1->parent;
+ ce1 = (ce1->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce1->parent;
rank1--;
} else {
- ce2 = ce2->parent;
+ ce2 = (ce2->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce2->parent;
rank2--;
}
}
while (ce1 != ce2) {
- ce1 = ce1->parent;
- ce2 = ce2->parent;
+ ce1 = (ce1->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce1->parent;
+ ce2 = (ce2->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce2->parent;
}
if (ce1) {
*pce = ce = ARENA_REALLOC(old_ce);
ce->refcount = 1;
- if (ce->parent) {
+ if (ce->parent && !(ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) {
ce->parent = ARENA_REALLOC(ce->parent);
}
/* static members */
if (old_ce->default_static_members_table) {
int i, end;
- zend_class_entry *parent = ce->parent;
+ zend_class_entry *parent = (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce->parent;
ce->default_static_members_table = emalloc(sizeof(zval) * old_ce->default_static_members_count);
i = ce->default_static_members_count - 1;
void *buf)
{
zend_class_entry *ce;
+ zend_class_entry *parent = NULL;
SERIALIZE_PTR(Z_PTR_P(zv));
ce = Z_PTR_P(zv);
UNSERIALIZE_PTR(ce);
SERIALIZE_STR(ce->name);
+ if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+ SERIALIZE_STR(ce->parent_name);
+ } else {
+ parent = ce->parent;
+ SERIALIZE_PTR(ce->parent);
+ }
zend_file_cache_serialize_hash(&ce->function_table, script, info, buf, zend_file_cache_serialize_func);
if (ce->default_properties_table) {
zval *p, *end;
/* Serialize only static properties in this class.
* Static properties from parent classes will be handled in class_copy_ctor */
- p = table + (ce->parent ? ce->parent->default_static_members_count : 0);
+ p = table + (parent ? parent->default_static_members_count : 0);
end = table + ce->default_static_members_count;
while (p < end) {
zend_file_cache_serialize_zval(p, script, info, buf);
}
}
- SERIALIZE_PTR(ce->parent);
SERIALIZE_PTR(ce->constructor);
SERIALIZE_PTR(ce->destructor);
SERIALIZE_PTR(ce->clone);
void *buf)
{
zend_class_entry *ce;
+ zend_class_entry *parent = NULL;
UNSERIALIZE_PTR(Z_PTR_P(zv));
ce = Z_PTR_P(zv);
UNSERIALIZE_STR(ce->name);
- UNSERIALIZE_PTR(ce->parent);
+ if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+ UNSERIALIZE_STR(ce->parent_name);
+ } else {
+ UNSERIALIZE_PTR(ce->parent);
+ parent = ce->parent;
+ }
zend_file_cache_unserialize_hash(&ce->function_table,
script, buf, zend_file_cache_unserialize_func, ZEND_FUNCTION_DTOR);
if (ce->default_properties_table) {
* Static properties from parent classes will be handled in class_copy_ctor */
UNSERIALIZE_PTR(ce->default_static_members_table);
table = ce->default_static_members_table;
- p = table + (ce->parent ? ce->parent->default_static_members_count : 0);
+ p = table + (parent ? parent->default_static_members_count : 0);
end = table + ce->default_static_members_count;
while (p < end) {
zend_file_cache_unserialize_zval(p, script, buf);
ce = Z_PTR_P(zv) = ZCG(arena_mem);
ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_class_entry)));
zend_accel_store_interned_string(ce->name);
+ if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+ zend_accel_store_interned_string(ce->parent_name);
+ }
zend_hash_persist(&ce->function_table, zend_persist_class_method);
if (ce->default_properties_table) {
int i;
/* Persist only static properties in this class.
* Static properties from parent classes will be handled in class_copy_ctor */
- i = ce->parent ? ce->parent->default_static_members_count : 0;
+ i = (ce->parent && !(ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) ? ce->parent->default_static_members_count : 0;
for (; i < ce->default_static_members_count; i++) {
zend_persist_zval(&ce->default_static_members_table[i]);
}
{
zend_class_entry *ce = Z_PTR_P(zv);
- if (ce->parent) {
+ if (ce->parent && !(ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) {
ce->parent = zend_shared_alloc_get_xlat_entry(ce->parent);
}
if (ce->type == ZEND_USER_CLASS) {
ADD_ARENA_SIZE(sizeof(zend_class_entry));
ADD_INTERNED_STRING(ce->name, 0);
+ if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+ ADD_INTERNED_STRING(ce->parent_name, 0);
+ }
zend_hash_persist_calc(&ce->function_table, zend_persist_class_method_calc);
if (ce->default_properties_table) {
int i;