void zend_shutdown(void) /* {{{ */
{
zend_destroy_rsrc_list(&EG(persistent_list));
- if (EG(active))
- {
- /*
- * The order of destruction is important here.
- * See bugs #65463 and 66036.
- */
- zend_function *func;
- zend_class_entry *ce;
-
- ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_FUNCTION_TABLE, func) {
- if (func->type == ZEND_USER_FUNCTION) {
- zend_cleanup_op_array_data((zend_op_array *) func);
- }
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_CLASS_TABLE, ce) {
- if (ce->type == ZEND_USER_CLASS) {
- zend_cleanup_user_class_data(ce);
- } else {
- break;
- }
- } ZEND_HASH_FOREACH_END();
- zend_cleanup_internal_classes();
- zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) clean_non_persistent_function_full);
- zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) clean_non_persistent_class_full);
- }
zend_destroy_modules();
virtual_cwd_deactivate();
ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size);
ZEND_API void destroy_op_array(zend_op_array *op_array);
ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle);
-ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce);
ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce);
ZEND_API void zend_cleanup_internal_classes(void);
-ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array);
-ZEND_API int clean_non_persistent_function_full(zval *zv);
-ZEND_API int clean_non_persistent_class_full(zval *zv);
ZEND_API void destroy_zend_function(zend_function *function);
ZEND_API void zend_function_dtor(zval *zv);
}
-static int clean_non_persistent_constant(zval *zv)
-{
- zend_constant *c = Z_PTR_P(zv);
- return (c->flags & CONST_PERSISTENT) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
-}
-
-
-static int clean_non_persistent_constant_full(zval *zv)
-{
- zend_constant *c = Z_PTR_P(zv);
- return (c->flags & CONST_PERSISTENT) ? 0 : 1;
-}
-
-
static int clean_module_constant(zval *el, void *arg)
{
zend_constant *c = (zend_constant *)Z_PTR_P(el);
return SUCCESS;
}
-
-void clean_non_persistent_constants(void)
-{
- if (EG(full_tables_cleanup)) {
- zend_hash_apply(EG(zend_constants), clean_non_persistent_constant_full);
- } else {
- zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant);
- }
-}
-
ZEND_API void zend_register_null_constant(const char *name, size_t name_len, int flags, int module_number)
{
zend_constant c;
int zend_startup_constants(void);
int zend_shutdown_constants(void);
void zend_register_standard_constants(void);
-void clean_non_persistent_constants(void);
ZEND_API int zend_verify_const_access(zend_class_constant *c, zend_class_entry *ce);
ZEND_API zval *zend_get_constant(zend_string *name);
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len);
}
/* }}} */
-static int clean_non_persistent_function(zval *zv) /* {{{ */
+static int clean_non_persistent_constant_full(zval *zv) /* {{{ */
{
- zend_function *function = Z_PTR_P(zv);
- return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
+ zend_constant *c = Z_PTR_P(zv);
+ return (c->flags & CONST_PERSISTENT) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
}
/* }}} */
-ZEND_API int clean_non_persistent_function_full(zval *zv) /* {{{ */
+static int clean_non_persistent_function_full(zval *zv) /* {{{ */
{
zend_function *function = Z_PTR_P(zv);
return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
}
/* }}} */
-static int clean_non_persistent_class(zval *zv) /* {{{ */
-{
- zend_class_entry *ce = Z_PTR_P(zv);
- return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
-}
-/* }}} */
-
-ZEND_API int clean_non_persistent_class_full(zval *zv) /* {{{ */
+static int clean_non_persistent_class_full(zval *zv) /* {{{ */
{
zend_class_entry *ce = Z_PTR_P(zv);
return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
void shutdown_executor(void) /* {{{ */
{
- zend_function *func;
- zend_class_entry *ce;
+ zend_string *key;
+ zval *zv;
+#if ZEND_DEBUG
+ zend_bool fast_shutdown = 0;
+#else
+ zend_bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup);
+#endif
zend_try {
+ zend_llist_destroy(&CG(open_files));
+ } zend_end_try();
-/* Removed because this can not be safely done, e.g. in this situation:
- Object 1 creates object 2
- Object 3 holds reference to object 2.
- Now when 1 and 2 are destroyed, 3 can still access 2 in its destructor, with
- very problematic results */
-/* zend_objects_store_call_destructors(&EG(objects_store)); */
+ zend_try {
+ zend_close_rsrc_list(&EG(regular_list));
+ } zend_end_try();
-/* Moved after symbol table cleaners, because some of the cleaners can call
- destructors, which would use EG(symtable_cache_ptr) and thus leave leaks */
-/* while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
- zend_hash_destroy(*EG(symtable_cache_ptr));
- efree(*EG(symtable_cache_ptr));
- EG(symtable_cache_ptr)--;
- }
-*/
- zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
+ zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
- zend_hash_graceful_reverse_destroy(&EG(symbol_table));
+ /* All resources and objects are destroyed. */
+ /* No PHP callback functions may be called after this point. */
+
+ zend_try {
+ zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
} zend_end_try();
+
EG(valid_symbol_table) = 0;
- zend_try {
- zval *zeh;
+ if (fast_shutdown) {
+ /* Fast Request Shutdown
+ * =====================
+ * Zend Memory Manager frees memory by its own. We don't have to free
+ * each allocated block separately.
+ */
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(zend_constants), zv) {
+ zend_constant *c = Z_PTR_P(zv);
+ if (c->flags & CONST_PERSISTENT) {
+ break;
+ }
+ } ZEND_HASH_FOREACH_END_DEL();
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
+ zend_function *func = Z_PTR_P(zv);
+ if (func->type == ZEND_INTERNAL_FUNCTION) {
+ break;
+ }
+ } ZEND_HASH_FOREACH_END_DEL();
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
+ zend_class_entry *ce = Z_PTR_P(zv);
+ if (ce->type == ZEND_INTERNAL_CLASS) {
+ break;
+ }
+ } ZEND_HASH_FOREACH_END_DEL();
+ } else {
+ zend_hash_graceful_reverse_destroy(&EG(symbol_table));
+
+#if ZEND_DEBUG
+ if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
+ gc_collect_cycles();
+ }
+#endif
+
/* remove error handlers before destroying classes and functions,
* so that if handler used some class, crash would not happen */
if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
- zeh = &EG(user_error_handler);
- zval_ptr_dtor(zeh);
+ zval_ptr_dtor(&EG(user_error_handler));
ZVAL_UNDEF(&EG(user_error_handler));
}
if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
- zeh = &EG(user_exception_handler);
- zval_ptr_dtor(zeh);
+ zval_ptr_dtor(&EG(user_exception_handler));
ZVAL_UNDEF(&EG(user_exception_handler));
}
zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1);
zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
- } zend_end_try();
- zend_try {
- /* Cleanup static data for functions and arrays.
- * We need a separate cleanup stage because of the following problem:
- * Suppose we destroy class X, which destroys the class's function table,
- * and in the function table we have function foo() that has static $bar.
- * Now if an object of class X is assigned to $bar, its destructor will be
- * called and will fail since X's function table is in mid-destruction.
- * So we want first of all to clean up all data and then move to tables destruction.
- * Note that only run-time accessed data need to be cleaned up, pre-defined data can
- * not contain objects and thus are not probelmatic */
+ zend_vm_stack_destroy();
+
if (EG(full_tables_cleanup)) {
- ZEND_HASH_FOREACH_PTR(EG(function_table), func) {
- if (func->type == ZEND_USER_FUNCTION) {
- zend_cleanup_op_array_data((zend_op_array *) func);
+ zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full);
+ zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
+ zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
+ } else {
+ ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) {
+ zend_constant *c = Z_PTR_P(zv);
+ if (c->flags & CONST_PERSISTENT) {
+ break;
}
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
- if (ce->type == ZEND_USER_CLASS) {
- zend_cleanup_user_class_data(ce);
- } else {
- zend_cleanup_internal_class_data(ce);
+ zval_ptr_dtor(&c->value);
+ if (c->name) {
+ zend_string_release(c->name);
}
- } ZEND_HASH_FOREACH_END();
- } else {
- ZEND_HASH_REVERSE_FOREACH_PTR(EG(function_table), func) {
- if (func->type != ZEND_USER_FUNCTION) {
+ efree(c);
+ zend_string_release(key);
+ } ZEND_HASH_FOREACH_END_DEL();
+ ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(function_table), key, zv) {
+ zend_function *func = Z_PTR_P(zv);
+ if (func->type == ZEND_INTERNAL_FUNCTION) {
break;
}
- zend_cleanup_op_array_data((zend_op_array *) func);
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
- if (ce->type != ZEND_USER_CLASS) {
+ destroy_op_array(&func->op_array);
+ zend_string_release(key);
+ } ZEND_HASH_FOREACH_END_DEL();
+ ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
+ zend_class_entry *ce = Z_PTR_P(zv);
+ if (ce->type == ZEND_INTERNAL_CLASS) {
break;
}
- zend_cleanup_user_class_data(ce);
- } ZEND_HASH_FOREACH_END();
- zend_cleanup_internal_classes();
- }
- } zend_end_try();
-
- zend_try {
- zend_llist_destroy(&CG(open_files));
- } zend_end_try();
-
- zend_try {
- clean_non_persistent_constants();
- } zend_end_try();
-
- zend_try {
- zend_close_rsrc_list(&EG(regular_list));
- } zend_end_try();
-
-#if ZEND_DEBUG
- if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
- gc_collect_cycles();
- }
-#endif
-
- zend_try {
- zend_objects_store_free_object_storage(&EG(objects_store));
-
- zend_vm_stack_destroy();
-
- /* Destroy all op arrays */
- if (EG(full_tables_cleanup)) {
- zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
- zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
- } else {
- zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function);
- zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class);
+ destroy_zend_class(zv);
+ zend_string_release(key);
+ } ZEND_HASH_FOREACH_END_DEL();
}
while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
FREE_HASHTABLE(*EG(symtable_cache_ptr));
EG(symtable_cache_ptr)--;
}
- } zend_end_try();
-
- zend_try {
-#if 0&&ZEND_DEBUG
- signal(SIGSEGV, original_sigsegv_handler);
-#endif
zend_hash_destroy(&EG(included_files));
zend_hash_destroy(EG(in_autoload));
FREE_HASHTABLE(EG(in_autoload));
}
- } zend_end_try();
- zend_shutdown_fpu();
+ if (EG(ht_iterators) != EG(ht_iterators_slots)) {
+ efree(EG(ht_iterators));
+ }
+ }
#if ZEND_DEBUG
if (EG(ht_iterators_used) && !CG(unclean_shutdown)) {
#endif
EG(ht_iterators_used) = 0;
- if (EG(ht_iterators) != EG(ht_iterators_slots)) {
- efree(EG(ht_iterators));
- }
+
+ zend_cleanup_internal_classes();
+
+ zend_shutdown_fpu();
EG(active) = 0;
}
zend_hash_get_current_data_ptr_ex(ht, &(ht)->nInternalPointer)
#define ZEND_HASH_FOREACH(_ht, indirect) do { \
- Bucket *_p = (_ht)->arData; \
- Bucket *_end = _p + (_ht)->nNumUsed; \
+ HashTable *__ht = (_ht); \
+ Bucket *_p = __ht->arData; \
+ Bucket *_end = _p + __ht->nNumUsed; \
for (; _p != _end; _p++) { \
zval *_z = &_p->val; \
if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
#define ZEND_HASH_REVERSE_FOREACH(_ht, indirect) do { \
+ HashTable *__ht = (_ht); \
uint32_t _idx; \
- for (_idx = (_ht)->nNumUsed; _idx > 0; _idx--) { \
- Bucket *_p = (_ht)->arData + _idx - 1; \
+ for (_idx = __ht->nNumUsed; _idx > 0; _idx--) { \
+ Bucket *_p = __ht->arData + (_idx - 1); \
zval *_z = &_p->val; \
if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
_z = Z_INDIRECT_P(_z); \
} \
} while (0)
+#define ZEND_HASH_FOREACH_END_DEL() \
+ __ht->nNumOfElements--; \
+ do { \
+ uint32_t j = HT_IDX_TO_HASH(_idx - 1); \
+ uint32_t nIndex = _p->h | __ht->nTableMask; \
+ uint32_t i = HT_HASH(__ht, nIndex); \
+ if (j != i) { \
+ Bucket *prev = HT_HASH_TO_BUCKET(__ht, i); \
+ while (Z_NEXT(prev->val) != j) { \
+ i = Z_NEXT(prev->val); \
+ prev = HT_HASH_TO_BUCKET(__ht, i); \
+ } \
+ Z_NEXT(prev->val) = Z_NEXT(_p->val); \
+ } else { \
+ HT_HASH(__ht, _p->h | __ht->nTableMask) = Z_NEXT(_p->val); \
+ } \
+ } while (0); \
+ } \
+ __ht->nNumUsed = _idx; \
+ } while (0)
+
#define ZEND_HASH_FOREACH_BUCKET(ht, _bucket) \
ZEND_HASH_FOREACH(ht, 0); \
_bucket = _p;
ZEND_HASH_REVERSE_FOREACH(ht, 1); \
_val = _z;
+#define ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(ht, _key, _val) \
+ ZEND_HASH_REVERSE_FOREACH(ht, 0); \
+ _key = _p->key; \
+ _val = _z;
+
#define ZEND_HASH_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_h = _p->h; \
}
}
-ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects)
+ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects, zend_bool fast_shutdown)
{
zend_object **obj_ptr, **end, *obj;
end = objects->object_buckets + 1;
obj_ptr = objects->object_buckets + objects->top;
- do {
- obj_ptr--;
- obj = *obj_ptr;
- if (IS_OBJ_VALID(obj)) {
- if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
- GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED;
- if (obj->handlers->free_obj) {
- GC_REFCOUNT(obj)++;
- obj->handlers->free_obj(obj);
- GC_REFCOUNT(obj)--;
+ if (fast_shutdown) {
+ do {
+ obj_ptr--;
+ obj = *obj_ptr;
+ if (IS_OBJ_VALID(obj)) {
+ if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
+ GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED;
+ if (obj->handlers->free_obj && obj->handlers->free_obj != zend_object_std_dtor) {
+ GC_REFCOUNT(obj)++;
+ obj->handlers->free_obj(obj);
+ GC_REFCOUNT(obj)--;
+ }
}
}
- }
- } while (obj_ptr != end);
+ } while (obj_ptr != end);
+ } else {
+ do {
+ obj_ptr--;
+ obj = *obj_ptr;
+ if (IS_OBJ_VALID(obj)) {
+ if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
+ GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED;
+ if (obj->handlers->free_obj) {
+ GC_REFCOUNT(obj)++;
+ obj->handlers->free_obj(obj);
+ GC_REFCOUNT(obj)--;
+ }
+ }
+ }
+ } while (obj_ptr != end);
+ }
}
GC_FLAGS(obj) |= IS_OBJ_DESTRUCTOR_CALLED;
}
-ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects);
+ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects, zend_bool fast_shutdown);
#define ZEND_OBJECTS_STORE_HANDLERS 0, zend_object_std_dtor, zend_objects_destroy_object, zend_objects_clone_obj
}
}
-ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array)
-{
- if (op_array->static_variables &&
- !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)
- ) {
- /* The static variables are initially shared when inheriting methods and will
- * be separated on first use. If they are never used, they stay shared. Cleaning
- * a shared static variables table is safe, as the intention is to clean all
- * such tables. */
- HT_ALLOW_COW_VIOLATION(op_array->static_variables);
-
- zend_hash_clean(op_array->static_variables);
- }
-}
-
-ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce)
-{
- /* Clean all parts that can contain run-time data */
- /* Note that only run-time accessed data need to be cleaned up, pre-defined data can
- not contain objects and thus are not probelmatic */
- if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
- zend_function *func;
-
- ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
- if (func->type == ZEND_USER_FUNCTION) {
- zend_cleanup_op_array_data((zend_op_array *) func);
- }
- } ZEND_HASH_FOREACH_END();
- }
- if (ce->static_members_table) {
- zval *static_members = ce->static_members_table;
- zval *p = static_members;
- zval *end = p + ce->default_static_members_count;
-
-
- ce->default_static_members_count = 0;
- ce->default_static_members_table = ce->static_members_table = NULL;
- while (p != end) {
- i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
- p++;
- }
- efree(static_members);
- }
-}
-
ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce)
{
if (CE_STATIC_MEMBERS(ce)) {
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
-opcache.fast_shutdown=1
opcache.enable_cli=1
You also may add the following, but it may break some applications and
size of the optimized code. Disabling "Doc Comments" may break some
existing applications and frameworks (e.g. Doctrine, ZF2, PHPUnit)
-opcache.fast_shutdown (default "0")
- If enabled, a fast shutdown sequence is used for the accelerated code
- The fast shutdown sequence doesn't free each allocated block, but lets
- the Zend Engine Memory Manager do the work.
-
opcache.enable_file_override (default "0")
Allow file existence override (file_exists, etc.) performance feature.
}
}
-#if !ZEND_DEBUG
-
-/* Fast Request Shutdown
- * =====================
- * Zend Memory Manager frees memory by its own. We don't have to free each
- * allocated block separately, but we like to call all the destructors and
- * callbacks in exactly the same order.
- */
-static void accel_fast_hash_destroy(HashTable *ht);
-
-static void accel_fast_zval_dtor(zval *zvalue)
-{
-tail_call:
- switch (Z_TYPE_P(zvalue)) {
- case IS_ARRAY:
- GC_REMOVE_FROM_BUFFER(Z_ARR_P(zvalue));
- if (Z_ARR_P(zvalue) != &EG(symbol_table)) {
- /* break possible cycles */
- ZVAL_NULL(zvalue);
- accel_fast_hash_destroy(Z_ARRVAL_P(zvalue));
- }
- break;
- case IS_OBJECT:
- OBJ_RELEASE(Z_OBJ_P(zvalue));
- break;
- case IS_RESOURCE:
- zend_list_delete(Z_RES_P(zvalue));
- break;
- case IS_REFERENCE: {
- zend_reference *ref = Z_REF_P(zvalue);
-
- if (--GC_REFCOUNT(ref) == 0) {
- if (Z_REFCOUNTED(ref->val) && Z_DELREF(ref->val) == 0) {
- zvalue = &ref->val;
- goto tail_call;
- }
- }
- }
- break;
- }
-}
-
-static void accel_fast_hash_destroy(HashTable *ht)
-{
- Bucket *p = ht->arData;
- Bucket *end = p + ht->nNumUsed;
-
- while (p != end) {
- if (Z_REFCOUNTED(p->val) && Z_DELREF(p->val) == 0) {
- accel_fast_zval_dtor(&p->val);
- }
- p++;
- }
-}
-
-static inline void zend_accel_fast_del_bucket(HashTable *ht, uint32_t idx, Bucket *p)
-{
- uint32_t nIndex = p->h | ht->nTableMask;
- uint32_t i = HT_HASH(ht, nIndex);
-
- ht->nNumOfElements--;
- if (idx != i) {
- Bucket *prev = HT_HASH_TO_BUCKET(ht, i);
- while (Z_NEXT(prev->val) != idx) {
- i = Z_NEXT(prev->val);
- prev = HT_HASH_TO_BUCKET(ht, i);
- }
- Z_NEXT(prev->val) = Z_NEXT(p->val);
- } else {
- HT_HASH(ht, p->h | ht->nTableMask) = Z_NEXT(p->val);
- }
-}
-
-static void zend_accel_fast_shutdown(void)
-{
- if (EG(full_tables_cleanup)) {
- return;
- }
-
- if (EG(objects_store).top > 1 || zend_hash_num_elements(&EG(regular_list)) > 0) {
- /* We don't have to destroy all zvals if they cannot call any destructors */
- zend_try {
- ZEND_HASH_REVERSE_FOREACH(&EG(symbol_table), 0) {
- if (Z_REFCOUNTED(_p->val) && Z_DELREF(_p->val) == 0) {
- accel_fast_zval_dtor(&_p->val);
- }
- zend_accel_fast_del_bucket(&EG(symbol_table), HT_IDX_TO_HASH(_idx-1), _p);
- } ZEND_HASH_FOREACH_END();
- } zend_end_try();
- zend_hash_init(&EG(symbol_table), 8, NULL, NULL, 0);
-
- ZEND_HASH_REVERSE_FOREACH(EG(function_table), 0) {
- zend_function *func = Z_PTR(_p->val);
-
- if (func->type == ZEND_INTERNAL_FUNCTION) {
- break;
- } else {
- if (func->op_array.static_variables) {
- if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
- if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
- accel_fast_hash_destroy(func->op_array.static_variables);
- }
- }
- }
- zend_accel_fast_del_bucket(EG(function_table), HT_IDX_TO_HASH(_idx-1), _p);
- }
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_REVERSE_FOREACH(EG(class_table), 0) {
- zend_class_entry *ce = Z_PTR(_p->val);
-
- if (ce->type == ZEND_INTERNAL_CLASS) {
- break;
- } else {
- if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
- zend_function *func;
-
- ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
- if (func->type == ZEND_USER_FUNCTION) {
- if (func->op_array.static_variables) {
- if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
- if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
- accel_fast_hash_destroy(func->op_array.static_variables);
- }
- }
- func->op_array.static_variables = NULL;
- }
- }
- } ZEND_HASH_FOREACH_END();
- }
- if (ce->static_members_table) {
- int i;
-
- for (i = 0; i < ce->default_static_members_count; i++) {
- zval *zv = &ce->static_members_table[i];
- ZVAL_UNDEF(&ce->static_members_table[i]);
- if (Z_REFCOUNTED_P(zv) && Z_DELREF_P(zv) == 0) {
- accel_fast_zval_dtor(zv);
- }
- }
- ce->static_members_table = NULL;
- }
- zend_accel_fast_del_bucket(EG(class_table), HT_IDX_TO_HASH(_idx-1), _p);
- }
- } ZEND_HASH_FOREACH_END();
-
- } else {
-
- zend_hash_init(&EG(symbol_table), 8, NULL, NULL, 0);
-
- ZEND_HASH_REVERSE_FOREACH(EG(function_table), 0) {
- zend_function *func = Z_PTR(_p->val);
-
- if (func->type == ZEND_INTERNAL_FUNCTION) {
- break;
- } else {
- zend_accel_fast_del_bucket(EG(function_table), HT_IDX_TO_HASH(_idx-1), _p);
- }
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_REVERSE_FOREACH(EG(class_table), 0) {
- zend_class_entry *ce = Z_PTR(_p->val);
-
- if (ce->type == ZEND_INTERNAL_CLASS) {
- break;
- } else {
- zend_accel_fast_del_bucket(EG(class_table), HT_IDX_TO_HASH(_idx-1), _p);
- }
- } ZEND_HASH_FOREACH_END();
- }
-
- ZEND_HASH_REVERSE_FOREACH(EG(zend_constants), 0) {
- zend_constant *c = Z_PTR(_p->val);
-
- if (c->flags & CONST_PERSISTENT) {
- break;
- } else {
- zend_accel_fast_del_bucket(EG(zend_constants), HT_IDX_TO_HASH(_idx-1), _p);
- }
- } ZEND_HASH_FOREACH_END();
- EG(function_table)->nNumUsed = EG(function_table)->nNumOfElements;
- EG(class_table)->nNumUsed = EG(class_table)->nNumOfElements;
- EG(zend_constants)->nNumUsed = EG(zend_constants)->nNumOfElements;
-}
-#endif
-
int accel_post_deactivate(void)
{
if (!ZCG(enabled) || !accel_startup_ok) {
if (!ZCG(enabled) || !accel_startup_ok) {
return;
}
-
-#if !ZEND_DEBUG
- if (ZCG(accel_directives).fast_shutdown && is_zend_mm()) {
- zend_accel_fast_shutdown();
- }
-#endif
}
static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
zend_bool validate_timestamps;
zend_bool revalidate_path;
zend_bool save_comments;
- zend_bool fast_shutdown;
zend_bool protect_memory;
zend_bool file_override_enabled;
zend_bool inherited_hack;
STD_PHP_INI_ENTRY("opcache.protect_memory" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.protect_memory, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.save_comments" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.save_comments, zend_accel_globals, accel_globals)
- STD_PHP_INI_ENTRY("opcache.fast_shutdown" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.fast_shutdown, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.opt_debug_level" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.opt_debug_level, zend_accel_globals, accel_globals)
add_assoc_bool(&directives, "opcache.protect_memory", ZCG(accel_directives).protect_memory);
add_assoc_bool(&directives, "opcache.save_comments", ZCG(accel_directives).save_comments);
- add_assoc_bool(&directives, "opcache.fast_shutdown", ZCG(accel_directives).fast_shutdown);
add_assoc_bool(&directives, "opcache.enable_file_override", ZCG(accel_directives).file_override_enabled);
add_assoc_long(&directives, "opcache.optimization_level", ZCG(accel_directives).optimization_level);
/* we don't work with *stream but need its value for comparison */
zend_hash_apply_with_argument(&EG(persistent_list), _php_stream_free_persistent, stream);
}
-#if ZEND_DEBUG
- if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) && (stream->__exposed == 0) && (EG(error_reporting) & E_WARNING)) {
- /* it leaked: Lets deliberately NOT pefree it so that the memory manager shows it
- * as leaked; it will log a warning, but lets help it out and display what kind
- * of stream it was. */
- if (!CG(unclean_shutdown)) {
- char *leakinfo;
- spprintf(&leakinfo, 0, __FILE__ "(%d) : Stream of type '%s' %p (path:%s) was not closed\n", __LINE__, stream->ops->label, stream, stream->orig_path);
-
- if (stream->orig_path) {
- pefree(stream->orig_path, stream->is_persistent);
- stream->orig_path = NULL;
- }
-# if defined(PHP_WIN32)
- OutputDebugString(leakinfo);
-# else
- fprintf(stderr, "%s", leakinfo);
-# endif
- efree(leakinfo);
- }
- } else {
- if (stream->orig_path) {
- pefree(stream->orig_path, stream->is_persistent);
- stream->orig_path = NULL;
- }
-
- pefree(stream, stream->is_persistent);
- }
-#else
if (stream->orig_path) {
pefree(stream->orig_path, stream->is_persistent);
stream->orig_path = NULL;
}
pefree(stream, stream->is_persistent);
-#endif
}
if (context) {