-
-
Save krakjoe/9c11289b3f8ff64a6c0c64d3b8bbc02c to your computer and use it in GitHub Desktop.
reload
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dnl config.m4 for extension reload | |
PHP_ARG_ENABLE([reload], | |
[whether to enable reload support], | |
[AS_HELP_STRING([--enable-reload], | |
[Enable reload support])], | |
[no]) | |
if test "$PHP_RELOAD" != "no"; then | |
AC_DEFINE(HAVE_RELOAD, 1, [ Have reload support ]) | |
PHP_NEW_EXTENSION(reload, reload.c, $ext_shared) | |
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* reload extension for PHP */ | |
#ifndef PHP_RELOAD_H | |
# define PHP_RELOAD_H | |
extern zend_module_entry reload_module_entry; | |
# define phpext_reload_ptr &reload_module_entry | |
# define PHP_RELOAD_VERSION "0.1.0" | |
# if defined(ZTS) && defined(COMPILE_DL_RELOAD) | |
ZEND_TSRMLS_CACHE_EXTERN() | |
# endif | |
#endif /* PHP_RELOAD_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
+----------------------------------------------------------------------+ | |
| PHP Version 7 | | |
+----------------------------------------------------------------------+ | |
| Copyright (c) The PHP Group | | |
+----------------------------------------------------------------------+ | |
| This source file is subject to version 3.01 of the PHP license, | | |
| that is bundled with this package in the file LICENSE, and is | | |
| available through the world-wide-web at the following url: | | |
| https://php.net/license/3_01.txt | | |
| If you did not receive a copy of the PHP license and are unable to | | |
| obtain it through the world-wide-web, please send a note to | | |
| license@php.net so we can mail you a copy immediately. | | |
+----------------------------------------------------------------------+ | |
| Author: krakjoe | | |
+----------------------------------------------------------------------+ | |
*/ | |
#ifdef HAVE_CONFIG_H | |
# include "config.h" | |
#endif | |
#include "php.h" | |
#include "ext/standard/info.h" | |
#include "php_reload.h" | |
#include "zend_closures.h" | |
typedef struct _zend_closure_t { | |
zend_object std; | |
zend_function func; | |
zval this_ptr; | |
zend_class_entry *called_scope; | |
#if PHP_VERSION_ID <= 70200 | |
void (*orig_internal_handler)(INTERNAL_FUNCTION_PARAMETERS); | |
#else | |
zif_handler orig_internal_handler; | |
#endif | |
} zend_closure_t; | |
typedef struct _php_reload_tables_t { | |
HashTable *classes; | |
HashTable *functions; | |
} php_reload_tables_t; | |
static zend_always_inline int php_reload_include(php_reload_tables_t *tables, zval *filename, zval *return_value) { | |
php_reload_tables_t backup; | |
zend_op_array *ops; | |
zend_fcall_info fci = empty_fcall_info; | |
zend_fcall_info_cache fcc = empty_fcall_info_cache; | |
ALLOC_HASHTABLE(tables->classes); | |
zend_hash_init(tables->classes, 8, NULL, NULL, 0); | |
ALLOC_HASHTABLE(tables->functions); | |
zend_hash_init(tables->functions, 8, NULL, NULL, 0); | |
backup.classes = CG(class_table); | |
backup.functions = CG(function_table); | |
CG(class_table) = tables->classes; | |
CG(function_table) = tables->functions; | |
ops = compile_filename(ZEND_INCLUDE, filename); | |
CG(class_table) = backup.classes; | |
CG(function_table) = backup.functions; | |
if (!ops) { | |
zend_hash_destroy(tables->classes); | |
zend_hash_destroy(tables->functions); | |
FREE_HASHTABLE(tables->classes); | |
FREE_HASHTABLE(tables->functions); | |
return FAILURE; | |
} | |
fci.size = sizeof(zend_fcall_info); | |
fci.retval = return_value; | |
fcc.function_handler = (zend_function*) ops; | |
ZEND_MAP_PTR_INIT(ops->run_time_cache, ecalloc(1, ops->cache_size)); | |
if (zend_call_function(&fci, &fcc) != SUCCESS) { | |
zend_hash_destroy(tables->classes); | |
zend_hash_destroy(tables->functions); | |
FREE_HASHTABLE(tables->classes); | |
FREE_HASHTABLE(tables->functions); | |
return FAILURE; | |
} | |
destroy_op_array(ops); | |
efree(ops); | |
return SUCCESS; | |
} | |
static zend_always_inline void php_reload_relink(zend_objects_store *objects, zend_class_entry *replaced, zend_class_entry *ce) { | |
if (objects->top > 1) { | |
uint32_t it = 1, | |
end = objects->top; | |
while (it < end) { | |
zend_object *object = objects->object_buckets[it]; | |
if (IS_OBJ_VALID(object)) { | |
if (object->ce == replaced) { | |
object->ce = ce; | |
} else if (instanceof_function(object->ce, zend_ce_closure)) { | |
zend_closure_t *closure = (zend_closure_t*) object; | |
if (RUN_TIME_CACHE(&closure->func.op_array)) { | |
memset(RUN_TIME_CACHE(&closure->func.op_array), 0, closure->func.op_array.cache_size); | |
} | |
if (closure->called_scope == replaced) { | |
closure->called_scope = ce; | |
} | |
} | |
} | |
it++; | |
} | |
} | |
} | |
static zend_always_inline void php_reload_classes(HashTable *classes) { | |
zend_string *key; | |
zend_class_entry *ce, *edit; | |
zend_ulong address; | |
HashTable replaced; | |
zend_hash_init(&replaced, 8, NULL, NULL, 0); | |
ZEND_HASH_FOREACH_STR_KEY_PTR(classes, key, ce) { | |
zend_class_entry *old = zend_hash_find_ptr(CG(class_table), key); | |
if (!old) { | |
zend_hash_add_ptr(CG(class_table), key, ce); | |
} else { | |
zend_hash_index_update_ptr( | |
&replaced, (zend_ulong) old, ce); | |
/* TODO verify interface of new class matches old class */ | |
zend_hash_update_ptr(CG(class_table), key, ce); | |
} | |
} ZEND_HASH_FOREACH_END(); | |
ZEND_HASH_FOREACH_NUM_KEY_PTR(&replaced, address, ce) { | |
zend_class_entry *replaced = (zend_class_entry*) address; | |
zend_function *method; | |
ZEND_HASH_FOREACH_PTR(CG(class_table), edit) { | |
if (edit->parent == replaced) { | |
edit->parent = ce; | |
} | |
/* TODO interfaces, traits ? */ | |
ZEND_HASH_FOREACH_PTR(&edit->function_table, method) { | |
zend_arg_info *info, | |
*end; | |
if (method->common.scope == replaced) { | |
method->common.scope = ce; | |
} | |
if (ZEND_USER_CODE(method->type)) { | |
if (RUN_TIME_CACHE(&method->op_array)) { | |
memset( | |
RUN_TIME_CACHE(&method->op_array), | |
0, | |
method->op_array.cache_size); | |
} | |
} | |
info = method->common.arg_info; | |
if (method->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { | |
info--; | |
} | |
end = method->common.arg_info + method->common.num_args; | |
if (method->common.fn_flags & ZEND_ACC_VARIADIC) { | |
end++; | |
} | |
while (info < end) { | |
if (ZEND_TYPE_IS_SET(info->type) && ZEND_TYPE_IS_CLASS(info->type)) { | |
zend_string *name = ZEND_TYPE_IS_NAME(info->type) ? | |
ZEND_TYPE_NAME(info->type) : | |
ZEND_TYPE_CE(info->type)->name; | |
if (zend_string_equals_ci(name, replaced->name)) { | |
info->type = ZEND_TYPE_ENCODE_CLASS( | |
replaced->name, | |
ZEND_TYPE_ALLOW_NULL(info->type)); | |
} | |
} | |
info++; | |
} | |
} ZEND_HASH_FOREACH_END(); | |
} ZEND_HASH_FOREACH_END(); | |
php_reload_relink(&EG(objects_store), replaced, ce); | |
} ZEND_HASH_FOREACH_END(); | |
zend_hash_destroy(&replaced); | |
} | |
static zend_always_inline void php_reload_functions(HashTable *functions) { | |
/* unimplemented */ | |
} | |
/* {{{ void reload(string file) | |
*/ | |
PHP_FUNCTION(reload) | |
{ | |
zval *file; | |
php_reload_tables_t tables; | |
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &file) != SUCCESS) { | |
return; | |
} | |
if (!file || Z_TYPE_P(file) != IS_STRING) { | |
return; | |
} | |
if (php_reload_include(&tables, file, return_value) != SUCCESS) { | |
return; | |
} | |
php_reload_classes(tables.classes); | |
php_reload_functions(tables.functions); | |
zend_hash_destroy(tables.classes); | |
FREE_HASHTABLE(tables.classes); | |
zend_hash_destroy(tables.functions); | |
FREE_HASHTABLE(tables.functions); | |
} | |
/* }}} */ | |
/* {{{ PHP_RINIT_FUNCTION | |
*/ | |
PHP_RINIT_FUNCTION(reload) | |
{ | |
#if defined(ZTS) && defined(COMPILE_DL_RELOAD) | |
ZEND_TSRMLS_CACHE_UPDATE(); | |
#endif | |
return SUCCESS; | |
} | |
/* }}} */ | |
/* {{{ PHP_MINFO_FUNCTION | |
*/ | |
PHP_MINFO_FUNCTION(reload) | |
{ | |
php_info_print_table_start(); | |
php_info_print_table_header(2, "reload support", "enabled"); | |
php_info_print_table_end(); | |
} | |
/* }}} */ | |
/* {{{ arginfo | |
*/ | |
ZEND_BEGIN_ARG_INFO_EX(reload_arginfo, 0, 0, 1) | |
ZEND_ARG_INFO(0, file) | |
ZEND_END_ARG_INFO() | |
/* }}} */ | |
/* {{{ reload_functions[] | |
*/ | |
static const zend_function_entry reload_functions[] = { | |
PHP_FE(reload, reload_arginfo) | |
PHP_FE_END | |
}; | |
/* }}} */ | |
/* {{{ reload_module_entry | |
*/ | |
zend_module_entry reload_module_entry = { | |
STANDARD_MODULE_HEADER, | |
"reload", /* Extension name */ | |
reload_functions, /* zend_function_entry */ | |
NULL, /* PHP_MINIT - Module initialization */ | |
NULL, /* PHP_MSHUTDOWN - Module shutdown */ | |
PHP_RINIT(reload), /* PHP_RINIT - Request initialization */ | |
NULL, /* PHP_RSHUTDOWN - Request shutdown */ | |
PHP_MINFO(reload), /* PHP_MINFO - Module info */ | |
PHP_RELOAD_VERSION, /* Version */ | |
STANDARD_MODULE_PROPERTIES | |
}; | |
/* }}} */ | |
#ifdef COMPILE_DL_RELOAD | |
# ifdef ZTS | |
ZEND_TSRMLS_CACHE_DEFINE() | |
# endif | |
ZEND_GET_MODULE(reload) | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment