diff options
Diffstat (limited to 'Zend/zend_opcode.c')
-rw-r--r-- | Zend/zend_opcode.c | 162 |
1 files changed, 124 insertions, 38 deletions
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 6681ef7b68..4e30b9ff7a 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -77,7 +77,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->last_live_range = 0; op_array->static_variables = NULL; - ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables); + ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL); op_array->last_try_catch = 0; op_array->fn_flags = 0; @@ -85,6 +85,9 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->last_literal = 0; op_array->literals = NULL; + op_array->num_dynamic_func_defs = 0; + op_array->dynamic_func_defs = NULL; + ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL); op_array->cache_size = zend_op_array_extension_handles * sizeof(void*); @@ -103,7 +106,7 @@ ZEND_API void destroy_zend_function(zend_function *function) zend_function_dtor(&tmp); } -ZEND_API void zend_type_release(zend_type type, zend_bool persistent) { +ZEND_API void zend_type_release(zend_type type, bool persistent) { if (ZEND_TYPE_HAS_LIST(type)) { zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) { @@ -163,7 +166,7 @@ ZEND_API void zend_function_dtor(zval *zv) ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce) { - if (CE_STATIC_MEMBERS(ce)) { + if (ZEND_MAP_PTR(ce->static_members_table) && CE_STATIC_MEMBERS(ce)) { zval *static_members = CE_STATIC_MEMBERS(ce); zval *p = static_members; zval *end = p + ce->default_static_members_count; @@ -255,18 +258,76 @@ static void _destroy_zend_class_traits_info(zend_class_entry *ce) } } +ZEND_API void zend_cleanup_mutable_class_data(zend_class_entry *ce) +{ + zend_class_mutable_data *mutable_data = ZEND_MAP_PTR_GET_IMM(ce->mutable_data); + + if (mutable_data) { + HashTable *constants_table; + zval *p; + + constants_table = mutable_data->constants_table; + if (constants_table && constants_table != &ce->constants_table) { + zend_class_constant *c; + + ZEND_HASH_FOREACH_PTR(constants_table, c) { + zval_ptr_dtor_nogc(&c->value); + } ZEND_HASH_FOREACH_END(); + zend_hash_destroy(constants_table); + mutable_data->constants_table = NULL; + } + + p = mutable_data->default_properties_table; + if (p && p != ce->default_properties_table) { + zval *end = p + ce->default_properties_count; + + while (p < end) { + zval_ptr_dtor_nogc(p); + p++; + } + mutable_data->default_properties_table = NULL; + } + + ZEND_MAP_PTR_SET_IMM(ce->mutable_data, NULL); + } +} + ZEND_API void destroy_zend_class(zval *zv) { zend_property_info *prop_info; zend_class_entry *ce = Z_PTR_P(zv); zend_function *fn; - if (ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED)) { + if (ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED|ZEND_ACC_FILE_CACHED)) { zend_op_array *op_array; if (ce->default_static_members_count) { zend_cleanup_internal_class_data(ce); } + + if (!(ce->ce_flags & ZEND_ACC_FILE_CACHED)) { + if (ZEND_MAP_PTR(ce->mutable_data) && ZEND_MAP_PTR_GET_IMM(ce->mutable_data)) { + zend_cleanup_mutable_class_data(ce); + } + } else { + zend_class_constant *c; + zval *p, *end; + + ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) { + if (c->ce == ce) { + zval_ptr_dtor_nogc(&c->value); + } + } ZEND_HASH_FOREACH_END(); + + p = ce->default_properties_table; + end = p + ce->default_properties_count; + + while (p < end) { + zval_ptr_dtor_nogc(p); + p++; + } + } + if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) { ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) { if (op_array->type == ZEND_USER_FUNCTION) { @@ -280,9 +341,37 @@ ZEND_API void destroy_zend_class(zval *zv) } switch (ce->type) { case ZEND_USER_CLASS: - if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_RESOLVED_PARENT)) { - zend_string_release_ex(ce->parent_name, 0); + if (!(ce->ce_flags & ZEND_ACC_CACHED)) { + if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_RESOLVED_PARENT)) { + zend_string_release_ex(ce->parent_name, 0); + } + + zend_string_release_ex(ce->name, 0); + zend_string_release_ex(ce->info.user.filename, 0); + + if (ce->info.user.doc_comment) { + zend_string_release_ex(ce->info.user.doc_comment, 0); + } + + if (ce->attributes) { + zend_hash_release(ce->attributes); + } + + if (ce->num_interfaces > 0 && !(ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) { + uint32_t i; + + for (i = 0; i < ce->num_interfaces; i++) { + zend_string_release_ex(ce->interface_names[i].name, 0); + zend_string_release_ex(ce->interface_names[i].lc_name, 0); + } + efree(ce->interface_names); + } + + if (ce->num_traits > 0) { + _destroy_zend_class_traits_info(ce); + } } + if (ce->default_properties_table) { zval *p = ce->default_properties_table; zval *end = p + ce->default_properties_count; @@ -325,7 +414,6 @@ ZEND_API void destroy_zend_class(zval *zv) } } ZEND_HASH_FOREACH_END(); zend_hash_destroy(&ce->properties_info); - zend_string_release_ex(ce->name, 0); zend_hash_destroy(&ce->function_table); if (zend_hash_num_elements(&ce->constants_table)) { zend_class_constant *c; @@ -343,29 +431,9 @@ ZEND_API void destroy_zend_class(zval *zv) } ZEND_HASH_FOREACH_END(); } zend_hash_destroy(&ce->constants_table); - if (ce->num_interfaces > 0) { - if (!(ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) { - uint32_t i; - - for (i = 0; i < ce->num_interfaces; i++) { - zend_string_release_ex(ce->interface_names[i].name, 0); - zend_string_release_ex(ce->interface_names[i].lc_name, 0); - } - } + if (ce->num_interfaces > 0 && (ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) { efree(ce->interfaces); } - zend_string_release_ex(ce->info.user.filename, 0); - if (ce->info.user.doc_comment) { - zend_string_release_ex(ce->info.user.doc_comment, 0); - } - if (ce->attributes) { - zend_hash_release(ce->attributes); - } - - if (ce->num_traits > 0) { - _destroy_zend_class_traits_info(ce); - } - break; case ZEND_INTERNAL_CLASS: if (ce->default_properties_table) { @@ -446,18 +514,20 @@ void zend_class_add_ref(zval *zv) } } -ZEND_API void destroy_op_array(zend_op_array *op_array) +ZEND_API void zend_destroy_static_vars(zend_op_array *op_array) { - uint32_t i; - - if (op_array->static_variables) { + if (ZEND_MAP_PTR(op_array->static_variables_ptr)) { HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr); - if (ht && !(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { - if (GC_DELREF(ht) == 0) { - zend_array_destroy(ht); - } + if (ht) { + zend_array_destroy(ht); + ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL); } } +} + +ZEND_API void destroy_op_array(zend_op_array *op_array) +{ + uint32_t i; if ((op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE) && ZEND_MAP_PTR(op_array->run_time_cache)) { @@ -534,6 +604,22 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) } efree(arg_info); } + if (op_array->static_variables) { + zend_array_destroy(op_array->static_variables); + } + if (op_array->num_dynamic_func_defs) { + for (i = 0; i < op_array->num_dynamic_func_defs; i++) { + /* Closures overwrite static_variables in their copy. + * Make sure to destroy them when the prototype function is destroyed. */ + if (op_array->dynamic_func_defs[i]->static_variables + && (op_array->dynamic_func_defs[i]->fn_flags & ZEND_ACC_CLOSURE)) { + zend_array_destroy(op_array->dynamic_func_defs[i]->static_variables); + op_array->dynamic_func_defs[i]->static_variables = NULL; + } + destroy_op_array(op_array->dynamic_func_defs[i]); + } + efree(op_array->dynamic_func_defs); + } } static void zend_update_extended_stmts(zend_op_array *op_array) @@ -754,14 +840,14 @@ static void emit_live_range( emit_live_range_raw(op_array, var_num, kind, start, end); } -static zend_bool is_fake_def(zend_op *opline) { +static bool is_fake_def(zend_op *opline) { /* These opcodes only modify the result, not create it. */ return opline->opcode == ZEND_ROPE_ADD || opline->opcode == ZEND_ADD_ARRAY_ELEMENT || opline->opcode == ZEND_ADD_ARRAY_UNPACK; } -static zend_bool keeps_op1_alive(zend_op *opline) { +static bool keeps_op1_alive(zend_op *opline) { /* These opcodes don't consume their OP1 operand, * it is later freed by something else. */ if (opline->opcode == ZEND_CASE |