php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #52144
Patch tracing_modified_functions_classes.patch revision 2012-11-08 14:32 UTC by laruence@php.net
Patch bug52144_new.patch revision 2012-11-07 10:58 UTC by laruence@php.net
revision 2012-11-07 07:03 UTC by laruence@php.net
Patch autofilter_missing_funcs.patch revision 2012-11-03 14:59 UTC by gopalv@php.net
Patch auto_filter_on_missing_lambdas.patch revision 2012-11-02 12:18 UTC by gopalv@php.net
Patch bug52144.patch revision 2012-11-02 04:32 UTC by laruence@php.net
revision 2012-11-01 03:10 UTC by laruence@php.net

Patch tracing_modified_functions_classes.patch for APC Bug #52144

Patch version 2012-11-08 14:32 UTC

Return to Bug #52144 | Download this patch
This patch renders other patches obsolete

Obsolete patches:

Patch Revisions:

Developer: laruence@php.net

Index: apc_main.c
===================================================================
--- apc_main.c	(revision 328266)
+++ apc_main.c	(working copy)
@@ -361,30 +361,96 @@
 }
 /* }}} */
 
+/* {{{ void apc_compiler_func_table_dtor_hook(void *pDest) */
+void apc_compiler_func_table_dtor_hook(void *pDest) {
+    zend_function *func = (zend_function *)pDest;
+    if (func->type == ZEND_USER_FUNCTION) {
+        function_add_ref(func);
+        zend_hash_next_index_insert(APCG(compiler_hook_func_table), func, sizeof(zend_function), NULL);
+    } 
+    return zend_function_dtor(func);
+}
+/* }}} */
+
+/* {{{ void apc_compiler_class_table_dtor_hook(void *pDest) */
+void apc_compiler_class_table_dtor_hook(void *pDest) {
+    zend_class_entry **pce = (zend_class_entry **)pDest;
+
+    if ((*pce)->type == ZEND_USER_CLASS) {
+        ++(*pce)->refcount;
+        zend_hash_next_index_insert(APCG(compiler_hook_class_table), pce, sizeof(zend_class_entry *), NULL);
+    }
+    return destroy_zend_class(pce);
+}
+/* }}} */
+
+/* {{{ UNLOAD_COMPILER_TABLES_HOOKS() 
+ */
+#define UNLOAD_COMPILER_TABLES_HOOKS() \
+    do { \
+        zend_hash_destroy(APCG(compiler_hook_func_table)); \
+        FREE_HASHTABLE(APCG(compiler_hook_func_table));  \
+        zend_hash_destroy(APCG(compiler_hook_class_table)); \
+        FREE_HASHTABLE(APCG(compiler_hook_class_table));  \
+        APCG(compiler_hook_func_table) = old_hook_func_table; \
+        APCG(compiler_hook_class_table) = old_hook_class_table; \
+        if (!(--APCG(compile_nesting))) { \
+            CG(class_table)->pDestructor = ZEND_CLASS_DTOR; \
+            CG(function_table)->pDestructor = ZEND_FUNCTION_DTOR; \
+        } \
+    } while (0);
+/* }}} */
+
 /* {{{ apc_compile_cache_entry  */
 zend_bool apc_compile_cache_entry(apc_cache_key_t *key, zend_file_handle* h, int type, time_t t, zend_op_array** op_array, apc_cache_entry_t** cache_entry TSRMLS_DC) {
-    int num_functions, num_classes;
+    int num_functions, num_classes, modified_functions, modified_classes;
     apc_function_t* alloc_functions;
     zend_op_array* alloc_op_array;
     apc_class_t* alloc_classes;
     char *path;
     apc_context_t ctxt;
+    HashTable *old_hook_class_table = NULL, *old_hook_func_table = NULL;
 
+    if (!(APCG(compile_nesting)++)) {
+        CG(function_table)->pDestructor = apc_compiler_func_table_dtor_hook;
+        CG(class_table)->pDestructor = apc_compiler_class_table_dtor_hook;
+    }
+
+    if (APCG(compiler_hook_func_table)) {
+        old_hook_func_table = APCG(compiler_hook_func_table);
+    }
+
+    if (APCG(compiler_hook_class_table)) {
+        old_hook_class_table = APCG(compiler_hook_class_table);
+    }
+
+    ALLOC_HASHTABLE(APCG(compiler_hook_func_table));
+    zend_hash_init(APCG(compiler_hook_func_table), 8, NULL, ZEND_FUNCTION_DTOR, 0);
+    ALLOC_HASHTABLE(APCG(compiler_hook_class_table));
+    zend_hash_init(APCG(compiler_hook_class_table), 8, NULL, ZEND_CLASS_DTOR, 0);
+
     /* remember how many functions and classes existed before compilation */
     num_functions = zend_hash_num_elements(CG(function_table));
     num_classes   = zend_hash_num_elements(CG(class_table));
 
-    /* compile the file using the default compile function,  *
-     * we set *op_array here so we return opcodes during     *
-     * a failure.  We should not return prior to this line.  */
-    *op_array = old_compile_file(h, type TSRMLS_CC);
-    if (*op_array == NULL) {
-        return FAILURE;
-    }
+    zend_try {
+        /* compile the file using the default compile function,  *
+         * we set *op_array here so we return opcodes during     *
+         * a failure.  We should not return prior to this line.  */
+        *op_array = old_compile_file(h, type TSRMLS_CC);
+        if (*op_array == NULL) {
+            UNLOAD_COMPILER_TABLES_HOOKS();
+            return FAILURE;
+        }
+    } zend_catch {
+        UNLOAD_COMPILER_TABLES_HOOKS();
+        zend_bailout();
+    } zend_end_try();
 
     ctxt.pool = apc_pool_create(APC_MEDIUM_POOL, apc_sma_malloc, apc_sma_free, 
                                                  apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
     if (!ctxt.pool) {
+        UNLOAD_COMPILER_TABLES_HOOKS();
         apc_warning("Unable to allocate memory for pool." TSRMLS_CC);
         return FAILURE;
     }
@@ -429,6 +495,18 @@
         goto freepool;
     }
 
+    if (zend_hash_num_elements(APCG(compiler_hook_func_table)) 
+            && !(alloc_functions = apc_copy_modified_functions(APCG(compiler_hook_func_table),
+                    alloc_functions, num_functions, &ctxt TSRMLS_CC))) {
+        goto freepool;
+    }
+
+    if (zend_hash_num_elements(APCG(compiler_hook_class_table)) 
+            && !(alloc_classes = apc_copy_modified_classes(APCG(compiler_hook_class_table),
+                    alloc_classes, num_classes, &ctxt TSRMLS_CC))) {
+        goto freepool;
+    }
+
     path = h->opened_path;
     if(!path && key->type == APC_CACHE_KEY_FPFILE) path = (char*)key->data.fpfile.fullpath;
     if(!path) path=h->filename;
@@ -438,10 +516,12 @@
     if(!(*cache_entry = apc_cache_make_file_entry(path, alloc_op_array, alloc_functions, alloc_classes, &ctxt TSRMLS_CC))) {
         goto freepool;
     }
-
+        
+    UNLOAD_COMPILER_TABLES_HOOKS();
     return SUCCESS;
 
 freepool:
+    UNLOAD_COMPILER_TABLES_HOOKS();
     apc_pool_destroy(ctxt.pool TSRMLS_CC);
     ctxt.pool = NULL;
 
Index: apc_compile.c
===================================================================
--- apc_compile.c	(revision 328266)
+++ apc_compile.c	(working copy)
@@ -1452,7 +1452,7 @@
     int new_count;              /* number of new functions in table */
     int i;
     apc_pool* pool = ctxt->pool;
-
+    
     new_count = zend_hash_num_elements(CG(function_table)) - old_count;
     assert(new_count >= 0);
 
@@ -1497,6 +1497,47 @@
 }
 /* }}} */
 
+/* {{{ apc_copy_modified_functions */
+apc_function_t * apc_copy_modified_functions(HashTable *funcs, apc_function_t *alloc_functions, int num_functions, apc_context_t *ctxt TSRMLS_DC) {
+    HashPosition pos;
+    zend_function *func;
+    apc_function_t *array;
+    int modified_count = zend_hash_num_elements(funcs);
+    int index = zend_hash_num_elements(CG(function_table)) - num_functions;
+
+    CHECK(array = (apc_function_t*) apc_pool_alloc(ctxt->pool, (sizeof(apc_function_t) * (index + modified_count + 1))));
+    memcpy(array, alloc_functions, (sizeof(apc_function_t) * (index + 1)));
+
+    zend_hash_internal_pointer_reset_ex(CG(function_table), &pos);
+    while (zend_hash_get_current_data_ex(CG(function_table), (void **)&func, &pos) == SUCCESS) {
+        if (func->type == ZEND_USER_FUNCTION) {
+            char* key;
+            uint key_size;
+            HashPosition nPos;
+            zend_function *modified_func;
+
+            zend_hash_internal_pointer_reset_ex(funcs, &nPos);
+            while (zend_hash_get_current_data_ex(funcs, (void **)&modified_func, &nPos) == SUCCESS) {
+                /* there might be some functions share the same name */
+                if (modified_func->op_array.line_start == func->op_array.line_start
+                       && strcmp(modified_func->op_array.function_name, func->op_array.function_name) == 0) {
+                    zend_hash_get_current_key_ex(CG(function_table), &key, &key_size, NULL, 0, &pos);
+                    CHECK(array[index].name = apc_pmemcpy(key, (int) key_size, ctxt->pool TSRMLS_CC));
+                    array[index].name_len = (int) key_size-1;
+                    CHECK(array[index].function = my_copy_function(NULL, func, ctxt TSRMLS_CC));
+                    index++;
+                    break;
+                }
+                zend_hash_move_forward_ex(funcs, &nPos);
+            }
+        }
+        zend_hash_move_forward_ex(CG(function_table), &pos);
+    }
+    array[index].function = NULL;
+    return array;
+}
+/* }}} */
+
 /* {{{ apc_copy_new_classes */
 apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_context_t *ctxt TSRMLS_DC)
 {
@@ -1570,6 +1611,54 @@
 }
 /* }}} */
 
+/* {{{ apc_copy_modified_classes */
+apc_class_t * apc_copy_modified_classes(HashTable *classes, apc_class_t *alloc_classes, int num_classes, apc_context_t *ctxt TSRMLS_DC) {
+    HashPosition pos;
+    apc_class_t *array;
+    zend_class_entry **pce;
+    int modified_count = zend_hash_num_elements(classes);
+    int index = zend_hash_num_elements(CG(class_table)) - num_classes;
+
+    CHECK(array = (apc_class_t*) apc_pool_alloc(ctxt->pool, (sizeof(apc_class_t) * (index + modified_count + 1))));
+    memcpy(array, alloc_classes, (sizeof(apc_class_t) * (index + 1)));
+
+    zend_hash_internal_pointer_reset_ex(CG(class_table), &pos);
+    while (zend_hash_get_current_data_ex(CG(class_table), (void **)&pce, &pos) == SUCCESS) {
+        if ((*pce)->type == ZEND_USER_CLASS) {
+            char* key;
+            uint key_size;
+            HashPosition nPos;
+            zend_class_entry **modified_ce;
+
+            zend_hash_internal_pointer_reset_ex(classes, &nPos);
+            while (zend_hash_get_current_data_ex(classes, (void **)&modified_ce, &nPos) == SUCCESS) {
+                if (strncmp((*modified_ce)->name, (*pce)->name, (*pce)->name_length) == 0) {
+                    zend_hash_get_current_key_ex(CG(class_table), &key, &key_size, NULL, 0, &pos);
+                    /* only the compile-time class declaration is cared */
+                    if (key[0] != '\0') {
+                        break;
+                    }
+                    CHECK(array[index].name = apc_pmemcpy(key, (int) key_size, ctxt->pool TSRMLS_CC));
+                    array[index].name_len = (int) key_size-1;
+                    CHECK(array[index].class_entry = my_copy_class_entry(NULL, *pce, ctxt TSRMLS_CC));
+                    if ((*pce)->parent) {
+                        CHECK(array[index].parent_name = apc_pstrdup((*pce)->parent->name, ctxt->pool TSRMLS_CC));
+                    } else {
+                        array[index].parent_name = NULL;
+                    }
+                    index++;
+                    break;
+                }
+                zend_hash_move_forward_ex(classes, &nPos);
+            }
+        }
+        zend_hash_move_forward_ex(CG(class_table), &pos);
+    }
+    array[index].class_entry = NULL;
+    return array;
+}
+/* }}} */
+
 /* Used only by my_prepare_op_array_for_execution */
 #ifdef ZEND_ENGINE_2_4
 # define APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION()                                               \
Index: apc_compile.h
===================================================================
--- apc_compile.h	(revision 328266)
+++ apc_compile.h	(working copy)
@@ -91,7 +91,9 @@
 extern zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_context_t* ctxt TSRMLS_DC);
 extern zend_class_entry* apc_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_context_t* ctxt TSRMLS_DC);
 extern apc_function_t* apc_copy_new_functions(int old_count, apc_context_t* ctxt TSRMLS_DC);
+extern apc_function_t* apc_copy_modified_functions(HashTable *funcs, apc_function_t *alloc_functions, int num_functions, apc_context_t *ctxt TSRMLS_DC);
 extern apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_context_t* ctxt TSRMLS_DC);
+extern apc_class_t* apc_copy_modified_classes(HashTable *classes, apc_class_t *alloc_classes, int num_classes, apc_context_t *ctxt TSRMLS_DC);
 extern zval* apc_copy_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC);
 #ifdef ZEND_ENGINE_2_4
 extern zend_trait_alias* apc_copy_trait_alias(zend_trait_alias *dst, zend_trait_alias *src, apc_context_t *ctxt TSRMLS_DC);
Index: apc_globals.h
===================================================================
--- apc_globals.h	(revision 328266)
+++ apc_globals.h	(working copy)
@@ -124,6 +124,9 @@
 #endif
     char *serializer_name;       /* the serializer config option */
     apc_serializer_t *serializer;/* the actual serializer in use */
+    HashTable *compiler_hook_func_table;
+    HashTable *compiler_hook_class_table;
+    int compile_nesting;
 ZEND_END_MODULE_GLOBALS(apc)
 
 /* (the following declaration is defined in php_apc.c) */
Index: php_apc.c
===================================================================
--- php_apc.c	(revision 328266)
+++ php_apc.c	(working copy)
@@ -109,6 +109,9 @@
     apc_globals->lazy_function_table = NULL;
     apc_globals->serializer_name = NULL;
     apc_globals->serializer = NULL;
+    apc_globals->compiler_hook_func_table = NULL;
+    apc_globals->compiler_hook_class_table = NULL;
+    apc_globals->compile_nesting = 0;
 }
 
 static void php_apc_shutdown_globals(zend_apc_globals* apc_globals TSRMLS_DC)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 10:01:28 2024 UTC