php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | |
Patch tracing_modified_functions_classes.patch for APC Bug #52144Patch version 2012-11-08 14:32 UTC Return to Bug #52144 | Download this patchThis patch renders other patches obsolete Obsolete patches: Patch Revisions:Developer: laruence@php.netIndex: 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) |
Copyright © 2001-2024 The PHP Group All rights reserved. |
Last updated: Sat Nov 23 00:01:32 2024 UTC |