summaryrefslogtreecommitdiff
path: root/Zend/zend_API.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r--Zend/zend_API.c159
1 files changed, 143 insertions, 16 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 5f558c4930..abfbb411a5 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -1213,39 +1213,147 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */
}
/* }}} */
+static zend_class_mutable_data *zend_allocate_mutable_data(zend_class_entry *class_type) /* {{{ */
+{
+ zend_class_mutable_data *mutable_data;
+
+ ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_IMMUTABLE);
+ ZEND_ASSERT(ZEND_MAP_PTR(class_type->mutable_data) != NULL);
+ ZEND_ASSERT(ZEND_MAP_PTR_GET_IMM(class_type->mutable_data) == NULL);
+
+ mutable_data = zend_arena_alloc(&CG(arena), sizeof(zend_class_mutable_data));
+ memset(mutable_data, 0, sizeof(zend_class_mutable_data));
+ mutable_data->ce_flags = class_type->ce_flags;
+ ZEND_MAP_PTR_SET_IMM(class_type->mutable_data, mutable_data);
+
+ return mutable_data;
+}
+/* }}} */
+
+ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_type) /* {{{ */
+{
+ zend_class_mutable_data *mutable_data;
+ HashTable *constants_table;
+ zend_string *key;
+ zend_class_constant *new_c, *c;
+
+ constants_table = zend_arena_alloc(&CG(arena), sizeof(HashTable));
+ zend_hash_init(constants_table, zend_hash_num_elements(&class_type->constants_table), NULL, NULL, 0);
+ zend_hash_extend(constants_table, zend_hash_num_elements(&class_type->constants_table), 0);
+
+ ZEND_HASH_FOREACH_STR_KEY_PTR(&class_type->constants_table, key, c) {
+ if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
+ new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
+ memcpy(new_c, c, sizeof(zend_class_constant));
+ c = new_c;
+ }
+ _zend_hash_append_ptr(constants_table, key, c);
+ } ZEND_HASH_FOREACH_END();
+
+ ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_IMMUTABLE);
+ ZEND_ASSERT(ZEND_MAP_PTR(class_type->mutable_data) != NULL);
+
+ mutable_data = ZEND_MAP_PTR_GET_IMM(class_type->mutable_data);
+ if (!mutable_data) {
+ mutable_data = zend_allocate_mutable_data(class_type);
+ }
+
+ mutable_data->constants_table = constants_table;
+
+ return constants_table;
+}
+
ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /* {{{ */
{
- if (!(class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- zend_class_constant *c;
- zval *val;
- zend_property_info *prop_info;
+ zend_class_mutable_data *mutable_data = NULL;
+ zval *default_properties_table = NULL;
+ zval *static_members_table = NULL;
+ zend_class_constant *c;
+ zval *val;
+ zend_property_info *prop_info;
+ uint32_t ce_flags;
- if (class_type->parent) {
- if (UNEXPECTED(zend_update_class_constants(class_type->parent) != SUCCESS)) {
- return FAILURE;
+ ce_flags = class_type->ce_flags;
+
+ if (ce_flags & ZEND_ACC_CONSTANTS_UPDATED) {
+ return SUCCESS;
+ }
+
+ if (ce_flags & ZEND_ACC_IMMUTABLE) {
+ mutable_data = ZEND_MAP_PTR_GET_IMM(class_type->mutable_data);
+ if (mutable_data) {
+ ce_flags = mutable_data->ce_flags;
+ if (ce_flags & ZEND_ACC_CONSTANTS_UPDATED) {
+ return SUCCESS;
}
+ } else {
+ mutable_data = zend_allocate_mutable_data(class_type);
}
+ }
- ZEND_HASH_FOREACH_PTR(&class_type->constants_table, c) {
- val = &c->value;
- if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
+ if (class_type->parent) {
+ if (UNEXPECTED(zend_update_class_constants(class_type->parent) != SUCCESS)) {
+ return FAILURE;
+ }
+ }
+
+ if (ce_flags & ZEND_ACC_HAS_AST_CONSTANTS) {
+ HashTable *constants_table;
+
+ if (ce_flags & ZEND_ACC_IMMUTABLE) {
+ constants_table = mutable_data->constants_table;
+ if (!constants_table) {
+ constants_table = zend_separate_class_constants_table(class_type);
+ }
+ } else {
+ constants_table = &class_type->constants_table;
+ }
+ ZEND_HASH_FOREACH_PTR(constants_table, c) {
+ if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
+ val = &c->value;
if (UNEXPECTED(zval_update_constant_ex(val, c->ce) != SUCCESS)) {
return FAILURE;
}
}
} ZEND_HASH_FOREACH_END();
+ }
- if (class_type->default_static_members_count && !CE_STATIC_MEMBERS(class_type)) {
- if (class_type->type == ZEND_INTERNAL_CLASS || (class_type->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED))) {
+ if (class_type->default_static_members_count) {
+ static_members_table = CE_STATIC_MEMBERS(class_type);
+ if (!static_members_table) {
+ if (class_type->type == ZEND_INTERNAL_CLASS || (ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED))) {
zend_class_init_statics(class_type);
+ static_members_table = CE_STATIC_MEMBERS(class_type);
}
}
+ }
+
+ default_properties_table = class_type->default_properties_table;
+ if ((ce_flags & ZEND_ACC_IMMUTABLE)
+ && (ce_flags & ZEND_ACC_HAS_AST_PROPERTIES)) {
+ zval *src, *dst, *end;
+
+ default_properties_table = mutable_data->default_properties_table;
+ if (!default_properties_table) {
+ default_properties_table = zend_arena_alloc(&CG(arena), sizeof(zval) * class_type->default_properties_count);
+ src = class_type->default_properties_table;
+ dst = default_properties_table;
+ end = dst + class_type->default_properties_count;
+ do {
+ ZVAL_COPY_VALUE_PROP(dst, src);
+ src++;
+ dst++;
+ } while (dst != end);
+ mutable_data->default_properties_table = default_properties_table;
+ }
+ }
+ if (ce_flags & (ZEND_ACC_HAS_AST_PROPERTIES|ZEND_ACC_HAS_AST_STATICS)) {
ZEND_HASH_FOREACH_PTR(&class_type->properties_info, prop_info) {
if (prop_info->flags & ZEND_ACC_STATIC) {
- val = CE_STATIC_MEMBERS(class_type) + prop_info->offset;
+ val = static_members_table + prop_info->offset;
} else {
- val = (zval*)((char*)class_type->default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0));
+ val = (zval*)((char*)default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0));
}
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
if (ZEND_TYPE_IS_SET(prop_info->type)) {
@@ -1268,8 +1376,21 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /
}
}
} ZEND_HASH_FOREACH_END();
+ }
- class_type->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
+ ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
+ ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS;
+ ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES;
+ if (class_type->ce_flags & ZEND_ACC_IMMUTABLE) {
+ ce_flags &= ~ZEND_ACC_HAS_AST_STATICS;
+ if (mutable_data) {
+ mutable_data->ce_flags = ce_flags;
+ }
+ } else {
+ if (!(ce_flags & ZEND_ACC_PRELOADED)) {
+ ce_flags &= ~ZEND_ACC_HAS_AST_STATICS;
+ }
+ class_type->ce_flags = ce_flags;
}
return SUCCESS;
@@ -1279,7 +1400,7 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /
static zend_always_inline void _object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */
{
if (class_type->default_properties_count) {
- zval *src = class_type->default_properties_table;
+ zval *src = CE_DEFAULT_PROPERTIES_TABLE(class_type);
zval *dst = object->properties_table;
zval *end = src + class_type->default_properties_count;
@@ -3809,6 +3930,11 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
if (Z_TYPE_P(property) == IS_CONSTANT_AST) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+ if (access_type & ZEND_ACC_STATIC) {
+ ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
+ } else {
+ ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
+ }
}
}
@@ -4124,6 +4250,7 @@ ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *c
c->ce = ce;
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+ ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
}
if (!zend_hash_add_ptr(&ce->constants_table, name, c)) {