mirror of
https://github.com/php/php-src.git
synced 2024-11-28 04:14:26 +08:00
Add preloading support for typed properties
During preloading, try to resolve all property types to CEs. Add a flag that tracks this. If not all property types can be resolved, then the class is not eligible for preloading.
This commit is contained in:
parent
a2e9534798
commit
c15007956d
@ -212,7 +212,7 @@ typedef struct _zend_oparray_context {
|
|||||||
/* Final class or method | | | */
|
/* Final class or method | | | */
|
||||||
#define ZEND_ACC_FINAL (1 << 5) /* X | X | | */
|
#define ZEND_ACC_FINAL (1 << 5) /* X | X | | */
|
||||||
/* | | | */
|
/* | | | */
|
||||||
/* Abstarct method | | | */
|
/* Abstract method | | | */
|
||||||
#define ZEND_ACC_ABSTRACT (1 << 6) /* X | X | | */
|
#define ZEND_ACC_ABSTRACT (1 << 6) /* X | X | | */
|
||||||
#define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS (1 << 6) /* X | | | */
|
#define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS (1 << 6) /* X | | | */
|
||||||
/* | | | */
|
/* | | | */
|
||||||
@ -260,6 +260,9 @@ 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 | | | */
|
||||||
/* | | | */
|
/* | | | */
|
||||||
|
/* Whether all property types are resolved to CEs | | | */
|
||||||
|
#define ZEND_ACC_PROPERTY_TYPES_RESOLVED (1 << 16) /* X | | | */
|
||||||
|
/* | | | */
|
||||||
/* Function Flags (unused: 28...30) | | | */
|
/* Function Flags (unused: 28...30) | | | */
|
||||||
/* ============== | | | */
|
/* ============== | | | */
|
||||||
/* | | | */
|
/* | | | */
|
||||||
|
@ -3408,6 +3408,42 @@ static void preload_link(void)
|
|||||||
} while (changed);
|
} while (changed);
|
||||||
EG(exception) = NULL;
|
EG(exception) = NULL;
|
||||||
|
|
||||||
|
/* Resolve property types */
|
||||||
|
ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
|
||||||
|
ce = Z_PTR_P(zv);
|
||||||
|
if (ce->type == ZEND_INTERNAL_CLASS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((ce->ce_flags & ZEND_ACC_LINKED)
|
||||||
|
&& !(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
|
||||||
|
zend_bool ok = 1;
|
||||||
|
zend_property_info *prop;
|
||||||
|
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
|
||||||
|
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
||||||
|
zend_string *name, *lcname;
|
||||||
|
if (!ZEND_TYPE_IS_NAME(prop->type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = ZEND_TYPE_NAME(prop->type);
|
||||||
|
lcname = zend_string_tolower(name);
|
||||||
|
p = zend_hash_find_ptr(EG(class_table), lcname);
|
||||||
|
zend_string_release(lcname);
|
||||||
|
if (!p) {
|
||||||
|
ok = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
zend_string_release(name);
|
||||||
|
prop->type = ZEND_TYPE_ENCODE_CE(p, ZEND_TYPE_ALLOW_NULL(prop->type));
|
||||||
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
|
||||||
/* Move unlinked clases (and with unresilved constants) back to scripts */
|
/* Move unlinked clases (and with unresilved constants) back to scripts */
|
||||||
orig_dtor = EG(class_table)->pDestructor;
|
orig_dtor = EG(class_table)->pDestructor;
|
||||||
EG(class_table)->pDestructor = NULL;
|
EG(class_table)->pDestructor = NULL;
|
||||||
@ -3420,6 +3456,8 @@ static void preload_link(void)
|
|||||||
zend_error(E_WARNING, "Can't preload unlinked class %s at %s:%d\n", ZSTR_VAL(ce->name), ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start);
|
zend_error(E_WARNING, "Can't preload unlinked class %s at %s:%d\n", ZSTR_VAL(ce->name), ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start);
|
||||||
} else if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
|
} else if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
|
||||||
zend_error(E_WARNING, "Can't preload class %s with unresolved constants at %s:%d\n", ZSTR_VAL(ce->name), ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start);
|
zend_error(E_WARNING, "Can't preload class %s with unresolved constants at %s:%d\n", ZSTR_VAL(ce->name), ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start);
|
||||||
|
} else if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
|
||||||
|
zend_error(E_WARNING, "Can't preload class %s with unresolved property types at %s:%d\n", ZSTR_VAL(ce->name), ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start);
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -40,4 +40,5 @@ class Y {
|
|||||||
|
|
||||||
class Z {
|
class Z {
|
||||||
public $foo;
|
public $foo;
|
||||||
|
public a $bar;
|
||||||
}
|
}
|
||||||
|
@ -745,10 +745,6 @@ static void zend_persist_property_info(zval *zv)
|
|||||||
zend_string *class_name = ZEND_TYPE_NAME(prop->type);
|
zend_string *class_name = ZEND_TYPE_NAME(prop->type);
|
||||||
zend_accel_store_interned_string(class_name);
|
zend_accel_store_interned_string(class_name);
|
||||||
prop->type = ZEND_TYPE_ENCODE_CLASS(class_name, ZEND_TYPE_ALLOW_NULL(prop->type));
|
prop->type = ZEND_TYPE_ENCODE_CLASS(class_name, ZEND_TYPE_ALLOW_NULL(prop->type));
|
||||||
} else if (ZEND_TYPE_IS_CE(prop->type)) {
|
|
||||||
zend_class_entry *ce = ZEND_TYPE_CE(prop->type);
|
|
||||||
ce = zend_shared_alloc_get_xlat_entry(ce);
|
|
||||||
prop->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop->type));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,16 +786,6 @@ static void zend_persist_class_constant(zval *zv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static zend_bool has_unresolved_property_types(zend_class_entry *ce) {
|
|
||||||
zend_property_info *prop;
|
|
||||||
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
|
||||||
if (ZEND_TYPE_IS_NAME(prop->type)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} ZEND_HASH_FOREACH_END();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void zend_persist_class_entry(zval *zv)
|
static void zend_persist_class_entry(zval *zv)
|
||||||
{
|
{
|
||||||
zend_class_entry *ce = Z_PTR_P(zv);
|
zend_class_entry *ce = Z_PTR_P(zv);
|
||||||
@ -807,7 +793,7 @@ static void zend_persist_class_entry(zval *zv)
|
|||||||
if (ce->type == ZEND_USER_CLASS) {
|
if (ce->type == ZEND_USER_CLASS) {
|
||||||
if ((ce->ce_flags & ZEND_ACC_LINKED)
|
if ((ce->ce_flags & ZEND_ACC_LINKED)
|
||||||
&& (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)
|
&& (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)
|
||||||
&& !has_unresolved_property_types(ce)
|
&& (ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)
|
||||||
&& !ZCG(current_persistent_script)->corrupted) {
|
&& !ZCG(current_persistent_script)->corrupted) {
|
||||||
ZCG(is_immutable_class) = 1;
|
ZCG(is_immutable_class) = 1;
|
||||||
ce = Z_PTR_P(zv) = zend_shared_memdup_put(ce, sizeof(zend_class_entry));
|
ce = Z_PTR_P(zv) = zend_shared_memdup_put(ce, sizeof(zend_class_entry));
|
||||||
@ -953,14 +939,6 @@ static void zend_persist_class_entry(zval *zv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//static int zend_update_property_info_ce(zval *zv)
|
|
||||||
//{
|
|
||||||
// zend_property_info *prop = Z_PTR_P(zv);
|
|
||||||
//
|
|
||||||
// prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce);
|
|
||||||
// return 0;
|
|
||||||
//}
|
|
||||||
|
|
||||||
static void zend_update_parent_ce(zend_class_entry *ce)
|
static void zend_update_parent_ce(zend_class_entry *ce)
|
||||||
{
|
{
|
||||||
if (ce->ce_flags & ZEND_ACC_LINKED) {
|
if (ce->ce_flags & ZEND_ACC_LINKED) {
|
||||||
@ -1018,6 +996,20 @@ static void zend_update_parent_ce(zend_class_entry *ce)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
|
||||||
|
zend_property_info *prop;
|
||||||
|
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
||||||
|
if (ZEND_TYPE_IS_CE(prop->type)) {
|
||||||
|
zend_class_entry *ce = ZEND_TYPE_CE(prop->type);
|
||||||
|
if (ce->type == ZEND_USER_CLASS) {
|
||||||
|
ce = zend_shared_alloc_get_xlat_entry(ce);
|
||||||
|
ZEND_ASSERT(ce);
|
||||||
|
prop->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop->type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
}
|
||||||
|
|
||||||
/* update methods */
|
/* update methods */
|
||||||
if (ce->constructor) {
|
if (ce->constructor) {
|
||||||
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->constructor);
|
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->constructor);
|
||||||
|
@ -331,14 +331,21 @@ static void zend_persist_class_constant_calc(zval *zv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static zend_bool has_unresolved_property_types(zend_class_entry *ce) {
|
static void check_property_type_resolution(zend_class_entry *ce) {
|
||||||
zend_property_info *prop;
|
zend_property_info *prop;
|
||||||
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
if (ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED) {
|
||||||
if (ZEND_TYPE_IS_NAME(prop->type)) {
|
/* Preloading might have computed this already. */
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
} ZEND_HASH_FOREACH_END();
|
|
||||||
return 0;
|
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
|
||||||
|
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
||||||
|
if (ZEND_TYPE_IS_NAME(prop->type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
}
|
||||||
|
ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zend_persist_class_entry_calc(zval *zv)
|
static void zend_persist_class_entry_calc(zval *zv)
|
||||||
@ -346,10 +353,12 @@ static void zend_persist_class_entry_calc(zval *zv)
|
|||||||
zend_class_entry *ce = Z_PTR_P(zv);
|
zend_class_entry *ce = Z_PTR_P(zv);
|
||||||
|
|
||||||
if (ce->type == ZEND_USER_CLASS) {
|
if (ce->type == ZEND_USER_CLASS) {
|
||||||
|
check_property_type_resolution(ce);
|
||||||
|
|
||||||
ZCG(is_immutable_class) =
|
ZCG(is_immutable_class) =
|
||||||
(ce->ce_flags & ZEND_ACC_LINKED) &&
|
(ce->ce_flags & ZEND_ACC_LINKED) &&
|
||||||
(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) &&
|
(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) &&
|
||||||
!has_unresolved_property_types(ce) &&
|
(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED) &&
|
||||||
!ZCG(current_persistent_script)->corrupted;
|
!ZCG(current_persistent_script)->corrupted;
|
||||||
|
|
||||||
ADD_SIZE_EX(sizeof(zend_class_entry));
|
ADD_SIZE_EX(sizeof(zend_class_entry));
|
||||||
|
Loading…
Reference in New Issue
Block a user