PHP Classes

File: ext/kernel/memory.c

Recommend this page to a friend!
  Classes of Alien Fernandez   Phady Framework   ext/kernel/memory.c   Download  
File: ext/kernel/memory.c
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Phady Framework
Web application MVC framework based on Phalcon
Author: By
Last change:
Date: 8 years ago
Size: 24,026 bytes
 

Contents

Class file image Download
/* +------------------------------------------------------------------------+ | Zephir Language | +------------------------------------------------------------------------+ | Copyright (c) 2011-2015 Zephir Team (http://www.zephir-lang.com) | +------------------------------------------------------------------------+ | This source file is subject to the New BSD License that is bundled | | with this package in the file docs/LICENSE.txt. | | | | If you did not receive a copy of the license and are unable to | | obtain it through the world-wide-web, please send an email | | to license@zephir-lang.com so we can send you a copy immediately. | +------------------------------------------------------------------------+ | Authors: Andres Gutierrez <andres@zephir-lang.com> | | Eduar Carvajal <eduar@zephir-lang.com> | | Vladimir Kolesnikov <vladimir@extrememember.com> | +------------------------------------------------------------------------+ */ #include "php.h" #include "php_ext.h" #include "kernel/memory.h" #include <Zend/zend_alloc.h> #include "kernel/fcall.h" #include "kernel/backtrace.h" /* * Memory Frames/Virtual Symbol Scopes *------------------------------------ * * Zephir uses memory frames to track the variables used within a method * in order to free them or reduce their reference counting accordingly before * exit the method in execution. * * This adds a minimum overhead to execution but save us the work of * free memory in each method manually. * * The whole memory frame is an open double-linked list which start is an * allocated empty frame that points to the real first frame. The start * memory frame is globally accesed using ZEPHIR_GLOBAL(start_frame) * * Not all methods must grow/restore the zephir_memory_entry. */ static zephir_memory_entry* zephir_memory_grow_stack_common(zend_zephir_globals_def *g) { assert(g->start_memory != NULL); if (!g->active_memory) { g->active_memory = g->start_memory; #ifndef ZEPHIR_RELEASE assert(g->active_memory->permanent == 1); #endif } else if (!g->active_memory->next) { #ifndef PHP_WIN32 assert(g->active_memory >= g->end_memory - 1 || g->active_memory < g->start_memory); #endif zephir_memory_entry *entry = (zephir_memory_entry *) ecalloc(1, sizeof(zephir_memory_entry)); /* ecalloc() will take care of these members entry->pointer = 0; entry->capacity = 0; entry->addresses = NULL; entry->hash_pointer = 0; entry->hash_capacity = 0; entry->hash_addresses = NULL; entry->next = NULL; */ #ifndef ZEPHIR_RELEASE entry->permanent = 0; entry->func = NULL; #endif entry->prev = g->active_memory; entry->prev->next = entry; g->active_memory = entry; } else { #ifndef ZEPHIR_RELEASE assert(g->active_memory->permanent == 1); #endif assert(g->active_memory < g->end_memory && g->active_memory >= g->start_memory); g->active_memory = g->active_memory->next; } assert(g->active_memory->pointer == 0); assert(g->active_memory->hash_pointer == 0); return g->active_memory; } /** * Restore a memory stack applying GC to all observed variables */ static void zephir_memory_restore_stack_common(zend_zephir_globals_def *g TSRMLS_DC) { size_t i; zephir_memory_entry *prev, *active_memory; zephir_symbol_table *active_symbol_table; zval **ptr; active_memory = g->active_memory; assert(active_memory != NULL); if (EXPECTED(!CG(unclean_shutdown))) { /* Clean active symbol table */ if (g->active_symbol_table) { active_symbol_table = g->active_symbol_table; if (active_symbol_table->scope == active_memory) { zend_hash_destroy(EG(active_symbol_table)); FREE_HASHTABLE(EG(active_symbol_table)); EG(active_symbol_table) = active_symbol_table->symbol_table; g->active_symbol_table = active_symbol_table->prev; efree(active_symbol_table); } } /* Check for non freed hash key zvals, mark as null to avoid string freeing */ for (i = 0; i < active_memory->hash_pointer; ++i) { assert(active_memory->hash_addresses[i] != NULL && *(active_memory->hash_addresses[i]) != NULL); if (Z_REFCOUNT_PP(active_memory->hash_addresses[i]) <= 1) { ZVAL_NULL(*active_memory->hash_addresses[i]); } else { zval_copy_ctor(*active_memory->hash_addresses[i]); } } #ifndef ZEPHIR_RELEASE for (i = 0; i < active_memory->pointer; ++i) { if (active_memory->addresses[i] != NULL && *(active_memory->addresses[i]) != NULL) { zval **var = active_memory->addresses[i]; #if PHP_VERSION_ID < 50400 if (Z_TYPE_PP(var) > IS_CONSTANT_ARRAY) { fprintf(stderr, "%s: observed variable #%d (%p) has invalid type %u [%s]\n", __func__, (int)i, *var, Z_TYPE_PP(var), active_memory->func); } #else if (Z_TYPE_PP(var) > IS_CALLABLE) { fprintf(stderr, "%s: observed variable #%d (%p) has invalid type %u [%s]\n", __func__, (int)i, *var, Z_TYPE_PP(var), active_memory->func); } #endif if (Z_REFCOUNT_PP(var) == 0) { fprintf(stderr, "%s: observed variable #%d (%p) has 0 references, type=%d [%s]\n", __func__, (int)i, *var, Z_TYPE_PP(var), active_memory->func); } else if (Z_REFCOUNT_PP(var) >= 1000000) { fprintf(stderr, "%s: observed variable #%d (%p) has too many references (%u), type=%d [%s]\n", __func__, (int)i, *var, Z_REFCOUNT_PP(var), Z_TYPE_PP(var), active_memory->func); } #if 0 /* Skip this check, PDO does return variables with is_ref = 1 and refcount = 1*/ else if (Z_REFCOUNT_PP(var) == 1 && Z_ISREF_PP(var)) { fprintf(stderr, "%s: observed variable #%d (%p) is a reference with reference count = 1, type=%d [%s]\n", __func__, (int)i, *var, Z_TYPE_PP(var), active_memory->func); } #endif } } #endif /* Traverse all zvals allocated, reduce the reference counting or free them */ for (i = 0; i < active_memory->pointer; ++i) { ptr = active_memory->addresses[i]; if (EXPECTED(ptr != NULL && *(ptr) != NULL)) { if (Z_REFCOUNT_PP(ptr) == 1) { if (!Z_ISREF_PP(ptr) || Z_TYPE_PP(ptr) == IS_OBJECT) { zval_ptr_dtor(ptr); } else { efree(*ptr); } } else { Z_DELREF_PP(ptr); } } } } #ifndef ZEPHIR_RELEASE active_memory->func = NULL; #endif prev = active_memory->prev; if (active_memory >= g->end_memory || active_memory < g->start_memory) { #ifndef ZEPHIR_RELEASE assert(g->active_memory->permanent == 0); #endif assert(prev != NULL); if (active_memory->hash_addresses != NULL) { efree(active_memory->hash_addresses); } if (active_memory->addresses != NULL) { efree(active_memory->addresses); } efree(g->active_memory); g->active_memory = prev; prev->next = NULL; } else { #ifndef ZEPHIR_RELEASE assert(g->active_memory->permanent == 1); #endif active_memory->pointer = 0; active_memory->hash_pointer = 0; g->active_memory = prev; } #ifndef ZEPHIR_RELEASE if (g->active_memory) { zephir_memory_entry *f = g->active_memory; if (f >= g->start_memory && f < g->end_memory - 1) { assert(f->permanent == 1); assert(f->next != NULL); if (f > g->start_memory) { assert(f->prev != NULL); } } } #endif } #ifndef ZEPHIR_RELEASE /** * Dumps a memory frame for debug purposes */ void zephir_dump_memory_frame(zephir_memory_entry *active_memory TSRMLS_DC) { size_t i; assert(active_memory != NULL); fprintf(stderr, "Dump of the memory frame %p (%s)\n", active_memory, active_memory->func); if (active_memory->hash_pointer) { for (i = 0; i < active_memory->hash_pointer; ++i) { assert(active_memory->hash_addresses[i] != NULL && *(active_memory->hash_addresses[i]) != NULL); fprintf(stderr, "Hash ptr %lu (%p => %p), type=%u, refcnt=%u\n", (ulong)i, active_memory->hash_addresses[i], *active_memory->hash_addresses[i], Z_TYPE_PP(active_memory->hash_addresses[i]), Z_REFCOUNT_PP(active_memory->hash_addresses[i])); } } for (i = 0; i < active_memory->pointer; ++i) { if (EXPECTED(active_memory->addresses[i] != NULL && *(active_memory->addresses[i]) != NULL)) { zval **var = active_memory->addresses[i]; fprintf(stderr, "Obs var %lu (%p => %p), type=%u, refcnt=%u; ", (ulong)i, var, *var, Z_TYPE_PP(var), Z_REFCOUNT_PP(var)); switch (Z_TYPE_PP(var)) { case IS_NULL: fprintf(stderr, "value=NULL\n"); break; case IS_LONG: fprintf(stderr, "value=%ld\n", Z_LVAL_PP(var)); break; case IS_DOUBLE: fprintf(stderr, "value=%E\n", Z_DVAL_PP(var)); break; case IS_BOOL: fprintf(stderr, "value=(bool)%d\n", Z_BVAL_PP(var)); break; case IS_ARRAY: fprintf(stderr, "value=array(%p), %d elements\n", Z_ARRVAL_PP(var), zend_hash_num_elements(Z_ARRVAL_PP(var))); break; case IS_OBJECT: fprintf(stderr, "value=object(%u), %s\n", Z_OBJ_HANDLE_PP(var), Z_OBJCE_PP(var)->name); break; case IS_STRING: fprintf(stderr, "value=%*s (%p)\n", Z_STRLEN_PP(var), Z_STRVAL_PP(var), Z_STRVAL_PP(var)); break; case IS_RESOURCE: fprintf(stderr, "value=(resource)%ld\n", Z_LVAL_PP(var)); break; default: fprintf(stderr, "\n"); break; } } } fprintf(stderr, "End of the dump of the memory frame %p\n", active_memory); } void zephir_dump_current_frame(TSRMLS_D) { zend_zephir_globals_def *zephir_globals_ptr = ZEPHIR_VGLOBAL; if (UNEXPECTED(zephir_globals_ptr->active_memory == NULL)) { fprintf(stderr, "WARNING: calling %s() without an active memory frame!\n", __func__); zephir_print_backtrace(); return; } zephir_dump_memory_frame(zephir_globals_ptr->active_memory TSRMLS_CC); } void zephir_dump_all_frames(TSRMLS_D) { zend_zephir_globals_def *zephir_globals_ptr = ZEPHIR_VGLOBAL; zephir_memory_entry *active_memory = zephir_globals_ptr->active_memory; fprintf(stderr, "*** DUMP START ***\n"); while (active_memory != NULL) { zephir_dump_memory_frame(active_memory TSRMLS_CC); active_memory = active_memory->prev; } fprintf(stderr, "*** DUMP END ***\n"); } /** * Finishes the current memory stack by releasing allocated memory */ int ZEND_FASTCALL zephir_memory_restore_stack(const char *func TSRMLS_DC) { zend_zephir_globals_def *zephir_globals_ptr = ZEPHIR_VGLOBAL; if (UNEXPECTED(zephir_globals_ptr->active_memory == NULL)) { fprintf(stderr, "WARNING: calling zephir_memory_restore_stack() without an active memory frame!\n"); zephir_print_backtrace(); return FAILURE; } if (UNEXPECTED(zephir_globals_ptr->active_memory->func != func)) { fprintf(stderr, "Trying to free someone else's memory frame!\n"); fprintf(stderr, "The frame was created by %s\n", zephir_globals_ptr->active_memory->func); fprintf(stderr, "Calling function: %s\n", func); zephir_print_backtrace(); } zephir_memory_restore_stack_common(zephir_globals_ptr TSRMLS_CC); return SUCCESS; } /** * Adds a memory frame in the current executed method */ void ZEND_FASTCALL zephir_memory_grow_stack(const char *func TSRMLS_DC) { zephir_memory_entry *entry; zend_zephir_globals_def *g = ZEPHIR_VGLOBAL; if (g->start_memory == NULL) { zephir_initialize_memory(g TSRMLS_CC); } entry = zephir_memory_grow_stack_common(g); entry->func = func; } #else /** * Adds a memory frame in the current executed method */ void ZEND_FASTCALL zephir_memory_grow_stack(TSRMLS_D) { zend_zephir_globals_def *g = ZEPHIR_VGLOBAL; if (g->start_memory == NULL) { zephir_initialize_memory(g TSRMLS_CC); } zephir_memory_grow_stack_common(g); } /** * Finishes the current memory stack by releasing allocated memory */ int ZEND_FASTCALL zephir_memory_restore_stack(TSRMLS_D) { zephir_memory_restore_stack_common(ZEPHIR_VGLOBAL TSRMLS_CC); return SUCCESS; } #endif /** * Pre-allocates memory for further use in execution */ void zephir_initialize_memory(zend_zephir_globals_def *zephir_globals_ptr TSRMLS_DC) { zephir_memory_entry *start; size_t i; start = (zephir_memory_entry *) pecalloc(ZEPHIR_NUM_PREALLOCATED_FRAMES, sizeof(zephir_memory_entry), 1); /* pecalloc() will take care of these members for every frame start->pointer = 0; start->hash_pointer = 0; start->prev = NULL; start->next = NULL; */ for (i = 0; i < ZEPHIR_NUM_PREALLOCATED_FRAMES; ++i) { start[i].addresses = pecalloc(24, sizeof(zval*), 1); start[i].capacity = 24; start[i].hash_addresses = pecalloc(8, sizeof(zval*), 1); start[i].hash_capacity = 8; #ifndef ZEPHIR_RELEASE start[i].permanent = 1; #endif } start[0].next = &start[1]; start[ZEPHIR_NUM_PREALLOCATED_FRAMES - 1].prev = &start[ZEPHIR_NUM_PREALLOCATED_FRAMES - 2]; for (i = 1; i < ZEPHIR_NUM_PREALLOCATED_FRAMES - 1; ++i) { start[i].next = &start[i + 1]; start[i].prev = &start[i - 1]; } zephir_globals_ptr->start_memory = start; zephir_globals_ptr->end_memory = start + ZEPHIR_NUM_PREALLOCATED_FRAMES; zephir_globals_ptr->fcache = pemalloc(sizeof(HashTable), 1); zend_hash_init(zephir_globals_ptr->fcache, 128, NULL, NULL, 1); // zephir_fcall_cache_dtor /* 'Allocator sizeof operand mismatch' warning can be safely ignored */ ALLOC_INIT_ZVAL(zephir_globals_ptr->global_null); Z_SET_REFCOUNT_P(zephir_globals_ptr->global_null, 2); /* 'Allocator sizeof operand mismatch' warning can be safely ignored */ ALLOC_INIT_ZVAL(zephir_globals_ptr->global_false); Z_SET_REFCOUNT_P(zephir_globals_ptr->global_false, 2); ZVAL_FALSE(zephir_globals_ptr->global_false); /* 'Allocator sizeof operand mismatch' warning can be safely ignored */ ALLOC_INIT_ZVAL(zephir_globals_ptr->global_true); Z_SET_REFCOUNT_P(zephir_globals_ptr->global_true, 2); ZVAL_TRUE(zephir_globals_ptr->global_true); zephir_globals_ptr->initialized = 1; } /** * Cleans the function/method cache up */ int zephir_cleanup_fcache(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) { zephir_fcall_cache_entry **entry = (zephir_fcall_cache_entry**) pDest; zend_class_entry *scope; uint len = hash_key->nKeyLength; assert(hash_key->arKey != NULL); assert(hash_key->nKeyLength > 2 * sizeof(zend_class_entry**)); memcpy(&scope, &hash_key->arKey[(len -1) - 2 * sizeof(zend_class_entry**)], sizeof(zend_class_entry*)); /* #ifndef ZEPHIR_RELEASE { zend_class_entry *cls; memcpy(&cls, &hash_key->arKey[len - sizeof(zend_class_entry**)], sizeof(zend_class_entry*)); fprintf(stderr, "func: %s, cls: %s, scope: %s [%u]\n", (*entry)->f->common.function_name, (cls ? cls->name : "N/A"), (scope ? scope->name : "N/A"), (uint)(*entry)->times); } #endif */ #ifndef ZEPHIR_RELEASE if ((*entry)->f->type != ZEND_INTERNAL_FUNCTION || (scope && scope->type != ZEND_INTERNAL_CLASS)) { return ZEND_HASH_APPLY_REMOVE; } #else if ((*entry)->type != ZEND_INTERNAL_FUNCTION || (scope && scope->type != ZEND_INTERNAL_CLASS)) { return ZEND_HASH_APPLY_REMOVE; } #endif #if PHP_VERSION_ID >= 50400 if (scope && scope->type == ZEND_INTERNAL_CLASS && scope->info.internal.module->type != MODULE_PERSISTENT) { return ZEND_HASH_APPLY_REMOVE; } #else if (scope && scope->type == ZEND_INTERNAL_CLASS && scope->module->type != MODULE_PERSISTENT) { return ZEND_HASH_APPLY_REMOVE; } #endif return ZEND_HASH_APPLY_KEEP; } /** * Deinitializes all the memory allocated by Zephir */ void zephir_deinitialize_memory(TSRMLS_D) { size_t i; zend_zephir_globals_def *zephir_globals_ptr = ZEPHIR_VGLOBAL; if (zephir_globals_ptr->initialized != 1) { zephir_globals_ptr->initialized = 0; return; } if (zephir_globals_ptr->start_memory != NULL) { zephir_clean_restore_stack(TSRMLS_C); } zend_hash_apply_with_arguments(zephir_globals_ptr->fcache TSRMLS_CC, zephir_cleanup_fcache, 0); #ifndef ZEPHIR_RELEASE assert(zephir_globals_ptr->start_memory != NULL); #endif for (i = 0; i < ZEPHIR_NUM_PREALLOCATED_FRAMES; ++i) { pefree(zephir_globals_ptr->start_memory[i].hash_addresses, 1); pefree(zephir_globals_ptr->start_memory[i].addresses, 1); } pefree(zephir_globals_ptr->start_memory, 1); zephir_globals_ptr->start_memory = NULL; zend_hash_destroy(zephir_globals_ptr->fcache); pefree(zephir_globals_ptr->fcache, 1); zephir_globals_ptr->fcache = NULL; for (i = 0; i < 2; i++) { zval_ptr_dtor(&zephir_globals_ptr->global_null); zval_ptr_dtor(&zephir_globals_ptr->global_false); zval_ptr_dtor(&zephir_globals_ptr->global_true); } zephir_globals_ptr->initialized = 0; } ZEPHIR_ATTR_NONNULL static void zephir_reallocate_memory(const zend_zephir_globals_def *g) { zephir_memory_entry *frame = g->active_memory; int persistent = (frame >= g->start_memory && frame < g->end_memory); void *buf = perealloc(frame->addresses, sizeof(zval **) * (frame->capacity + 16), persistent); if (EXPECTED(buf != NULL)) { frame->capacity += 16; frame->addresses = buf; } else { zend_error(E_CORE_ERROR, "Memory allocation failed"); } #ifndef ZEPHIR_RELEASE assert(frame->permanent == persistent); #endif } ZEPHIR_ATTR_NONNULL static void zephir_reallocate_hmemory(const zend_zephir_globals_def *g) { zephir_memory_entry *frame = g->active_memory; int persistent = (frame >= g->start_memory && frame < g->end_memory); void *buf = perealloc(frame->hash_addresses, sizeof(zval **) * (frame->hash_capacity + 4), persistent); if (EXPECTED(buf != NULL)) { frame->hash_capacity += 4; frame->hash_addresses = buf; } else { zend_error(E_CORE_ERROR, "Memory allocation failed"); } #ifndef ZEPHIR_RELEASE assert(frame->permanent == persistent); #endif } ZEPHIR_ATTR_NONNULL1(2) static inline void zephir_do_memory_observe(zval **var, const zend_zephir_globals_def *g) { zephir_memory_entry *frame = g->active_memory; #ifndef ZEPHIR_RELEASE if (UNEXPECTED(frame == NULL)) { fprintf(stderr, "ZEPHIR_MM_GROW() must be called before using any of MM functions or macros!"); zephir_print_backtrace(); abort(); } #endif if (UNEXPECTED(frame->pointer == frame->capacity)) { zephir_reallocate_memory(g); } #ifndef ZEPHIR_RELEASE { size_t i; for (i = 0; i < frame->pointer; ++i) { if (frame->addresses[i] == var) { fprintf(stderr, "Variable %p is already observed", var); zephir_print_backtrace(); abort(); } } } #endif frame->addresses[frame->pointer] = var; ++frame->pointer; } /** * Observes a memory pointer to release its memory at the end of the request */ void ZEND_FASTCALL zephir_memory_observe(zval **var TSRMLS_DC) { zend_zephir_globals_def *g = ZEPHIR_VGLOBAL; zephir_do_memory_observe(var, g); *var = NULL; /* In case an exception or error happens BEFORE the observed variable gets initialized */ } /** * Observes a variable and allocates memory for it */ void ZEND_FASTCALL zephir_memory_alloc(zval **var TSRMLS_DC) { zend_zephir_globals_def *g = ZEPHIR_VGLOBAL; zephir_do_memory_observe(var, g); ALLOC_INIT_ZVAL(*var); } /** * Releases memory for an allocated zval */ void ZEND_FASTCALL zephir_ptr_dtor(zval **var) { if (!Z_ISREF_PP(var) || Z_TYPE_PP(var) == IS_OBJECT) { zval_ptr_dtor(var); } else { if (Z_REFCOUNT_PP(var) == 0) { efree(*var); } else { Z_DELREF_PP(var); if (Z_REFCOUNT_PP(var) == 0) { efree(*var); } } } } /** * Releases memory for an allocated zval */ void ZEND_FASTCALL zephir_dtor(zval *var) { if (!Z_ISREF_P(var)) { zval_dtor(var); } } /** * Observes a variable and allocates memory for it * Marks hash key zvals to be nulled before freeing */ void ZEND_FASTCALL zephir_memory_alloc_pnull(zval **var TSRMLS_DC) { zend_zephir_globals_def *g = ZEPHIR_VGLOBAL; zephir_memory_entry *active_memory = g->active_memory; #ifndef ZEPHIR_RELEASE if (UNEXPECTED(active_memory == NULL)) { fprintf(stderr, "ZEPHIR_MM_GROW() must be called before using any of MM functions or macros!"); zephir_print_backtrace(); abort(); } #endif zephir_do_memory_observe(var, g); ALLOC_INIT_ZVAL(*var); if (active_memory->hash_pointer == active_memory->hash_capacity) { zephir_reallocate_hmemory(g); } active_memory->hash_addresses[active_memory->hash_pointer] = var; ++active_memory->hash_pointer; } /** * Removes a memory pointer from the active memory pool */ void ZEND_FASTCALL zephir_memory_remove(zval **var TSRMLS_DC) { zval_ptr_dtor(var); *var = NULL; } /** * Cleans the zephir memory stack recursivery */ int ZEND_FASTCALL zephir_clean_restore_stack(TSRMLS_D) { zend_zephir_globals_def *zephir_globals_ptr = ZEPHIR_VGLOBAL; while (zephir_globals_ptr->active_memory != NULL) { zephir_memory_restore_stack_common(zephir_globals_ptr TSRMLS_CC); } return SUCCESS; } /** * Copies a variable only if its refcount is greater than 1 */ void ZEND_FASTCALL zephir_copy_ctor(zval *destination, zval *origin) { if (Z_REFCOUNT_P(origin) > 1) { zval_copy_ctor(destination); } else { ZVAL_NULL(origin); } } /** * Creates virtual symbol tables dynamically */ void zephir_create_symbol_table(TSRMLS_D) { zephir_symbol_table *entry; zend_zephir_globals_def *zephir_globals_ptr = ZEPHIR_VGLOBAL; HashTable *symbol_table; #ifndef ZEPHIR_RELEASE if (!zephir_globals_ptr->active_memory) { fprintf(stderr, "ERROR: Trying to create a virtual symbol table without a memory frame"); zephir_print_backtrace(); return; } #endif entry = (zephir_symbol_table *) emalloc(sizeof(zephir_symbol_table)); entry->scope = zephir_globals_ptr->active_memory; entry->symbol_table = EG(active_symbol_table); entry->prev = zephir_globals_ptr->active_symbol_table; zephir_globals_ptr->active_symbol_table = entry; ALLOC_HASHTABLE(symbol_table); zend_hash_init(symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0); EG(active_symbol_table) = symbol_table; } /** * Restores all the virtual symbol tables */ void zephir_clean_symbol_tables(TSRMLS_D) { /*unsigned int i; if (ZEPHIR_GLOBAL(symbol_tables)) { for (i = ZEPHIR_GLOBAL(number_symbol_tables); i > 0; i--) { EG(active_symbol_table) = ZEPHIR_GLOBAL(symbol_tables)[i - 1]; } efree(ZEPHIR_GLOBAL(symbol_tables)); ZEPHIR_GLOBAL(symbol_tables) = NULL; }*/ } /** * Exports symbols to the active symbol table */ int zephir_set_symbol(zval *key_name, zval *value TSRMLS_DC) { if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } if (EG(active_symbol_table)) { if (Z_TYPE_P(key_name) == IS_STRING) { Z_ADDREF_P(value); zend_hash_update(EG(active_symbol_table), Z_STRVAL_P(key_name), Z_STRLEN_P(key_name) + 1, &value, sizeof(zval *), NULL); if (EG(exception)) { return FAILURE; } } } return SUCCESS; } /** * Exports a string symbol to the active symbol table */ int zephir_set_symbol_str(char *key_name, unsigned int key_length, zval *value TSRMLS_DC) { if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } if (&EG(symbol_table)) { Z_ADDREF_P(value); zend_hash_update(&EG(symbol_table), key_name, key_length, &value, sizeof(zval *), NULL); if (EG(exception)) { return FAILURE; } } return SUCCESS; } static inline void zephir_dtor_func(zval *zvalue ZEND_FILE_LINE_DC) { switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) { case IS_STRING: case IS_CONSTANT: CHECK_ZVAL_STRING_REL(zvalue); STR_FREE_REL(zvalue->value.str.val); break; #if PHP_VERSION_ID < 50600 case IS_CONSTANT_ARRAY: #endif case IS_ARRAY: { TSRMLS_FETCH(); if (zvalue->value.ht && (zvalue->value.ht != &EG(symbol_table))) { /* break possible cycles */ Z_TYPE_P(zvalue) = IS_NULL; zend_hash_destroy(zvalue->value.ht); FREE_HASHTABLE(zvalue->value.ht); } } break; case IS_OBJECT: { TSRMLS_FETCH(); Z_OBJ_HT_P(zvalue)->del_ref(zvalue TSRMLS_CC); } break; case IS_RESOURCE: { TSRMLS_FETCH(); zend_list_delete(zvalue->value.lval); } break; case IS_LONG: case IS_DOUBLE: case IS_BOOL: case IS_NULL: default: return; break; } } void zephir_value_dtor(zval *zvalue ZEND_FILE_LINE_DC) { if (zvalue->type <= IS_BOOL) { return; } zephir_dtor_func(zvalue ZEND_FILE_LINE_RELAY_CC); }