├── xmder ├── utils.go ├── go.mod ├── xmder_linux ├── types.go └── xmder.go ├── CREDITS ├── screwopcode_config.h ├── config.w32 ├── README.md ├── md5.h ├── zend_file_cache.h ├── zend_accelerator_module.h ├── zend_accelerator_debug.h ├── zend_persist.h ├── Optimizer ├── zend_dfg.h ├── zend_dump.h ├── zend_func_info.h ├── zend_call_graph.h ├── scdf.h ├── nop_removal.c ├── zend_worklist.h ├── compact_vars.c ├── zend_optimizer.h ├── zend_cfg.h ├── zend_optimizer_internal.h ├── optimize_temp_vars_5.c ├── pass2.c ├── zend_dfg.c ├── scdf.c ├── optimize_func_calls.c ├── zend_call_graph.c └── zend_ssa.h ├── zend_accelerator_util_funcs.h ├── zend_accelerator_blacklist.h ├── zend_accelerator_debug.c ├── shared_alloc_mmap.c ├── shared_alloc_posix.c ├── gensecretkey.sh ├── zend_accelerator_hash.h ├── shared_alloc_shm.c ├── aes.h ├── zend_shared_alloc.h ├── md5.c ├── zend_accelerator_hash.c ├── config.m4 ├── zend_accelerator_blacklist.c └── ZendAccelerator.h /xmder/utils.go: -------------------------------------------------------------------------------- 1 | package main -------------------------------------------------------------------------------- /xmder/go.mod: -------------------------------------------------------------------------------- 1 | module xmder 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /xmder/xmder_linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkcmf/screw-opcode/master/xmder/xmder_linux -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Opcache 2 | Andi Gutmans, Zeev Suraski, Stanislav Malyshev, Dmitry Stogov, Xinchen Hui 3 | -------------------------------------------------------------------------------- /screwopcode_config.h: -------------------------------------------------------------------------------- 1 | #define SCREWOPCODE_VERSION "v2.0.1" 2 | #define SCREWOPCODE_CACHE_ID "screwopcode_" SCREWOPCODE_VERSION "_cache" 3 | #define SCREWOPCODE_HEADER "" 4 | #define SCREWOPCODE_HEADER_LEN 30 -------------------------------------------------------------------------------- /xmder/types.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "time" 4 | 5 | var sourcepath string 6 | 7 | type cryptStats struct { 8 | TotalFiles int64 // 总数 9 | SuccessCryptedCount int64 // 成功加密数 10 | FailedCryptedCount int64 // 失败数 11 | TimeStart time.Time 12 | TimeEnd time.Time 13 | } -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | ARG_ENABLE("screwopcode", "whether to enable ScrewOpcode support", "yes"); 2 | 3 | ARG_ENABLE("screwopcode-file", "whether to enable file based caching", "yes"); 4 | 5 | /* var PHP_OPCACHE_PGO = false; */ 6 | 7 | if (PHP_OPCACHE != "no") { 8 | 9 | if (PHP_OPCACHE_FILE == "yes") { 10 | AC_DEFINE('HAVE_OPCACHE_FILE_CACHE', 1, 'Define to enable file based caching (experimental)'); 11 | } 12 | 13 | EXTENSION('screwopcode', "\ 14 | ZendAccelerator.c \ 15 | zend_accelerator_blacklist.c \ 16 | zend_accelerator_debug.c \ 17 | zend_accelerator_hash.c \ 18 | zend_accelerator_module.c \ 19 | zend_accelerator_util_funcs.c \ 20 | zend_persist.c \ 21 | zend_persist_calc.c \ 22 | zend_file_cache.c \ 23 | zend_shared_alloc.c \ 24 | shared_alloc_win32.c", true, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); 25 | 26 | ADD_SOURCES(configure_module_dirname + "/Optimizer", "zend_optimizer.c pass1_5.c pass2.c pass3.c optimize_func_calls.c block_pass.c optimize_temp_vars_5.c nop_removal.c compact_literals.c zend_cfg.c zend_dfg.c dfa_pass.c zend_ssa.c zend_inference.c zend_func_info.c zend_call_graph.c sccp.c scdf.c dce.c compact_vars.c zend_dump.c", "screwopcode", "OptimizerObj"); 27 | 28 | 29 | ADD_FLAG('CFLAGS_OPCACHE', "/I " + configure_module_dirname); 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # screw_opcode 2 | 基于opcache魔改进行php加密,在生成和读取opcode阶段进行加解密从而有效防止源码泄露。 3 | 4 | 已支持php版本 5 | php 7.2(master版本) 6 | php8.0 php-8.0分支 (https://github.com/del-xiong/screw-opcode/tree/php-8.0) 7 | 8 | # 安装 9 | 10 | 编译流程 11 | 1. 下载本程序并解压到某个目录并进入 12 | 2. 执行 **bash gensecretkey.sh** 生成随机安全密钥头文件 13 | 3. 执行php bin中的**phpize**自动生成扩展所需文件(如果你的php里没有可以去官网下载) 14 | 4. 执行 **./configure --with-php-config=[php config path]** 进行配置,[php config path]是你的php-config的绝对路径 15 | 5. 执行**make**生成扩展 modules/screwopcode.so 16 | 6. **make install**安装扩展或手动把扩展路径加入php.ini中 重启php 17 | ``` 18 | 注意由于是zend插件,需要用zend_extension来载入 19 | zend_extension=/path/to/screwopcode.so 20 | ``` 21 | 7. 新建opcode缓存目录(假设为/tmp/opcodes)并修改php.ini配置文件,添加以下配置 22 | ``` 23 | [screwopcode] 24 | screwopcode.enable = 1 25 | screwopcode.file_cache=/tmp/opcodes 26 | screwopcode.file_cache_only=0 27 | screwopcode.file_override_enabled=0 28 | screwopcode.enable_cli=1 29 | screwopcode.jit=0 30 | screwopcode.validate_timestamps=0 31 | ``` 32 | 8. 执行php -m 确认[Zend Modules]中包含ScrewOpcode说开插件加载成功 33 | 34 | **/tmp/opcodes 是opcode加密缓存目录 可以自定义到其他目录,必须先创建目录否则可能出错** 35 | 36 | # 如何使用 37 | 插件安装成功后,运行php的时候会自动生成opcode缓存并移除源代码,下次执行相同文件直接从opcode加载。 38 | 你也可以在项目发布前使用小工具手动批量加密,进入xmder目录并执行 ./xmder -p [你的源码目录] 即可(目前还未添加并发处理所以速度可能会比较慢) 39 | 40 | # 项目持续升级中 企鹅群 530887505 41 | -------------------------------------------------------------------------------- /md5.h: -------------------------------------------------------------------------------- 1 | #ifndef MD5_H 2 | #define MD5_H 3 | 4 | typedef struct { 5 | unsigned int count[2]; 6 | unsigned int state[4]; 7 | unsigned char buffer[64]; 8 | } MD5_CTX; 9 | 10 | 11 | #define F(x, y, z) ((x & y) | (~x & z)) 12 | #define G(x, y, z) ((x & z) | (y & ~z)) 13 | #define H(x, y, z) (x^y^z) 14 | #define I(x, y, z) (y ^ (x | ~z)) 15 | #define ROTATE_LEFT(x, n) ((x << n) | (x >> (32-n))) 16 | #define FF(a, b, c, d, x, s, ac) \ 17 | { \ 18 | a += F(b,c,d) + x + ac; \ 19 | a = ROTATE_LEFT(a,s); \ 20 | a += b; \ 21 | } 22 | #define GG(a, b, c, d, x, s, ac) \ 23 | { \ 24 | a += G(b,c,d) + x + ac; \ 25 | a = ROTATE_LEFT(a,s); \ 26 | a += b; \ 27 | } 28 | #define HH(a, b, c, d, x, s, ac) \ 29 | { \ 30 | a += H(b,c,d) + x + ac; \ 31 | a = ROTATE_LEFT(a,s); \ 32 | a += b; \ 33 | } 34 | #define II(a, b, c, d, x, s, ac) \ 35 | { \ 36 | a += I(b,c,d) + x + ac; \ 37 | a = ROTATE_LEFT(a,s); \ 38 | a += b; \ 39 | } 40 | 41 | void MD5Init(MD5_CTX *context); 42 | 43 | void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen); 44 | 45 | void MD5Final(MD5_CTX *context, unsigned char digest[16]); 46 | 47 | void MD5Transform(unsigned int state[4], unsigned char block[64]); 48 | 49 | void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len); 50 | 51 | void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len); 52 | 53 | char *md5(char *str); 54 | 55 | #endif 56 | 57 | #include "md5.c" -------------------------------------------------------------------------------- /zend_file_cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Dmitry Stogov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef ZEND_FILE_CACHE_H 20 | #define ZEND_FILE_CACHE_H 21 | 22 | int zend_file_cache_script_store(zend_persistent_script *script, int in_shm); 23 | zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle); 24 | void zend_file_cache_invalidate(zend_string *full_path); 25 | uint32_t screw_aes_128(int crypt, char *buf, uint8_t *key, int dataLen); 26 | 27 | #endif /* ZEND_FILE_CACHE_H */ 28 | -------------------------------------------------------------------------------- /zend_accelerator_module.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_ACCELERATOR_MODULE_H 23 | #define ZEND_ACCELERATOR_MODULE_H 24 | 25 | int start_accel_module(void); 26 | 27 | void zend_accel_override_file_functions(void); 28 | 29 | #endif /* _ZEND_ACCELERATOR_MODULE_H */ 30 | -------------------------------------------------------------------------------- /zend_accelerator_debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_ACCELERATOR_DEBUG_H 23 | #define ZEND_ACCELERATOR_DEBUG_H 24 | 25 | #define ACCEL_LOG_FATAL 0 26 | #define ACCEL_LOG_ERROR 1 27 | #define ACCEL_LOG_WARNING 2 28 | #define ACCEL_LOG_INFO 3 29 | #define ACCEL_LOG_DEBUG 4 30 | 31 | void zend_accel_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); 32 | 33 | #endif /* _ZEND_ACCELERATOR_DEBUG_H */ 34 | -------------------------------------------------------------------------------- /zend_persist.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_PERSIST_H 23 | #define ZEND_PERSIST_H 24 | 25 | int zend_accel_script_persistable(zend_persistent_script *script); 26 | uint32_t zend_accel_script_persist_calc(zend_persistent_script *script, char *key, unsigned int key_length, int for_shm); 27 | zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, char **key, unsigned int key_length, int for_shm); 28 | 29 | #endif /* ZEND_PERSIST_H */ 30 | -------------------------------------------------------------------------------- /Optimizer/zend_dfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, DFG - Data Flow Graph | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Dmitry Stogov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef ZEND_DFG_H 20 | #define ZEND_DFG_H 21 | 22 | #include "zend_bitset.h" 23 | #include "zend_cfg.h" 24 | 25 | typedef struct _zend_dfg { 26 | int vars; 27 | uint32_t size; 28 | zend_bitset tmp; 29 | zend_bitset def; 30 | zend_bitset use; 31 | zend_bitset in; 32 | zend_bitset out; 33 | } zend_dfg; 34 | 35 | #define DFG_BITSET(set, set_size, block_num) \ 36 | ((set) + ((block_num) * (set_size))) 37 | 38 | #define DFG_SET(set, set_size, block_num, var_num) \ 39 | zend_bitset_incl(DFG_BITSET(set, set_size, block_num), (var_num)) 40 | 41 | #define DFG_ISSET(set, set_size, block_num, var_num) \ 42 | zend_bitset_in(DFG_BITSET(set, set_size, block_num), (var_num)) 43 | 44 | BEGIN_EXTERN_C() 45 | 46 | int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg *dfg, uint32_t build_flags); 47 | 48 | END_EXTERN_C() 49 | 50 | #endif /* ZEND_DFG_H */ 51 | 52 | /* 53 | * Local variables: 54 | * tab-width: 4 55 | * c-basic-offset: 4 56 | * indent-tabs-mode: t 57 | * End: 58 | */ 59 | -------------------------------------------------------------------------------- /Optimizer/zend_dump.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, Bytecode Visualisation | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Dmitry Stogov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef ZEND_DUMP_H 20 | #define ZEND_DUMP_H 21 | 22 | #include "zend_ssa.h" 23 | #include "zend_dfg.h" 24 | 25 | #define ZEND_DUMP_HIDE_UNREACHABLE (1<<0) 26 | #define ZEND_DUMP_RC_INFERENCE (1<<1) 27 | #define ZEND_DUMP_CFG (1<<2) 28 | #define ZEND_DUMP_SSA (1<<3) 29 | #define ZEND_DUMP_RT_CONSTANTS ZEND_RT_CONSTANTS 30 | 31 | BEGIN_EXTERN_C() 32 | 33 | void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, const char *msg, const void *data); 34 | void zend_dump_dominators(const zend_op_array *op_array, const zend_cfg *cfg); 35 | void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zend_dfg *dfg); 36 | void zend_dump_phi_placement(const zend_op_array *op_array, const zend_ssa *ssa); 37 | void zend_dump_variables(const zend_op_array *op_array); 38 | void zend_dump_ssa_variables(const zend_op_array *op_array, const zend_ssa *ssa, uint32_t dump_flags); 39 | void zend_dump_var(const zend_op_array *op_array, zend_uchar var_type, int var_num); 40 | 41 | END_EXTERN_C() 42 | 43 | #endif /* ZEND_DUMP_H */ 44 | 45 | /* 46 | * Local variables: 47 | * tab-width: 4 48 | * c-basic-offset: 4 49 | * indent-tabs-mode: t 50 | * End: 51 | */ 52 | -------------------------------------------------------------------------------- /zend_accelerator_util_funcs.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_ACCELERATOR_UTIL_FUNCS_H 23 | #define ZEND_ACCELERATOR_UTIL_FUNCS_H 24 | 25 | #include "zend.h" 26 | #include "ZendAccelerator.h" 27 | 28 | void zend_accel_copy_internal_functions(void); 29 | 30 | zend_persistent_script *create_persistent_script(void); 31 | void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements); 32 | 33 | void zend_accel_free_user_functions(HashTable *ht); 34 | void zend_accel_move_user_functions(HashTable *str, HashTable *dst); 35 | 36 | zend_op_array *zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory); 37 | 38 | #define ADLER32_INIT 1 /* initial Adler-32 value */ 39 | 40 | unsigned int zend_adler32(unsigned int checksum, signed char *buf, uint32_t len); 41 | 42 | unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script); 43 | 44 | #endif /* ZEND_ACCELERATOR_UTIL_FUNCS_H */ 45 | 46 | /* 47 | * Local variables: 48 | * tab-width: 4 49 | * c-basic-offset: 4 50 | * End: 51 | */ 52 | -------------------------------------------------------------------------------- /zend_accelerator_blacklist.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_ACCELERATOR_BLACKLIST_H 23 | #define ZEND_ACCELERATOR_BLACKLIST_H 24 | 25 | typedef struct _zend_regexp_list zend_regexp_list; 26 | 27 | typedef struct _zend_blacklist_entry 28 | { 29 | char *path; 30 | int path_length; 31 | int id; 32 | } zend_blacklist_entry; 33 | 34 | typedef struct _zend_blacklist 35 | { 36 | zend_blacklist_entry *entries; 37 | int size; 38 | int pos; 39 | zend_regexp_list *regexp_list; 40 | } zend_blacklist; 41 | 42 | typedef int (*blacklist_apply_func_arg_t)(zend_blacklist_entry *, zval *); 43 | 44 | extern zend_blacklist accel_blacklist; 45 | 46 | void zend_accel_blacklist_init(zend_blacklist *blacklist); 47 | void zend_accel_blacklist_shutdown(zend_blacklist *blacklist); 48 | 49 | void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename); 50 | zend_bool zend_accel_blacklist_is_blacklisted(zend_blacklist *blacklist, char *verify_path); 51 | void zend_accel_blacklist_apply(zend_blacklist *blacklist, blacklist_apply_func_arg_t func, void *argument); 52 | 53 | #endif /* ZEND_ACCELERATOR_BLACKLIST_H */ 54 | -------------------------------------------------------------------------------- /Optimizer/zend_func_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, Func Info | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Dmitry Stogov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef ZEND_FUNC_INFO_H 20 | #define ZEND_FUNC_INFO_H 21 | 22 | #include "zend_ssa.h" 23 | 24 | /* func flags */ 25 | #define ZEND_FUNC_INDIRECT_VAR_ACCESS (1<<0) 26 | #define ZEND_FUNC_HAS_CALLS (1<<1) 27 | #define ZEND_FUNC_VARARG (1<<2) 28 | #define ZEND_FUNC_NO_LOOPS (1<<3) 29 | #define ZEND_FUNC_IRREDUCIBLE (1<<4) 30 | #define ZEND_FUNC_RECURSIVE (1<<7) 31 | #define ZEND_FUNC_RECURSIVE_DIRECTLY (1<<8) 32 | #define ZEND_FUNC_RECURSIVE_INDIRECTLY (1<<9) 33 | 34 | /* The following flags are valid only for return values of internal functions 35 | * returned by zend_get_func_info() 36 | */ 37 | #define FUNC_MAY_WARN (1<<30) 38 | 39 | typedef struct _zend_func_info zend_func_info; 40 | typedef struct _zend_call_info zend_call_info; 41 | 42 | #define ZEND_FUNC_INFO(op_array) \ 43 | ((zend_func_info*)((op_array)->reserved[zend_func_info_rid])) 44 | 45 | #define ZEND_SET_FUNC_INFO(op_array, info) do { \ 46 | zend_func_info** pinfo = (zend_func_info**)&(op_array)->reserved[zend_func_info_rid]; \ 47 | *pinfo = info; \ 48 | } while (0) 49 | 50 | BEGIN_EXTERN_C() 51 | 52 | extern int zend_func_info_rid; 53 | 54 | uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa); 55 | 56 | int zend_func_info_startup(void); 57 | int zend_func_info_shutdown(void); 58 | 59 | END_EXTERN_C() 60 | 61 | #endif /* ZEND_FUNC_INFO_H */ 62 | 63 | /* 64 | * Local variables: 65 | * tab-width: 4 66 | * c-basic-offset: 4 67 | * indent-tabs-mode: t 68 | * End: 69 | */ 70 | -------------------------------------------------------------------------------- /xmder/xmder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | "os/exec" 9 | "path" 10 | "path/filepath" 11 | "strings" 12 | "sync/atomic" 13 | "syscall" 14 | "time" 15 | ) 16 | var cmd *exec.Cmd 17 | 18 | const cryptedHeaderContent = "" 19 | 20 | func init() { 21 | 22 | flag.StringVar(&sourcepath,"p","","source code path") 23 | flag.Parse() 24 | if sourcepath == "" { 25 | log.Fatalln("source path not defined") 26 | } 27 | } 28 | 29 | func main() { 30 | stats := cryptStats{ 31 | TimeStart: time.Now(), 32 | } 33 | loopVisitEachFile(sourcepath, &stats) 34 | stats.TimeEnd = time.Now() 35 | stats.TotalFiles = stats.SuccessCryptedCount+stats.FailedCryptedCount 36 | log.Printf("total files(总文件数): %d\n", stats.TotalFiles) 37 | log.Printf("success crypted count(成功加密文件数): %d\n", stats.SuccessCryptedCount) 38 | log.Printf("failed crypted count(失败文件数): %d\n", stats.FailedCryptedCount) 39 | log.Printf("processing time(耗时): %.2fS\n", stats.TimeEnd.Sub(stats.TimeStart).Seconds()) 40 | } 41 | 42 | func loopVisitEachFile(dirpath string, stats *cryptStats) { 43 | filepath.Walk(dirpath, func(p string, f os.FileInfo, err error) error { 44 | if f == nil { 45 | return err 46 | } 47 | if !f.IsDir() && len(p) > 4 && strings.ToLower(p[len(p)-4:]) == ".php" { 48 | silentExecuteSourceFile(p, f, stats) 49 | } else if f.IsDir() { 50 | loopVisitEachFile(path.Join(dirpath, f.Name()), stats) 51 | return nil 52 | } 53 | return nil 54 | }) 55 | } 56 | 57 | func silentExecuteSourceFile(fPath string,fInfo os.FileInfo,stats *cryptStats) { 58 | // check if this file has been crypted or not 59 | // 先检查文件是否已加密 60 | if fInfo.Size() == int64(len(cryptedHeaderContent)) { 61 | b, err := os.ReadFile(fPath) 62 | if err ==nil && string(b) == cryptedHeaderContent { 63 | // crypted return 64 | fmt.Print(fPath+"...skip..√\n") 65 | atomic.AddInt64(&stats.SuccessCryptedCount, 1) 66 | return 67 | } 68 | } 69 | fmt.Print(fPath+"...") 70 | cmd = exec.Command(os.Getenv("SHELL"),"-c",fmt.Sprintf(`/usr/bin/php -r "screwopcode_compile_file('%s');"`, fPath)) 71 | cmd.SysProcAttr = &syscall.SysProcAttr{} 72 | uid, gid := GetFileGroupId(fInfo) 73 | cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid} 74 | b, err := cmd.CombinedOutput() 75 | fmt.Print("√\n") 76 | b2, err := os.ReadFile(fPath) 77 | if err != nil { 78 | atomic.AddInt64(&stats.FailedCryptedCount, 1) 79 | log.Fatalln(err) 80 | return 81 | } 82 | if string(b2) != cryptedHeaderContent { 83 | atomic.AddInt64(&stats.FailedCryptedCount, 1) 84 | log.Println(string(b)) 85 | } else { 86 | atomic.AddInt64(&stats.SuccessCryptedCount, 1) 87 | } 88 | } 89 | // get uid/gid of a file 90 | func GetFileGroupId(fInfo os.FileInfo) (uint32,uint32) { 91 | stat,_ := fInfo.Sys().(*syscall.Stat_t) 92 | return uint32(stat.Uid),uint32(stat.Gid) 93 | } 94 | -------------------------------------------------------------------------------- /zend_accelerator_debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #ifdef ZEND_WIN32 27 | #include 28 | #endif 29 | #include "ZendAccelerator.h" 30 | 31 | void zend_accel_error(int type, const char *format, ...) 32 | { 33 | va_list args; 34 | time_t timestamp; 35 | char *time_string; 36 | FILE *fLog = NULL; 37 | 38 | if (type <= ZCG(accel_directives).log_verbosity_level) 39 | { 40 | 41 | timestamp = time(NULL); 42 | time_string = asctime(localtime(×tamp)); 43 | time_string[24] = 0; 44 | 45 | if (!ZCG(accel_directives).error_log || 46 | !*ZCG(accel_directives).error_log || 47 | strcmp(ZCG(accel_directives).error_log, "stderr") == 0) 48 | { 49 | 50 | fLog = stderr; 51 | } 52 | else 53 | { 54 | fLog = fopen(ZCG(accel_directives).error_log, "a+"); 55 | if (!fLog) 56 | { 57 | fLog = stderr; 58 | } 59 | } 60 | 61 | #ifdef ZTS 62 | fprintf(fLog, "%s (" ZEND_ULONG_FMT "): ", time_string, (zend_ulong)tsrm_thread_id()); 63 | #else 64 | fprintf(fLog, "%s (%d): ", time_string, getpid()); 65 | #endif 66 | 67 | switch (type) 68 | { 69 | case ACCEL_LOG_FATAL: 70 | fprintf(fLog, "Fatal Error "); 71 | break; 72 | case ACCEL_LOG_ERROR: 73 | fprintf(fLog, "Error "); 74 | break; 75 | case ACCEL_LOG_WARNING: 76 | fprintf(fLog, "Warning "); 77 | break; 78 | case ACCEL_LOG_INFO: 79 | fprintf(fLog, "Message "); 80 | break; 81 | case ACCEL_LOG_DEBUG: 82 | fprintf(fLog, "Debug "); 83 | break; 84 | } 85 | 86 | va_start(args, format); 87 | vfprintf(fLog, format, args); 88 | va_end(args); 89 | fprintf(fLog, "\n"); 90 | 91 | fflush(fLog); 92 | if (fLog != stderr) 93 | { 94 | fclose(fLog); 95 | } 96 | } 97 | /* perform error handling even without logging the error */ 98 | switch (type) 99 | { 100 | case ACCEL_LOG_ERROR: 101 | zend_bailout(); 102 | break; 103 | case ACCEL_LOG_FATAL: 104 | exit(-2); 105 | break; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Optimizer/zend_call_graph.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, Call Graph | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Dmitry Stogov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef ZEND_CALL_GRAPH_H 20 | #define ZEND_CALL_GRAPH_H 21 | 22 | #include "zend_ssa.h" 23 | #include "zend_func_info.h" 24 | #include "zend_optimizer.h" 25 | 26 | typedef struct _zend_send_arg_info { 27 | zend_op *opline; 28 | } zend_send_arg_info; 29 | 30 | typedef struct _zend_recv_arg_info { 31 | int ssa_var; 32 | zend_ssa_var_info info; 33 | } zend_recv_arg_info; 34 | 35 | struct _zend_call_info { 36 | zend_op_array *caller_op_array; 37 | zend_op *caller_init_opline; 38 | zend_op *caller_call_opline; 39 | zend_function *callee_func; 40 | zend_call_info *next_caller; 41 | zend_call_info *next_callee; 42 | zend_func_info *clone; 43 | int recursive; 44 | int num_args; 45 | zend_send_arg_info arg_info[1]; 46 | }; 47 | 48 | struct _zend_func_info { 49 | int num; 50 | uint32_t flags; 51 | zend_ssa ssa; /* Static Single Assignmnt Form */ 52 | zend_call_info *caller_info; /* where this function is called from */ 53 | zend_call_info *callee_info; /* which functions are called from this one */ 54 | zend_call_info **call_map; /* Call info associated with init/call/send opnum */ 55 | int num_args; /* (-1 - unknown) */ 56 | zend_recv_arg_info *arg_info; 57 | zend_ssa_var_info return_info; 58 | zend_func_info *clone; 59 | int clone_num; 60 | int return_value_used; /* -1 unknown, 0 no, 1 yes */ 61 | void *codegen_data; 62 | }; 63 | 64 | typedef struct _zend_call_graph { 65 | int op_arrays_count; 66 | zend_op_array **op_arrays; 67 | zend_func_info *func_infos; 68 | } zend_call_graph; 69 | 70 | BEGIN_EXTERN_C() 71 | 72 | int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_call_graph *call_graph); 73 | zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array); 74 | int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info); 75 | 76 | END_EXTERN_C() 77 | 78 | #endif /* ZEND_CALL_GRAPH_H */ 79 | 80 | /* 81 | * Local variables: 82 | * tab-width: 4 83 | * c-basic-offset: 4 84 | * indent-tabs-mode: t 85 | * End: 86 | */ 87 | -------------------------------------------------------------------------------- /shared_alloc_mmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #include "zend_shared_alloc.h" 23 | 24 | #ifdef USE_MMAP 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) 33 | #define MAP_ANONYMOUS MAP_ANON 34 | #endif 35 | 36 | static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in) 37 | { 38 | zend_shared_segment *shared_segment; 39 | 40 | *shared_segments_count = 1; 41 | *shared_segments_p = (zend_shared_segment **)calloc(1, sizeof(zend_shared_segment) + sizeof(void *)); 42 | if (!*shared_segments_p) 43 | { 44 | *error_in = "calloc"; 45 | return ALLOC_FAILURE; 46 | } 47 | shared_segment = (zend_shared_segment *)((char *)(*shared_segments_p) + sizeof(void *)); 48 | (*shared_segments_p)[0] = shared_segment; 49 | 50 | #ifdef MAP_HUGETLB 51 | /* Try to allocate huge pages first to reduce dTLB misses. 52 | * OS has to be configured properly 53 | * (e.g. https://wiki.debian.org/Hugepages#Enabling_HugeTlbPage) 54 | * You may verify huge page usage with the following command: 55 | * `grep "Huge" /proc/meminfo` 56 | */ 57 | shared_segment->p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); 58 | if (shared_segment->p != MAP_FAILED) 59 | { 60 | shared_segment->pos = 0; 61 | shared_segment->size = requested_size; 62 | 63 | return ALLOC_SUCCESS; 64 | } 65 | #endif 66 | 67 | shared_segment->p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); 68 | if (shared_segment->p == MAP_FAILED) 69 | { 70 | *error_in = "mmap"; 71 | return ALLOC_FAILURE; 72 | } 73 | 74 | shared_segment->pos = 0; 75 | shared_segment->size = requested_size; 76 | 77 | return ALLOC_SUCCESS; 78 | } 79 | 80 | static int detach_segment(zend_shared_segment *shared_segment) 81 | { 82 | munmap(shared_segment->p, shared_segment->size); 83 | return 0; 84 | } 85 | 86 | static size_t segment_type_size(void) 87 | { 88 | return sizeof(zend_shared_segment); 89 | } 90 | 91 | zend_shared_memory_handlers zend_alloc_mmap_handlers = { 92 | create_segments, 93 | detach_segment, 94 | segment_type_size}; 95 | 96 | #endif /* USE_MMAP */ 97 | -------------------------------------------------------------------------------- /shared_alloc_posix.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #include "zend_shared_alloc.h" 23 | 24 | #ifdef USE_SHM_OPEN 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | typedef struct 35 | { 36 | zend_shared_segment common; 37 | int shm_fd; 38 | } zend_shared_segment_posix; 39 | 40 | static int create_segments(size_t requested_size, zend_shared_segment_posix ***shared_segments_p, int *shared_segments_count, char **error_in) 41 | { 42 | zend_shared_segment_posix *shared_segment; 43 | char shared_segment_name[sizeof("/ZendAccelerator.") + 20]; 44 | 45 | *shared_segments_count = 1; 46 | *shared_segments_p = (zend_shared_segment_posix **)calloc(1, sizeof(zend_shared_segment_posix) + sizeof(void *)); 47 | if (!*shared_segments_p) 48 | { 49 | *error_in = "calloc"; 50 | return ALLOC_FAILURE; 51 | } 52 | shared_segment = (zend_shared_segment_posix *)((char *)(*shared_segments_p) + sizeof(void *)); 53 | (*shared_segments_p)[0] = shared_segment; 54 | 55 | sprintf(shared_segment_name, "/ZendAccelerator.%d", getpid()); 56 | shared_segment->shm_fd = shm_open(shared_segment_name, O_RDWR | O_CREAT | O_TRUNC, 0600); 57 | if (shared_segment->shm_fd == -1) 58 | { 59 | *error_in = "shm_open"; 60 | return ALLOC_FAILURE; 61 | } 62 | 63 | if (ftruncate(shared_segment->shm_fd, requested_size) != 0) 64 | { 65 | *error_in = "ftruncate"; 66 | shm_unlink(shared_segment_name); 67 | return ALLOC_FAILURE; 68 | } 69 | 70 | shared_segment->common.p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED, shared_segment->shm_fd, 0); 71 | if (shared_segment->common.p == MAP_FAILED) 72 | { 73 | *error_in = "mmap"; 74 | shm_unlink(shared_segment_name); 75 | return ALLOC_FAILURE; 76 | } 77 | shm_unlink(shared_segment_name); 78 | 79 | shared_segment->common.pos = 0; 80 | shared_segment->common.size = requested_size; 81 | 82 | return ALLOC_SUCCESS; 83 | } 84 | 85 | static int detach_segment(zend_shared_segment_posix *shared_segment) 86 | { 87 | munmap(shared_segment->common.p, shared_segment->common.size); 88 | close(shared_segment->shm_fd); 89 | return 0; 90 | } 91 | 92 | static size_t segment_type_size(void) 93 | { 94 | return sizeof(zend_shared_segment_posix); 95 | } 96 | 97 | zend_shared_memory_handlers zend_alloc_posix_handlers = { 98 | (create_segments_t)create_segments, 99 | (detach_segment_t)detach_segment, 100 | segment_type_size}; 101 | 102 | #endif /* USE_SHM_OPEN */ 103 | -------------------------------------------------------------------------------- /Optimizer/scdf.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, Call Graph | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Nikita Popov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef _SCDF_H 20 | #define _SCDF_H 21 | 22 | #include "zend_bitset.h" 23 | 24 | typedef struct _scdf_ctx { 25 | zend_op_array *op_array; 26 | zend_ssa *ssa; 27 | zend_bitset instr_worklist; 28 | /* Represent phi-instructions through the defining var */ 29 | zend_bitset phi_var_worklist; 30 | zend_bitset block_worklist; 31 | zend_bitset executable_blocks; 32 | /* 1 bit per edge, see scdf_edge(cfg, from, to) */ 33 | zend_bitset feasible_edges; 34 | uint32_t instr_worklist_len; 35 | uint32_t phi_var_worklist_len; 36 | uint32_t block_worklist_len; 37 | 38 | struct { 39 | void (*visit_instr)( 40 | struct _scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_op); 41 | void (*visit_phi)( 42 | struct _scdf_ctx *scdf, zend_ssa_phi *phi); 43 | void (*mark_feasible_successors)( 44 | struct _scdf_ctx *scdf, int block_num, zend_basic_block *block, 45 | zend_op *opline, zend_ssa_op *ssa_op); 46 | } handlers; 47 | } scdf_ctx; 48 | 49 | void scdf_init(zend_optimizer_ctx *ctx, scdf_ctx *scdf, zend_op_array *op_array, zend_ssa *ssa); 50 | void scdf_solve(scdf_ctx *scdf, const char *name); 51 | 52 | int scdf_remove_unreachable_blocks(scdf_ctx *scdf); 53 | 54 | /* Add uses to worklist */ 55 | static inline void scdf_add_to_worklist(scdf_ctx *scdf, int var_num) { 56 | zend_ssa *ssa = scdf->ssa; 57 | zend_ssa_var *var = &ssa->vars[var_num]; 58 | int use; 59 | zend_ssa_phi *phi; 60 | FOREACH_USE(var, use) { 61 | zend_bitset_incl(scdf->instr_worklist, use); 62 | } FOREACH_USE_END(); 63 | FOREACH_PHI_USE(var, phi) { 64 | zend_bitset_incl(scdf->phi_var_worklist, phi->ssa_var); 65 | } FOREACH_PHI_USE_END(); 66 | } 67 | 68 | /* This should usually not be necessary, however it's used for type narrowing. */ 69 | static inline void scdf_add_def_to_worklist(scdf_ctx *scdf, int var_num) { 70 | zend_ssa_var *var = &scdf->ssa->vars[var_num]; 71 | if (var->definition >= 0) { 72 | zend_bitset_incl(scdf->instr_worklist, var->definition); 73 | } else if (var->definition_phi) { 74 | zend_bitset_incl(scdf->phi_var_worklist, var_num); 75 | } 76 | } 77 | 78 | static inline uint32_t scdf_edge(zend_cfg *cfg, int from, int to) { 79 | zend_basic_block *to_block = cfg->blocks + to; 80 | int i; 81 | 82 | for (i = 0; i < to_block->predecessors_count; i++) { 83 | uint32_t edge = to_block->predecessor_offset + i; 84 | 85 | if (cfg->predecessors[edge] == from) { 86 | return edge; 87 | } 88 | } 89 | ZEND_ASSERT(0); 90 | } 91 | 92 | static inline zend_bool scdf_is_edge_feasible(scdf_ctx *scdf, int from, int to) { 93 | uint32_t edge = scdf_edge(&scdf->ssa->cfg, from, to); 94 | return zend_bitset_in(scdf->feasible_edges, edge); 95 | } 96 | 97 | void scdf_mark_edge_feasible(scdf_ctx *scdf, int from, int to); 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /gensecretkey.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | pwd_sha256=`head -20 /dev/urandom |sha256sum` 3 | pwd_sha256=${pwd_sha256:0:64} 4 | if [ ! `echo $pwd_sha256|wc -L` == 64 ];then 5 | echo "wrong data"; 6 | echo "数据错误"; 7 | exit 8 | fi 9 | echo "rand secret key(随机秘钥): $pwd_sha256"; 10 | rm -rf screwopcode_key.h; 11 | echo "#define GK_F(x,y,z) ((x & y) | (~x & z)) 12 | #define GK_G(x,y,z) ((x & z) | (y & ~z)) 13 | #define GK_H(x,y,z) (x^y^z) 14 | #define GK_I(x,y,z) (y ^ (x | ~z)) 15 | #define GK_ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n))) 16 | #define GK_TRANSFORM1(a,b,c,d,x,s,ac) \ 17 | { \ 18 | a += GK_F(b,c,d) + x + ac; \ 19 | a = GK_ROTATE_LEFT(a,s); \ 20 | a += b; \ 21 | } 22 | #define GK_TRANSFORM2(a,b,c,d,x,s,ac) \ 23 | { \ 24 | a += GK_G(b,c,d) + x + ac; \ 25 | a = GK_ROTATE_LEFT(a,s); \ 26 | a += b; \ 27 | } 28 | #define GK_TRANSFORM3(a,b,c,d,x,s,ac) \ 29 | { \ 30 | a += GK_H(b,c,d) + x + ac; \ 31 | a = GK_ROTATE_LEFT(a,s); \ 32 | a += b; \ 33 | } 34 | #define GK_TRANSFORM4(a,b,c,d,x,s,ac) \ 35 | { \ 36 | a += GK_I(b,c,d) + x + ac; \ 37 | a = GK_ROTATE_LEFT(a,s); \ 38 | a += b; \ 39 | } 40 | #define GETKEY() ({unsigned int state[16];\\" >> screwopcode_key.h; 41 | for i in {0..15} 42 | do 43 | echo "state[$i] = 0x${pwd_sha256:$i*4:4};\\" >> screwopcode_key.h; 44 | done 45 | # 循环创建变形逻辑 46 | for ((i=0;i<1+$((16#${pwd_sha256:0:1}));i++)) 47 | do 48 | echo "GK_TRANSFORM1(state[0], state[1], state[2], state[3], state[0], 1, (state[0]^state[1]) ^ 0x${pwd_sha256:3:2});\\ 49 | GK_TRANSFORM2(state[1], state[2], state[3], state[4], state[1], 27, (state[1]^state[2]) ^ 0x${pwd_sha256:5:2});\\ 50 | GK_TRANSFORM3(state[2], state[3], state[4], state[5], state[2], 9, (state[2]^state[3]) ^ 0x${pwd_sha256:7:2});\\ 51 | GK_TRANSFORM4(state[3], state[4], state[5], state[6], state[3], 12, (state[3]^state[4]) ^ 0x${pwd_sha256:9:2});\\" >> screwopcode_key.h; 52 | done 53 | for ((i=0;i<2+$((16#${pwd_sha256:8:1}));i++)) 54 | do 55 | echo "GK_TRANSFORM1(state[4], state[5], state[6], state[7], state[4], 17, (state[4]^state[5]) ^ 0x${pwd_sha256:11:2});\\ 56 | GK_TRANSFORM2(state[5], state[6], state[7], state[8], state[5], 21, (state[5]^state[6]) ^ 0x${pwd_sha256:13:2});\\ 57 | GK_TRANSFORM3(state[6], state[7], state[8], state[9], state[6], 12, (state[6]^state[7]) ^ 0x${pwd_sha256:15:2});\\ 58 | GK_TRANSFORM4(state[7], state[8], state[9], state[10], state[7], 8, (state[7]^state[8]) ^ 0x${pwd_sha256:17:2});\\" >> screwopcode_key.h; 59 | done 60 | for ((i=0;i<3+$((16#${pwd_sha256:16:1}));i++)) 61 | do 62 | echo "GK_TRANSFORM1(state[8], state[9], state[10], state[11], state[8], 7, (state[8]^state[9]) ^ 0x${pwd_sha256:19:2});\\ 63 | GK_TRANSFORM2(state[9], state[10], state[11], state[12], state[9], 14, (state[9]^state[10]) ^ 0x${pwd_sha256:21:2});\\ 64 | GK_TRANSFORM3(state[10], state[11], state[12], state[13], state[10], 2, (state[10]^state[11]) ^ 0x${pwd_sha256:23:2});\\ 65 | GK_TRANSFORM4(state[11], state[12], state[13], state[14], state[11], 6, (state[11]^state[12]) ^ 0x${pwd_sha256:25:2});\\" >> screwopcode_key.h; 66 | done 67 | for ((i=0;i<4+$((16#${pwd_sha256:24:1}));i++)) 68 | do 69 | echo "GK_TRANSFORM1(state[12], state[13], state[14], state[15], state[12], 1, (state[12]^state[13]) ^ 0x${pwd_sha256:27:2});\\ 70 | GK_TRANSFORM2(state[13], state[14], state[15], state[0], state[13], 15, (state[13]^state[14]) ^ 0x${pwd_sha256:29:2});\\ 71 | GK_TRANSFORM3(state[14], state[15], state[0], state[1], state[14], 24, (state[14]^state[15]) ^ 0x31);\\ 72 | GK_TRANSFORM4(state[15], state[0], state[1], state[2], state[15], 8, (state[15]^state[0]) ^ 0x${pwd_sha256:33:2});\\" >> screwopcode_key.h; 73 | done 74 | echo "int i;\\ 75 | char str[32];\\ 76 | char hashcode[64];\\ 77 | memset(str, 0, 32);\\ 78 | memset(hashcode, 0, 64);\\ 79 | for (i=0;i<16;i++) {\\ 80 | sprintf(hashcode,\"%x%s\",state[i],str);\\ 81 | sprintf(str, \"%s\",md5(hashcode));\\ 82 | }\\ 83 | str;\\ 84 | })" >> screwopcode_key.h; 85 | 86 | echo "创建成功 success."; -------------------------------------------------------------------------------- /zend_accelerator_hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_ACCELERATOR_HASH_H 23 | #define ZEND_ACCELERATOR_HASH_H 24 | 25 | #include "zend.h" 26 | 27 | /* 28 | zend_accel_hash - is a hash table allocated in shared memory and 29 | distributed across simultaneously running processes. The hash tables have 30 | fixed sizen selected during construction by zend_accel_hash_init(). All the 31 | hash entries are preallocated in the 'hash_entries' array. 'num_entries' is 32 | initialized by zero and grows when new data is added. 33 | zend_accel_hash_update() just takes the next entry from 'hash_entries' 34 | array and puts it into appropriate place of 'hash_table'. 35 | Hash collisions are resolved by separate chaining with linked lists, 36 | however, entries are still taken from the same 'hash_entries' array. 37 | 'key' and 'data' passed to zend_accel_hash_update() must be already 38 | allocated in shared memory. Few keys may be resolved to the same data. 39 | using 'indirect' entries, that point to other entries ('data' is actually 40 | a pointer to another zend_accel_hash_entry). 41 | zend_accel_hash_update() requires exclusive lock, however, 42 | zend_accel_hash_find() does not. 43 | */ 44 | 45 | typedef struct _zend_accel_hash_entry zend_accel_hash_entry; 46 | 47 | struct _zend_accel_hash_entry 48 | { 49 | zend_ulong hash_value; 50 | char *key; 51 | uint32_t key_length; 52 | zend_accel_hash_entry *next; 53 | void *data; 54 | zend_bool indirect; 55 | }; 56 | 57 | typedef struct _zend_accel_hash 58 | { 59 | zend_accel_hash_entry **hash_table; 60 | zend_accel_hash_entry *hash_entries; 61 | uint32_t num_entries; 62 | uint32_t max_num_entries; 63 | uint32_t num_direct_entries; 64 | } zend_accel_hash; 65 | 66 | void zend_accel_hash_init(zend_accel_hash *accel_hash, uint32_t hash_size); 67 | void zend_accel_hash_clean(zend_accel_hash *accel_hash); 68 | 69 | zend_accel_hash_entry *zend_accel_hash_update( 70 | zend_accel_hash *accel_hash, 71 | char *key, 72 | uint32_t key_length, 73 | zend_bool indirect, 74 | void *data); 75 | 76 | void *zend_accel_hash_find( 77 | zend_accel_hash *accel_hash, 78 | zend_string *key); 79 | 80 | zend_accel_hash_entry *zend_accel_hash_find_entry( 81 | zend_accel_hash *accel_hash, 82 | zend_string *key); 83 | 84 | void *zend_accel_hash_str_find( 85 | zend_accel_hash *accel_hash, 86 | char *key, 87 | uint32_t key_length); 88 | 89 | zend_accel_hash_entry *zend_accel_hash_str_find_entry( 90 | zend_accel_hash *accel_hash, 91 | char *key, 92 | uint32_t key_length); 93 | 94 | int zend_accel_hash_unlink( 95 | zend_accel_hash *accel_hash, 96 | char *key, 97 | uint32_t key_length); 98 | 99 | static inline zend_bool zend_accel_hash_is_full(zend_accel_hash *accel_hash) 100 | { 101 | if (accel_hash->num_entries == accel_hash->max_num_entries) 102 | { 103 | return 1; 104 | } 105 | else 106 | { 107 | return 0; 108 | } 109 | } 110 | 111 | #endif /* ZEND_ACCELERATOR_HASH_H */ 112 | -------------------------------------------------------------------------------- /Optimizer/nop_removal.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | /* pass 10: 23 | * - remove NOPs 24 | */ 25 | 26 | #include "php.h" 27 | #include "Optimizer/zend_optimizer.h" 28 | #include "Optimizer/zend_optimizer_internal.h" 29 | #include "zend_API.h" 30 | #include "zend_constants.h" 31 | #include "zend_execute.h" 32 | #include "zend_vm.h" 33 | 34 | void zend_optimizer_nop_removal(zend_op_array *op_array) 35 | { 36 | zend_op *end, *opline; 37 | uint32_t new_count, i, shift; 38 | int j; 39 | uint32_t *shiftlist; 40 | ALLOCA_FLAG(use_heap); 41 | 42 | shiftlist = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last, use_heap); 43 | i = new_count = shift = 0; 44 | end = op_array->opcodes + op_array->last; 45 | for (opline = op_array->opcodes; opline < end; opline++) 46 | { 47 | 48 | /* Kill JMP-over-NOP-s */ 49 | if (opline->opcode == ZEND_JMP && ZEND_OP1_JMP_ADDR(opline) > op_array->opcodes + i) 50 | { 51 | /* check if there are only NOPs under the branch */ 52 | zend_op *target = ZEND_OP1_JMP_ADDR(opline) - 1; 53 | 54 | while (target->opcode == ZEND_NOP) 55 | { 56 | target--; 57 | } 58 | if (target == opline) 59 | { 60 | /* only NOPs */ 61 | opline->opcode = ZEND_NOP; 62 | } 63 | } 64 | 65 | shiftlist[i++] = shift; 66 | if (opline->opcode == ZEND_NOP) 67 | { 68 | shift++; 69 | } 70 | else 71 | { 72 | if (shift) 73 | { 74 | zend_op *new_opline = op_array->opcodes + new_count; 75 | 76 | *new_opline = *opline; 77 | zend_optimizer_migrate_jump(op_array, new_opline, opline); 78 | } 79 | new_count++; 80 | } 81 | } 82 | 83 | if (shift) 84 | { 85 | op_array->last = new_count; 86 | end = op_array->opcodes + op_array->last; 87 | 88 | /* update JMPs */ 89 | for (opline = op_array->opcodes; opline < end; opline++) 90 | { 91 | zend_optimizer_shift_jump(op_array, opline, shiftlist); 92 | } 93 | 94 | /* update brk/cont array */ 95 | for (j = 0; j < op_array->last_live_range; j++) 96 | { 97 | op_array->live_range[j].start -= shiftlist[op_array->live_range[j].start]; 98 | op_array->live_range[j].end -= shiftlist[op_array->live_range[j].end]; 99 | } 100 | 101 | /* update try/catch array */ 102 | for (j = 0; j < op_array->last_try_catch; j++) 103 | { 104 | op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op]; 105 | op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op]; 106 | if (op_array->try_catch_array[j].finally_op) 107 | { 108 | op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op]; 109 | op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end]; 110 | } 111 | } 112 | 113 | /* update early binding list */ 114 | if (op_array->early_binding != (uint32_t)-1) 115 | { 116 | uint32_t *opline_num = &op_array->early_binding; 117 | 118 | do 119 | { 120 | *opline_num -= shiftlist[*opline_num]; 121 | opline_num = &op_array->opcodes[*opline_num].result.opline_num; 122 | } while (*opline_num != (uint32_t)-1); 123 | } 124 | } 125 | free_alloca(shiftlist, use_heap); 126 | } 127 | -------------------------------------------------------------------------------- /Optimizer/zend_worklist.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andy Wingo | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id:$ */ 20 | 21 | #ifndef _ZEND_WORKLIST_H_ 22 | #define _ZEND_WORKLIST_H_ 23 | 24 | #include "zend_arena.h" 25 | #include "zend_bitset.h" 26 | 27 | typedef struct _zend_worklist_stack { 28 | int *buf; 29 | int len; 30 | int capacity; 31 | } zend_worklist_stack; 32 | 33 | #define ZEND_WORKLIST_STACK_ALLOCA(s, _len, use_heap) do { \ 34 | (s)->buf = (int*)do_alloca(sizeof(int) * _len, use_heap); \ 35 | (s)->len = 0; \ 36 | (s)->capacity = _len; \ 37 | } while (0) 38 | 39 | #define ZEND_WORKLIST_STACK_FREE_ALLOCA(s, use_heap) \ 40 | free_alloca((s)->buf, use_heap) 41 | 42 | static inline int zend_worklist_stack_prepare(zend_arena **arena, zend_worklist_stack *stack, int len) 43 | { 44 | ZEND_ASSERT(len >= 0); 45 | 46 | stack->buf = (int*)zend_arena_calloc(arena, sizeof(*stack->buf), len); 47 | stack->len = 0; 48 | stack->capacity = len; 49 | 50 | return SUCCESS; 51 | } 52 | 53 | static inline void zend_worklist_stack_push(zend_worklist_stack *stack, int i) 54 | { 55 | ZEND_ASSERT(stack->len < stack->capacity); 56 | stack->buf[stack->len++] = i; 57 | } 58 | 59 | static inline int zend_worklist_stack_peek(zend_worklist_stack *stack) 60 | { 61 | ZEND_ASSERT(stack->len); 62 | return stack->buf[stack->len - 1]; 63 | } 64 | 65 | static inline int zend_worklist_stack_pop(zend_worklist_stack *stack) 66 | { 67 | ZEND_ASSERT(stack->len); 68 | return stack->buf[--stack->len]; 69 | } 70 | 71 | typedef struct _zend_worklist { 72 | zend_bitset visited; 73 | zend_worklist_stack stack; 74 | } zend_worklist; 75 | 76 | #define ZEND_WORKLIST_ALLOCA(w, _len, use_heap) do { \ 77 | (w)->stack.buf = (int*)do_alloca(ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len) + sizeof(zend_ulong) * zend_bitset_len(_len), use_heap); \ 78 | (w)->stack.len = 0; \ 79 | (w)->stack.capacity = _len; \ 80 | (w)->visited = (zend_bitset)((char*)(w)->stack.buf + ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len)); \ 81 | memset((w)->visited, 0, sizeof(zend_ulong) * zend_bitset_len(_len)); \ 82 | } while (0) 83 | 84 | #define ZEND_WORKLIST_FREE_ALLOCA(w, use_heap) \ 85 | free_alloca((w)->stack.buf, use_heap) 86 | 87 | static inline int zend_worklist_prepare(zend_arena **arena, zend_worklist *worklist, int len) 88 | { 89 | ZEND_ASSERT(len >= 0); 90 | worklist->visited = (zend_bitset)zend_arena_calloc(arena, sizeof(zend_ulong), zend_bitset_len(len)); 91 | return zend_worklist_stack_prepare(arena, &worklist->stack, len); 92 | } 93 | 94 | static inline int zend_worklist_len(zend_worklist *worklist) 95 | { 96 | return worklist->stack.len; 97 | } 98 | 99 | static inline int zend_worklist_push(zend_worklist *worklist, int i) 100 | { 101 | ZEND_ASSERT(i >= 0 && i < worklist->stack.capacity); 102 | 103 | if (zend_bitset_in(worklist->visited, i)) { 104 | return 0; 105 | } 106 | 107 | zend_bitset_incl(worklist->visited, i); 108 | zend_worklist_stack_push(&worklist->stack, i); 109 | return 1; 110 | } 111 | 112 | static inline int zend_worklist_peek(zend_worklist *worklist) 113 | { 114 | return zend_worklist_stack_peek(&worklist->stack); 115 | } 116 | 117 | static inline int zend_worklist_pop(zend_worklist *worklist) 118 | { 119 | /* Does not clear visited flag */ 120 | return zend_worklist_stack_pop(&worklist->stack); 121 | } 122 | 123 | #endif /* _ZEND_WORKLIST_H_ */ 124 | 125 | /* 126 | * Local variables: 127 | * tab-width: 4 128 | * c-basic-offset: 4 129 | * indent-tabs-mode: t 130 | * End: 131 | */ 132 | -------------------------------------------------------------------------------- /Optimizer/compact_vars.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, Removing unused variables | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Nikita Popov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #include "ZendAccelerator.h" 20 | #include "Optimizer/zend_optimizer_internal.h" 21 | #include "zend_bitset.h" 22 | 23 | /* This pass removes all CVs that are completely unused. It does *not* merge any CVs. 24 | * This pass does not operate on SSA form anymore. */ 25 | void zend_optimizer_compact_vars(zend_op_array *op_array) { 26 | int i; 27 | 28 | ALLOCA_FLAG(use_heap1); 29 | ALLOCA_FLAG(use_heap2); 30 | uint32_t used_cvs_len = zend_bitset_len(op_array->last_var); 31 | zend_bitset used_cvs = ZEND_BITSET_ALLOCA(used_cvs_len, use_heap1); 32 | uint32_t *cv_map = do_alloca(op_array->last_var * sizeof(uint32_t), use_heap2); 33 | uint32_t num_cvs, tmp_offset; 34 | 35 | /* Determine which CVs are used */ 36 | zend_bitset_clear(used_cvs, used_cvs_len); 37 | for (i = 0; i < op_array->last; i++) { 38 | zend_op *opline = &op_array->opcodes[i]; 39 | if (opline->op1_type == IS_CV) { 40 | zend_bitset_incl(used_cvs, VAR_NUM(opline->op1.var)); 41 | } 42 | if (opline->op2_type == IS_CV) { 43 | zend_bitset_incl(used_cvs, VAR_NUM(opline->op2.var)); 44 | } 45 | if (opline->result_type == IS_CV) { 46 | zend_bitset_incl(used_cvs, VAR_NUM(opline->result.var)); 47 | } 48 | } 49 | 50 | num_cvs = 0; 51 | for (i = 0; i < op_array->last_var; i++) { 52 | if (zend_bitset_in(used_cvs, i)) { 53 | cv_map[i] = num_cvs++; 54 | } else { 55 | cv_map[i] = (uint32_t) -1; 56 | } 57 | } 58 | 59 | free_alloca(used_cvs, use_heap1); 60 | if (num_cvs == op_array->last_var) { 61 | free_alloca(cv_map, use_heap2); 62 | return; 63 | } 64 | 65 | ZEND_ASSERT(num_cvs < op_array->last_var); 66 | tmp_offset = op_array->last_var - num_cvs; 67 | 68 | /* Update CV and TMP references in opcodes */ 69 | for (i = 0; i < op_array->last; i++) { 70 | zend_op *opline = &op_array->opcodes[i]; 71 | if (opline->op1_type == IS_CV) { 72 | opline->op1.var = NUM_VAR(cv_map[VAR_NUM(opline->op1.var)]); 73 | } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { 74 | opline->op1.var -= sizeof(zval) * tmp_offset; 75 | } 76 | if (opline->op2_type == IS_CV) { 77 | opline->op2.var = NUM_VAR(cv_map[VAR_NUM(opline->op2.var)]); 78 | } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) { 79 | opline->op2.var -= sizeof(zval) * tmp_offset; 80 | } 81 | if (opline->result_type == IS_CV) { 82 | opline->result.var = NUM_VAR(cv_map[VAR_NUM(opline->result.var)]); 83 | } else if (opline->result_type & (IS_VAR|IS_TMP_VAR)) { 84 | opline->result.var -= sizeof(zval) * tmp_offset; 85 | } 86 | } 87 | 88 | /* Update TMP references in live ranges */ 89 | if (op_array->live_range) { 90 | for (i = 0; i < op_array->last_live_range; i++) { 91 | op_array->live_range[i].var -= sizeof(zval) * tmp_offset; 92 | } 93 | } 94 | 95 | /* Update CV name table */ 96 | if (num_cvs) { 97 | zend_string **names = safe_emalloc(sizeof(zend_string *), num_cvs, 0); 98 | for (i = 0; i < op_array->last_var; i++) { 99 | if (cv_map[i] != (uint32_t) -1) { 100 | names[cv_map[i]] = op_array->vars[i]; 101 | } else { 102 | zend_string_release(op_array->vars[i]); 103 | } 104 | } 105 | efree(op_array->vars); 106 | op_array->vars = names; 107 | } else { 108 | for (i = 0; i < op_array->last_var; i++) { 109 | zend_string_release(op_array->vars[i]); 110 | } 111 | efree(op_array->vars); 112 | op_array->vars = NULL; 113 | } 114 | 115 | op_array->last_var = num_cvs; 116 | 117 | free_alloca(cv_map, use_heap2); 118 | } 119 | -------------------------------------------------------------------------------- /Optimizer/zend_optimizer.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_OPTIMIZER_H 23 | #define ZEND_OPTIMIZER_H 24 | 25 | #include "zend.h" 26 | #include "zend_compile.h" 27 | 28 | #define ZEND_OPTIMIZER_PASS_1 (1 << 0) /* CSE, STRING construction */ 29 | #define ZEND_OPTIMIZER_PASS_2 (1 << 1) /* Constant conversion and jumps */ 30 | #define ZEND_OPTIMIZER_PASS_3 (1 << 2) /* ++, +=, series of jumps */ 31 | #define ZEND_OPTIMIZER_PASS_4 (1 << 3) /* INIT_FCALL_BY_NAME -> DO_FCALL */ 32 | #define ZEND_OPTIMIZER_PASS_5 (1 << 4) /* CFG based optimization */ 33 | #define ZEND_OPTIMIZER_PASS_6 (1 << 5) /* DFA based optimization */ 34 | #define ZEND_OPTIMIZER_PASS_7 (1 << 6) /* CALL GRAPH optimization */ 35 | #define ZEND_OPTIMIZER_PASS_8 (1 << 7) /* SCCP (constant propagation) */ 36 | #define ZEND_OPTIMIZER_PASS_9 (1 << 8) /* TMP VAR usage */ 37 | #define ZEND_OPTIMIZER_PASS_10 (1 << 9) /* NOP removal */ 38 | #define ZEND_OPTIMIZER_PASS_11 (1 << 10) /* Merge equal constants */ 39 | #define ZEND_OPTIMIZER_PASS_12 (1 << 11) /* Adjust used stack */ 40 | #define ZEND_OPTIMIZER_PASS_13 (1 << 12) /* Remove unused variables */ 41 | #define ZEND_OPTIMIZER_PASS_14 (1 << 13) /* DCE (dead code elimination) */ 42 | #define ZEND_OPTIMIZER_PASS_15 (1 << 14) /* Collect constants */ 43 | #define ZEND_OPTIMIZER_PASS_16 (1 << 15) /* Inline functions */ 44 | 45 | #define ZEND_OPTIMIZER_ALL_PASSES 0x7FFFFFFF 46 | 47 | #define DEFAULT_OPTIMIZATION_LEVEL "0x7FFFBFFF" 48 | 49 | #define ZEND_DUMP_AFTER_PASS_1 ZEND_OPTIMIZER_PASS_1 50 | #define ZEND_DUMP_AFTER_PASS_2 ZEND_OPTIMIZER_PASS_2 51 | #define ZEND_DUMP_AFTER_PASS_3 ZEND_OPTIMIZER_PASS_3 52 | #define ZEND_DUMP_AFTER_PASS_4 ZEND_OPTIMIZER_PASS_4 53 | #define ZEND_DUMP_AFTER_PASS_5 ZEND_OPTIMIZER_PASS_5 54 | #define ZEND_DUMP_AFTER_PASS_6 ZEND_OPTIMIZER_PASS_6 55 | #define ZEND_DUMP_AFTER_PASS_7 ZEND_OPTIMIZER_PASS_7 56 | #define ZEND_DUMP_AFTER_PASS_8 ZEND_OPTIMIZER_PASS_8 57 | #define ZEND_DUMP_AFTER_PASS_9 ZEND_OPTIMIZER_PASS_9 58 | #define ZEND_DUMP_AFTER_PASS_10 ZEND_OPTIMIZER_PASS_10 59 | #define ZEND_DUMP_AFTER_PASS_11 ZEND_OPTIMIZER_PASS_11 60 | #define ZEND_DUMP_AFTER_PASS_12 ZEND_OPTIMIZER_PASS_12 61 | #define ZEND_DUMP_AFTER_PASS_13 ZEND_OPTIMIZER_PASS_13 62 | #define ZEND_DUMP_AFTER_PASS_14 ZEND_OPTIMIZER_PASS_14 63 | 64 | #define ZEND_DUMP_BEFORE_OPTIMIZER (1 << 16) 65 | #define ZEND_DUMP_AFTER_OPTIMIZER (1 << 17) 66 | 67 | #define ZEND_DUMP_BEFORE_BLOCK_PASS (1 << 18) 68 | #define ZEND_DUMP_AFTER_BLOCK_PASS (1 << 19) 69 | #define ZEND_DUMP_BLOCK_PASS_VARS (1 << 20) 70 | 71 | #define ZEND_DUMP_BEFORE_DFA_PASS (1 << 21) 72 | #define ZEND_DUMP_AFTER_DFA_PASS (1 << 22) 73 | #define ZEND_DUMP_DFA_CFG (1 << 23) 74 | #define ZEND_DUMP_DFA_DOMINATORS (1 << 24) 75 | #define ZEND_DUMP_DFA_LIVENESS (1 << 25) 76 | #define ZEND_DUMP_DFA_PHI (1 << 26) 77 | #define ZEND_DUMP_DFA_SSA (1 << 27) 78 | #define ZEND_DUMP_DFA_SSA_VARS (1 << 28) 79 | 80 | typedef struct _zend_script 81 | { 82 | zend_string *filename; 83 | zend_op_array main_op_array; 84 | HashTable function_table; 85 | HashTable class_table; 86 | } zend_script; 87 | 88 | int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level); 89 | int zend_optimizer_startup(void); 90 | int zend_optimizer_shutdown(void); 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /shared_alloc_shm.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #include "zend_shared_alloc.h" 23 | 24 | #ifdef USE_SHM 25 | 26 | #if defined(__FreeBSD__) 27 | #include 28 | #endif 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | 42 | #ifndef MIN 43 | #define MIN(x, y) ((x) > (y) ? (y) : (x)) 44 | #endif 45 | 46 | #define SEG_ALLOC_SIZE_MAX 32 * 1024 * 1024 47 | #define SEG_ALLOC_SIZE_MIN 2 * 1024 * 1024 48 | 49 | typedef struct 50 | { 51 | zend_shared_segment common; 52 | int shm_id; 53 | } zend_shared_segment_shm; 54 | 55 | static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, char **error_in) 56 | { 57 | int i; 58 | size_t allocate_size = 0, remaining_bytes = requested_size, seg_allocate_size; 59 | int first_segment_id = -1; 60 | key_t first_segment_key = -1; 61 | struct shmid_ds sds; 62 | int shmget_flags; 63 | zend_shared_segment_shm *shared_segments; 64 | 65 | seg_allocate_size = SEG_ALLOC_SIZE_MAX; 66 | /* determine segment size we _really_ need: 67 | * no more than to include requested_size 68 | */ 69 | while (requested_size * 2 <= seg_allocate_size && seg_allocate_size > SEG_ALLOC_SIZE_MIN) 70 | { 71 | seg_allocate_size >>= 1; 72 | } 73 | 74 | shmget_flags = IPC_CREAT | SHM_R | SHM_W | IPC_EXCL; 75 | 76 | /* try allocating this much, if not - try shrinking */ 77 | while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) 78 | { 79 | allocate_size = MIN(requested_size, seg_allocate_size); 80 | first_segment_id = shmget(first_segment_key, allocate_size, shmget_flags); 81 | if (first_segment_id != -1) 82 | { 83 | break; 84 | } 85 | seg_allocate_size >>= 1; /* shrink the allocated block */ 86 | } 87 | 88 | if (first_segment_id == -1) 89 | { 90 | *error_in = "shmget"; 91 | return ALLOC_FAILURE; 92 | } 93 | 94 | *shared_segments_count = ((requested_size - 1) / seg_allocate_size) + 1; 95 | *shared_segments_p = (zend_shared_segment_shm **)calloc(1, (*shared_segments_count) * sizeof(zend_shared_segment_shm) + sizeof(void *) * (*shared_segments_count)); 96 | if (!*shared_segments_p) 97 | { 98 | *error_in = "calloc"; 99 | return ALLOC_FAILURE; 100 | } 101 | shared_segments = (zend_shared_segment_shm *)((char *)(*shared_segments_p) + sizeof(void *) * (*shared_segments_count)); 102 | for (i = 0; i < *shared_segments_count; i++) 103 | { 104 | (*shared_segments_p)[i] = shared_segments + i; 105 | } 106 | 107 | remaining_bytes = requested_size; 108 | for (i = 0; i < *shared_segments_count; i++) 109 | { 110 | allocate_size = MIN(remaining_bytes, seg_allocate_size); 111 | if (i != 0) 112 | { 113 | shared_segments[i].shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags); 114 | } 115 | else 116 | { 117 | shared_segments[i].shm_id = first_segment_id; 118 | } 119 | 120 | if (shared_segments[i].shm_id == -1) 121 | { 122 | return ALLOC_FAILURE; 123 | } 124 | 125 | shared_segments[i].common.p = shmat(shared_segments[i].shm_id, NULL, 0); 126 | if (shared_segments[i].common.p == (void *)-1) 127 | { 128 | *error_in = "shmat"; 129 | shmctl(shared_segments[i].shm_id, IPC_RMID, &sds); 130 | return ALLOC_FAILURE; 131 | } 132 | shmctl(shared_segments[i].shm_id, IPC_RMID, &sds); 133 | 134 | shared_segments[i].common.pos = 0; 135 | shared_segments[i].common.size = allocate_size; 136 | remaining_bytes -= allocate_size; 137 | } 138 | return ALLOC_SUCCESS; 139 | } 140 | 141 | static int detach_segment(zend_shared_segment_shm *shared_segment) 142 | { 143 | shmdt(shared_segment->common.p); 144 | return 0; 145 | } 146 | 147 | static size_t segment_type_size(void) 148 | { 149 | return sizeof(zend_shared_segment_shm); 150 | } 151 | 152 | zend_shared_memory_handlers zend_alloc_shm_handlers = { 153 | (create_segments_t)create_segments, 154 | (detach_segment_t)detach_segment, 155 | segment_type_size}; 156 | 157 | #endif /* USE_SHM */ 158 | -------------------------------------------------------------------------------- /aes.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file aes.h 3 | * 4 | * \brief AES block cipher 5 | * 6 | * Copyright (C) 2006-2010, Brainspark B.V. 7 | * 8 | * This file is part of PolarSSL (http://www.polarssl.org) 9 | * Lead Maintainer: Paul Bakker 10 | * 11 | * All rights reserved. 12 | * 13 | * This program is free software; you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation; either version 2 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License along 24 | * with this program; if not, write to the Free Software Foundation, Inc., 25 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 26 | */ 27 | #ifndef POLARSSL_AES_H 28 | #define POLARSSL_AES_H 29 | 30 | #include 31 | 32 | #define AES_ENCRYPT 1 33 | #define AES_DECRYPT 0 34 | 35 | #define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ 36 | #define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ 37 | 38 | /** 39 | * \brief AES context structure 40 | */ 41 | typedef struct { 42 | int nr; /*!< number of rounds */ 43 | unsigned long *rk; /*!< AES round keys */ 44 | unsigned long buf[68]; /*!< unaligned data */ 45 | } 46 | aes_context; 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | /** 53 | * \brief AES key schedule (encryption) 54 | * 55 | * \param ctx AES context to be initialized 56 | * \param key encryption key 57 | * \param keysize must be 128, 192 or 256 58 | * 59 | * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH 60 | */ 61 | int aes_setkey_enc(aes_context *ctx, const unsigned char *key, unsigned int keysize); 62 | 63 | /** 64 | * \brief AES key schedule (decryption) 65 | * 66 | * \param ctx AES context to be initialized 67 | * \param key decryption key 68 | * \param keysize must be 128, 192 or 256 69 | * 70 | * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH 71 | */ 72 | int aes_setkey_dec(aes_context *ctx, const unsigned char *key, unsigned int keysize); 73 | 74 | /** 75 | * \brief AES-ECB block encryption/decryption 76 | * 77 | * \param ctx AES context 78 | * \param mode AES_ENCRYPT or AES_DECRYPT 79 | * \param input 16-byte input block 80 | * \param output 16-byte output block 81 | * 82 | * \return 0 if successful 83 | */ 84 | int aes_crypt_ecb(aes_context *ctx, 85 | int mode, 86 | const unsigned char input[16], 87 | unsigned char output[16]); 88 | 89 | /** 90 | * \brief AES-CBC buffer encryption/decryption 91 | * Length should be a multiple of the block 92 | * size (16 bytes) 93 | * 94 | * \param ctx AES context 95 | * \param mode AES_ENCRYPT or AES_DECRYPT 96 | * \param length length of the input data 97 | * \param iv initialization vector (updated after use) 98 | * \param input buffer holding the input data 99 | * \param output buffer holding the output data 100 | * 101 | * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH 102 | */ 103 | int aes_crypt_cbc(aes_context *ctx, 104 | int mode, 105 | size_t length, 106 | unsigned char iv[16], 107 | const unsigned char *input, 108 | unsigned char *output); 109 | 110 | /** 111 | * \brief AES-CFB128 buffer encryption/decryption. 112 | * 113 | * \param ctx AES context 114 | * \param mode AES_ENCRYPT or AES_DECRYPT 115 | * \param length length of the input data 116 | * \param iv_off offset in IV (updated after use) 117 | * \param iv initialization vector (updated after use) 118 | * \param input buffer holding the input data 119 | * \param output buffer holding the output data 120 | * 121 | * \return 0 if successful 122 | */ 123 | int aes_crypt_cfb128(aes_context *ctx, 124 | int mode, 125 | size_t length, 126 | size_t *iv_off, 127 | unsigned char iv[16], 128 | const unsigned char *input, 129 | unsigned char *output); 130 | 131 | /* 132 | * \brief AES-CTR buffer encryption/decryption 133 | * 134 | * Warning: You have to keep the maximum use of your counter in mind! 135 | * 136 | * \param length The length of the data 137 | * \param nc_off The offset in the current stream_block (for resuming 138 | * within current cipher stream). The offset pointer to 139 | * should be 0 at the start of a stream. 140 | * \param nonce_counter The 128-bit nonce and counter. 141 | * \param stream_block The saved stream-block for resuming. Is overwritten 142 | * by the function. 143 | * \param input The input data stream 144 | * \param output The output data stream 145 | * 146 | * \return 0 if successful 147 | */ 148 | int aes_crypt_ctr(aes_context *ctx, 149 | size_t length, 150 | size_t *nc_off, 151 | unsigned char nonce_counter[16], 152 | unsigned char stream_block[16], 153 | const unsigned char *input, 154 | unsigned char *output); 155 | 156 | /** 157 | * \brief Checkup routine 158 | * 159 | * \return 0 if successful, or 1 if the test failed 160 | */ 161 | int aes_self_test(int verbose); 162 | 163 | void screw_aes(int crypt, uint8_t *buf, int bufLen, uint8_t *key, int *rLen); 164 | 165 | #ifdef __cplusplus 166 | } 167 | #endif 168 | 169 | #endif /* aes.h */ -------------------------------------------------------------------------------- /zend_shared_alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_SHARED_ALLOC_H 23 | #define ZEND_SHARED_ALLOC_H 24 | 25 | #include "zend.h" 26 | #include "ZendAccelerator.h" 27 | 28 | #if defined(__APPLE__) && defined(__MACH__) /* darwin */ 29 | #ifdef HAVE_SHM_MMAP_POSIX 30 | #define USE_SHM_OPEN 1 31 | #endif 32 | #ifdef HAVE_SHM_MMAP_ANON 33 | #define USE_MMAP 1 34 | #endif 35 | #elif defined(__linux__) || defined(_AIX) 36 | #ifdef HAVE_SHM_IPC 37 | #define USE_SHM 1 38 | #endif 39 | #ifdef HAVE_SHM_MMAP_ANON 40 | #define USE_MMAP 1 41 | #endif 42 | #elif defined(__sparc) || defined(__sun) 43 | #ifdef HAVE_SHM_MMAP_POSIX 44 | #define USE_SHM_OPEN 1 45 | #endif 46 | #ifdef HAVE_SHM_IPC 47 | #define USE_SHM 1 48 | #endif 49 | #if defined(__i386) 50 | #ifdef HAVE_SHM_MMAP_ANON 51 | #define USE_MMAP 1 52 | #endif 53 | #endif 54 | #else 55 | #ifdef HAVE_SHM_MMAP_POSIX 56 | #define USE_SHM_OPEN 1 57 | #endif 58 | #ifdef HAVE_SHM_MMAP_ANON 59 | #define USE_MMAP 1 60 | #endif 61 | #ifdef HAVE_SHM_IPC 62 | #define USE_SHM 1 63 | #endif 64 | #endif 65 | 66 | #define ALLOC_FAILURE 0 67 | #define ALLOC_SUCCESS 1 68 | #define FAILED_REATTACHED 2 69 | #define SUCCESSFULLY_REATTACHED 4 70 | #define ALLOC_FAIL_MAPPING 8 71 | #define ALLOC_FALLBACK 9 72 | 73 | typedef struct _zend_shared_segment 74 | { 75 | size_t size; 76 | size_t pos; /* position for simple stack allocator */ 77 | void *p; 78 | } zend_shared_segment; 79 | 80 | typedef int (*create_segments_t)(size_t requested_size, zend_shared_segment ***shared_segments, int *shared_segment_count, char **error_in); 81 | typedef int (*detach_segment_t)(zend_shared_segment *shared_segment); 82 | 83 | typedef struct 84 | { 85 | create_segments_t create_segments; 86 | detach_segment_t detach_segment; 87 | size_t (*segment_type_size)(void); 88 | } zend_shared_memory_handlers; 89 | 90 | typedef struct _handler_entry 91 | { 92 | const char *name; 93 | zend_shared_memory_handlers *handler; 94 | } zend_shared_memory_handler_entry; 95 | 96 | typedef struct _zend_shared_memory_state 97 | { 98 | int *positions; /* current positions for each segment */ 99 | size_t shared_free; /* amount of free shared memory */ 100 | } zend_shared_memory_state; 101 | 102 | typedef struct _zend_smm_shared_globals 103 | { 104 | /* Shared Memory Manager */ 105 | zend_shared_segment **shared_segments; 106 | /* Number of allocated shared segments */ 107 | int shared_segments_count; 108 | /* Amount of free shared memory */ 109 | size_t shared_free; 110 | /* Amount of shared memory allocated by garbage */ 111 | size_t wasted_shared_memory; 112 | /* No more shared memory flag */ 113 | zend_bool memory_exhausted; 114 | /* Saved Shared Allocator State */ 115 | zend_shared_memory_state shared_memory_state; 116 | /* Pointer to the application's shared data structures */ 117 | void *app_shared_globals; 118 | } zend_smm_shared_globals; 119 | 120 | extern zend_smm_shared_globals *smm_shared_globals; 121 | 122 | #define ZSMMG(element) (smm_shared_globals->element) 123 | 124 | #define SHARED_ALLOC_REATTACHED (SUCCESS + 1) 125 | 126 | int zend_shared_alloc_startup(size_t requested_size); 127 | void zend_shared_alloc_shutdown(void); 128 | 129 | /* allocate shared memory block */ 130 | void *zend_shared_alloc(size_t size); 131 | 132 | /* copy into shared memory */ 133 | void *_zend_shared_memdup(void *p, size_t size, zend_bool free_source); 134 | int zend_shared_memdup_size(void *p, size_t size); 135 | 136 | int zend_accel_in_shm(void *ptr); 137 | 138 | typedef union _align_test 139 | { 140 | void *ptr; 141 | double dbl; 142 | zend_long lng; 143 | } align_test; 144 | 145 | #if ZEND_GCC_VERSION >= 2000 146 | #define PLATFORM_ALIGNMENT (__alignof__(align_test) < 8 ? 8 : __alignof__(align_test)) 147 | #else 148 | #define PLATFORM_ALIGNMENT (sizeof(align_test)) 149 | #endif 150 | 151 | #define ZEND_ALIGNED_SIZE(size) \ 152 | ZEND_MM_ALIGNED_SIZE_EX(size, PLATFORM_ALIGNMENT) 153 | 154 | /* exclusive locking */ 155 | void zend_shared_alloc_lock(void); 156 | void zend_shared_alloc_unlock(void); /* returns the allocated size during lock..unlock */ 157 | void zend_shared_alloc_safe_unlock(void); 158 | 159 | /* old/new mapping functions */ 160 | void zend_shared_alloc_init_xlat_table(void); 161 | void zend_shared_alloc_destroy_xlat_table(void); 162 | void zend_shared_alloc_clear_xlat_table(void); 163 | void zend_shared_alloc_register_xlat_entry(const void *old, const void *new); 164 | void *zend_shared_alloc_get_xlat_entry(const void *old); 165 | 166 | size_t zend_shared_alloc_get_free_memory(void); 167 | void zend_shared_alloc_save_state(void); 168 | void zend_shared_alloc_restore_state(void); 169 | const char *zend_accel_get_shared_model(void); 170 | 171 | /* memory write protection */ 172 | void zend_accel_shared_protect(int mode); 173 | 174 | #ifdef USE_MMAP 175 | extern zend_shared_memory_handlers zend_alloc_mmap_handlers; 176 | #endif 177 | 178 | #ifdef USE_SHM 179 | extern zend_shared_memory_handlers zend_alloc_shm_handlers; 180 | #endif 181 | 182 | #ifdef USE_SHM_OPEN 183 | extern zend_shared_memory_handlers zend_alloc_posix_handlers; 184 | #endif 185 | 186 | #ifdef ZEND_WIN32 187 | extern zend_shared_memory_handlers zend_alloc_win32_handlers; 188 | void zend_shared_alloc_create_lock(void); 189 | void zend_shared_alloc_lock_win32(void); 190 | void zend_shared_alloc_unlock_win32(void); 191 | #endif 192 | 193 | #endif /* ZEND_SHARED_ALLOC_H */ 194 | -------------------------------------------------------------------------------- /Optimizer/zend_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, CFG - Control Flow Graph | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Dmitry Stogov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef ZEND_CFG_H 20 | #define ZEND_CFG_H 21 | 22 | /* zend_basic_bloc.flags */ 23 | #define ZEND_BB_START (1<<0) /* fist block */ 24 | #define ZEND_BB_FOLLOW (1<<1) /* follows the next block */ 25 | #define ZEND_BB_TARGET (1<<2) /* jump taget */ 26 | #define ZEND_BB_EXIT (1<<3) /* without successors */ 27 | #define ZEND_BB_ENTRY (1<<4) /* stackless entry */ 28 | #define ZEND_BB_TRY (1<<5) /* start of try block */ 29 | #define ZEND_BB_CATCH (1<<6) /* start of catch block */ 30 | #define ZEND_BB_FINALLY (1<<7) /* start of finally block */ 31 | #define ZEND_BB_FINALLY_END (1<<8) /* end of finally block */ 32 | #define ZEND_BB_GEN_VAR (1<<9) /* start of live range */ 33 | #define ZEND_BB_KILL_VAR (1<<10) /* end of live range */ 34 | #define ZEND_BB_UNREACHABLE_FREE (1<<11) /* unreachable loop free */ 35 | #define ZEND_BB_RECV_ENTRY (1<<12) /* RECV entry */ 36 | 37 | #define ZEND_BB_LOOP_HEADER (1<<16) 38 | #define ZEND_BB_IRREDUCIBLE_LOOP (1<<17) 39 | 40 | #define ZEND_BB_REACHABLE (1<<31) 41 | 42 | #define ZEND_BB_PROTECTED (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY|ZEND_BB_TRY|ZEND_BB_CATCH|ZEND_BB_FINALLY|ZEND_BB_FINALLY_END|ZEND_BB_GEN_VAR|ZEND_BB_KILL_VAR) 43 | 44 | typedef struct _zend_basic_block { 45 | int *successors; /* successor block indices */ 46 | uint32_t flags; 47 | uint32_t start; /* first opcode number */ 48 | uint32_t len; /* number of opcodes */ 49 | int successors_count; /* number of successors */ 50 | int predecessors_count; /* number of predecessors */ 51 | int predecessor_offset; /* offset of 1-st predecessor */ 52 | int idom; /* immediate dominator block */ 53 | int loop_header; /* closest loop header, or -1 */ 54 | int level; /* steps away from the entry in the dom. tree */ 55 | int children; /* list of dominated blocks */ 56 | int next_child; /* next dominated block */ 57 | int successors_storage[2]; /* up to 2 successor blocks */ 58 | } zend_basic_block; 59 | 60 | /* 61 | +------------+---+---+---+---+---+ 62 | | |OP1|OP2|EXT| 0 | 1 | 63 | +------------+---+---+---+---+---+ 64 | |JMP |ADR| | |OP1| - | 65 | |JMPZ | |ADR| |OP2|FOL| 66 | |JMPNZ | |ADR| |OP2|FOL| 67 | |JMPZNZ | |ADR|ADR|OP2|EXT| 68 | |JMPZ_EX | |ADR| |OP2|FOL| 69 | |JMPNZ_EX | |ADR| |OP2|FOL| 70 | |JMP_SET | |ADR| |OP2|FOL| 71 | |COALESCE | |ADR| |OP2|FOL| 72 | |ASSERT_CHK | |ADR| |OP2|FOL| 73 | |NEW | |ADR| |OP2|FOL| 74 | |DCL_ANON* |ADR| | |OP1|FOL| 75 | |FE_RESET_* | |ADR| |OP2|FOL| 76 | |FE_FETCH_* | | |ADR|EXT|FOL| 77 | |CATCH | | |ADR|EXT|FOL| 78 | |FAST_CALL |ADR| | |OP1|FOL| 79 | |FAST_RET | | | | - | - | 80 | |RETURN* | | | | - | - | 81 | |EXIT | | | | - | - | 82 | |THROW | | | | - | - | 83 | |* | | | |FOL| - | 84 | +------------+---+---+---+---+---+ 85 | */ 86 | 87 | typedef struct _zend_cfg { 88 | int blocks_count; /* number of basic blocks */ 89 | int edges_count; /* number of edges */ 90 | zend_basic_block *blocks; /* array of basic blocks */ 91 | int *predecessors; 92 | uint32_t *map; 93 | unsigned int split_at_live_ranges : 1; 94 | unsigned int split_at_calls : 1; 95 | unsigned int split_at_recv : 1; 96 | unsigned int dynamic : 1; /* accesses varables by name */ 97 | unsigned int vararg : 1; /* uses func_get_args() */ 98 | } zend_cfg; 99 | 100 | /* Build Flags */ 101 | #define ZEND_RT_CONSTANTS (1<<31) 102 | #define ZEND_CFG_STACKLESS (1<<30) 103 | #define ZEND_SSA_DEBUG_LIVENESS (1<<29) 104 | #define ZEND_SSA_DEBUG_PHI_PLACEMENT (1<<28) 105 | #define ZEND_SSA_RC_INFERENCE (1<<27) 106 | #define ZEND_CFG_SPLIT_AT_LIVE_RANGES (1<<26) 107 | #define ZEND_CFG_NO_ENTRY_PREDECESSORS (1<<25) 108 | #define ZEND_CFG_RECV_ENTRY (1<<24) 109 | #define ZEND_CALL_TREE (1<<23) 110 | #define ZEND_SSA_USE_CV_RESULTS (1<<22) 111 | 112 | #define CRT_CONSTANT_EX(op_array, node, rt_constants) \ 113 | ((rt_constants) ? \ 114 | RT_CONSTANT(op_array, (node)) \ 115 | : \ 116 | CT_CONSTANT_EX(op_array, (node).constant) \ 117 | ) 118 | 119 | #define CRT_CONSTANT(node) \ 120 | CRT_CONSTANT_EX(op_array, node, (build_flags & ZEND_RT_CONSTANTS)) 121 | 122 | #define RETURN_VALUE_USED(opline) \ 123 | ((opline)->result_type != IS_UNUSED) 124 | 125 | BEGIN_EXTERN_C() 126 | 127 | int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg, uint32_t *func_flags); 128 | void zend_cfg_remark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg); 129 | int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg); 130 | int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cfg); 131 | int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32_t *flags); 132 | 133 | END_EXTERN_C() 134 | 135 | #endif /* ZEND_CFG_H */ 136 | 137 | /* 138 | * Local variables: 139 | * tab-width: 4 140 | * c-basic-offset: 4 141 | * indent-tabs-mode: t 142 | * End: 143 | */ 144 | -------------------------------------------------------------------------------- /md5.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned char PADDING[] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 7 | 8 | void MD5Init(MD5_CTX *context) { 9 | context->count[0] = 0; 10 | context->count[1] = 0; 11 | context->state[0] = 0x67452301; 12 | context->state[1] = 0xEFCDAB89; 13 | context->state[2] = 0x98BADCFE; 14 | context->state[3] = 0x10325476; 15 | } 16 | 17 | void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen) { 18 | unsigned int i = 0, index = 0, partlen = 0; 19 | index = (context->count[0] >> 3) & 0x3F; 20 | partlen = 64 - index; 21 | context->count[0] += inputlen << 3; 22 | if (context->count[0] < (inputlen << 3)) 23 | context->count[1]++; 24 | context->count[1] += inputlen >> 29; 25 | 26 | if (inputlen >= partlen) { 27 | memcpy(&context->buffer[index], input, partlen); 28 | MD5Transform(context->state, context->buffer); 29 | for (i = partlen; i + 64 <= inputlen; i += 64) 30 | MD5Transform(context->state, &input[i]); 31 | index = 0; 32 | } else { 33 | i = 0; 34 | } 35 | memcpy(&context->buffer[index], &input[i], inputlen - i); 36 | } 37 | 38 | void MD5Final(MD5_CTX *context, unsigned char digest[16]) { 39 | unsigned int index = 0, padlen = 0; 40 | unsigned char bits[8]; 41 | index = (context->count[0] >> 3) & 0x3F; 42 | padlen = (index < 56) ? (56 - index) : (120 - index); 43 | MD5Encode(bits, context->count, 8); 44 | MD5Update(context, PADDING, padlen); 45 | MD5Update(context, bits, 8); 46 | MD5Encode(digest, context->state, 16); 47 | } 48 | 49 | void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len) { 50 | unsigned int i = 0, j = 0; 51 | while (j < len) { 52 | output[j] = input[i] & 0xFF; 53 | output[j + 1] = (input[i] >> 8) & 0xFF; 54 | output[j + 2] = (input[i] >> 16) & 0xFF; 55 | output[j + 3] = (input[i] >> 24) & 0xFF; 56 | i++; 57 | j += 4; 58 | } 59 | } 60 | 61 | void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len) { 62 | unsigned int i = 0, j = 0; 63 | while (j < len) { 64 | output[i] = (input[j]) | 65 | (input[j + 1] << 8) | 66 | (input[j + 2] << 16) | 67 | (input[j + 3] << 24); 68 | i++; 69 | j += 4; 70 | } 71 | } 72 | 73 | void MD5Transform(unsigned int state[4], unsigned char block[64]) { 74 | unsigned int a = state[0]; 75 | unsigned int b = state[1]; 76 | unsigned int c = state[2]; 77 | unsigned int d = state[3]; 78 | unsigned int x[64]; 79 | MD5Decode(x, block, 64); 80 | FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */ 81 | FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */ 82 | FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */ 83 | FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */ 84 | FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */ 85 | FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */ 86 | FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */ 87 | FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */ 88 | FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */ 89 | FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */ 90 | FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */ 91 | FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */ 92 | FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */ 93 | FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */ 94 | FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */ 95 | FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */ 96 | 97 | /* Round 2 */ 98 | GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */ 99 | GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */ 100 | GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */ 101 | GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */ 102 | GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */ 103 | GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */ 104 | GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */ 105 | GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */ 106 | GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */ 107 | GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */ 108 | GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */ 109 | GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */ 110 | GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */ 111 | GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */ 112 | GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */ 113 | GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */ 114 | 115 | /* Round 3 */ 116 | HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */ 117 | HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */ 118 | HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */ 119 | HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */ 120 | HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */ 121 | HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */ 122 | HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */ 123 | HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */ 124 | HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */ 125 | HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */ 126 | HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */ 127 | HH(b, c, d, a, x[6], 23, 0x4881d05); /* 44 */ 128 | HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */ 129 | HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */ 130 | HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */ 131 | HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */ 132 | 133 | /* Round 4 */ 134 | II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */ 135 | II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */ 136 | II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */ 137 | II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */ 138 | II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */ 139 | II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */ 140 | II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */ 141 | II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */ 142 | II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */ 143 | II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */ 144 | II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */ 145 | II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */ 146 | II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */ 147 | II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */ 148 | II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */ 149 | II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */ 150 | state[0] += a; 151 | state[1] += b; 152 | state[2] += c; 153 | state[3] += d; 154 | } 155 | 156 | char *md5(char *str) { 157 | char *dest = (char *) calloc(32, sizeof(char)); 158 | unsigned char Crypt[16]; 159 | char *r; 160 | int i; 161 | memset(dest, 0, sizeof(dest)); 162 | MD5_CTX md5; 163 | MD5Init(&md5); 164 | MD5Update(&md5, str, strlen(str)); 165 | MD5Final(&md5, Crypt); 166 | for (i = 0; i < 16; i++) sprintf(dest + i * 2, "%02x", Crypt[i]); 167 | return dest; 168 | } -------------------------------------------------------------------------------- /Optimizer/zend_optimizer_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_OPTIMIZER_INTERNAL_H 23 | #define ZEND_OPTIMIZER_INTERNAL_H 24 | 25 | #include "zend_ssa.h" 26 | #include "zend_func_info.h" 27 | 28 | #define ZEND_OP1_LITERAL(opline) (op_array)->literals[(opline)->op1.constant] 29 | #define ZEND_OP1_JMP_ADDR(opline) OP_JMP_ADDR(opline, (opline)->op1) 30 | #define ZEND_OP2_LITERAL(opline) (op_array)->literals[(opline)->op2.constant] 31 | #define ZEND_OP2_JMP_ADDR(opline) OP_JMP_ADDR(opline, (opline)->op2) 32 | 33 | #define VAR_NUM(v) EX_VAR_TO_NUM(v) 34 | #define NUM_VAR(v) ((uint32_t)(zend_uintptr_t)ZEND_CALL_VAR_NUM(0, v)) 35 | 36 | #define INV_COND(op) ((op) == ZEND_JMPZ ? ZEND_JMPNZ : ZEND_JMPZ) 37 | #define INV_EX_COND(op) ((op) == ZEND_JMPZ_EX ? ZEND_JMPNZ : ZEND_JMPZ) 38 | #define INV_COND_EX(op) ((op) == ZEND_JMPZ ? ZEND_JMPNZ_EX : ZEND_JMPZ_EX) 39 | #define INV_EX_COND_EX(op) ((op) == ZEND_JMPZ_EX ? ZEND_JMPNZ_EX : ZEND_JMPZ_EX) 40 | 41 | #define RESULT_UNUSED(op) (op->result_type == IS_UNUSED) 42 | #define SAME_VAR(op1, op2) (op1##_type == op2##_type && op1.var == op2.var) 43 | 44 | typedef struct _zend_optimizer_ctx 45 | { 46 | zend_arena *arena; 47 | zend_script *script; 48 | HashTable *constants; 49 | zend_long optimization_level; 50 | zend_long debug_level; 51 | } zend_optimizer_ctx; 52 | 53 | #define LITERAL_LONG(op, val) \ 54 | do \ 55 | { \ 56 | zval _c; \ 57 | ZVAL_LONG(&_c, val); \ 58 | op.constant = zend_optimizer_add_literal(op_array, &_c); \ 59 | } while (0) 60 | 61 | #define LITERAL_BOOL(op, val) \ 62 | do \ 63 | { \ 64 | zval _c; \ 65 | ZVAL_BOOL(&_c, val); \ 66 | op.constant = zend_optimizer_add_literal(op_array, &_c); \ 67 | } while (0) 68 | 69 | #define literal_dtor(zv) \ 70 | do \ 71 | { \ 72 | zval_ptr_dtor_nogc(zv); \ 73 | ZVAL_NULL(zv); \ 74 | } while (0) 75 | 76 | #define COPY_NODE(target, src) \ 77 | do \ 78 | { \ 79 | target##_type = src##_type; \ 80 | target = src; \ 81 | } while (0) 82 | 83 | int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv); 84 | int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy); 85 | void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval *value); 86 | int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval *value); 87 | int zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval *op1, zval *op2); 88 | int zend_optimizer_eval_unary_op(zval *result, zend_uchar opcode, zval *op1); 89 | int zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1); 90 | int zend_optimizer_eval_strlen(zval *result, zval *op1); 91 | int zend_optimizer_update_op1_const(zend_op_array *op_array, 92 | zend_op *opline, 93 | zval *val); 94 | int zend_optimizer_update_op2_const(zend_op_array *op_array, 95 | zend_op *opline, 96 | zval *val); 97 | int zend_optimizer_replace_by_const(zend_op_array *op_array, 98 | zend_op *opline, 99 | zend_uchar type, 100 | uint32_t var, 101 | zval *val); 102 | 103 | void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var); 104 | void zend_optimizer_remove_live_range_ex(zend_op_array *op_array, uint32_t var, uint32_t start); 105 | void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx); 106 | void zend_optimizer_pass2(zend_op_array *op_array); 107 | void zend_optimizer_pass3(zend_op_array *op_array); 108 | void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx); 109 | void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx); 110 | void zend_optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx); 111 | int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, uint32_t *flags); 112 | void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map); 113 | void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx); 114 | void zend_optimizer_nop_removal(zend_op_array *op_array); 115 | void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx); 116 | void zend_optimizer_compact_vars(zend_op_array *op_array); 117 | int zend_optimizer_is_disabled_func(const char *name, size_t len); 118 | zend_function *zend_optimizer_get_called_func( 119 | zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants); 120 | uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args); 121 | void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline); 122 | void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist); 123 | zend_uchar zend_compound_assign_to_binary_op(zend_uchar opcode); 124 | int sccp_optimize_op_array(zend_optimizer_ctx *ctx, zend_op_array *op_arrya, zend_ssa *ssa, zend_call_info **call_map); 125 | int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_bool reorder_dtor_effects); 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /Optimizer/optimize_temp_vars_5.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #include "php.h" 23 | #include "Optimizer/zend_optimizer.h" 24 | #include "Optimizer/zend_optimizer_internal.h" 25 | #include "zend_API.h" 26 | #include "zend_constants.h" 27 | #include "zend_execute.h" 28 | #include "zend_vm.h" 29 | #include "zend_bitset.h" 30 | 31 | #define GET_AVAILABLE_T() \ 32 | for (i = 0; i < T; i++) \ 33 | { \ 34 | if (!zend_bitset_in(taken_T, i)) \ 35 | { \ 36 | break; \ 37 | } \ 38 | } \ 39 | zend_bitset_incl(taken_T, i); \ 40 | if (i > max) \ 41 | { \ 42 | max = i; \ 43 | } 44 | 45 | void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx) 46 | { 47 | int T = op_array->T; 48 | int offset = op_array->last_var; 49 | uint32_t bitset_len; 50 | zend_bitset taken_T; /* T index in use */ 51 | zend_op **start_of_T; /* opline where T is first used */ 52 | zend_bitset valid_T; /* Is the map_T valid */ 53 | int *map_T; /* Map's the T to its new index */ 54 | zend_op *opline, *end; 55 | int currT; 56 | int i; 57 | int max = -1; 58 | int var_to_free = -1; 59 | void *checkpoint = zend_arena_checkpoint(ctx->arena); 60 | 61 | bitset_len = zend_bitset_len(T); 62 | taken_T = (zend_bitset)zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); 63 | start_of_T = (zend_op **)zend_arena_alloc(&ctx->arena, T * sizeof(zend_op *)); 64 | valid_T = (zend_bitset)zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); 65 | map_T = (int *)zend_arena_alloc(&ctx->arena, T * sizeof(int)); 66 | 67 | end = op_array->opcodes; 68 | opline = &op_array->opcodes[op_array->last - 1]; 69 | 70 | /* Find T definition points */ 71 | while (opline >= end) 72 | { 73 | if (opline->result_type & (IS_VAR | IS_TMP_VAR)) 74 | { 75 | start_of_T[VAR_NUM(opline->result.var) - offset] = opline; 76 | } 77 | opline--; 78 | } 79 | 80 | zend_bitset_clear(valid_T, bitset_len); 81 | zend_bitset_clear(taken_T, bitset_len); 82 | 83 | end = op_array->opcodes; 84 | opline = &op_array->opcodes[op_array->last - 1]; 85 | 86 | while (opline >= end) 87 | { 88 | if ((opline->op1_type & (IS_VAR | IS_TMP_VAR))) 89 | { 90 | currT = VAR_NUM(opline->op1.var) - offset; 91 | if (opline->opcode == ZEND_ROPE_END) 92 | { 93 | int num = (((opline->extended_value + 1) * sizeof(zend_string *)) + (sizeof(zval) - 1)) / sizeof(zval); 94 | int var; 95 | 96 | var = max; 97 | while (var >= 0 && !zend_bitset_in(taken_T, var)) 98 | { 99 | var--; 100 | } 101 | max = MAX(max, var + num); 102 | var = var + 1; 103 | map_T[currT] = var; 104 | zend_bitset_incl(valid_T, currT); 105 | zend_bitset_incl(taken_T, var); 106 | opline->op1.var = NUM_VAR(var + offset); 107 | while (num > 1) 108 | { 109 | num--; 110 | zend_bitset_incl(taken_T, var + num); 111 | } 112 | } 113 | else 114 | { 115 | if (!zend_bitset_in(valid_T, currT)) 116 | { 117 | int use_new_var = 0; 118 | 119 | /* Code in "finally" blocks may modify temorary variables. 120 | * We allocate new temporaries for values that need to 121 | * relive FAST_CALLs. 122 | */ 123 | if ((op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) && 124 | (opline->opcode == ZEND_RETURN || 125 | opline->opcode == ZEND_GENERATOR_RETURN || 126 | opline->opcode == ZEND_RETURN_BY_REF || 127 | opline->opcode == ZEND_FREE || 128 | opline->opcode == ZEND_FE_FREE)) 129 | { 130 | zend_op *curr = opline; 131 | 132 | while (--curr >= end) 133 | { 134 | if (curr->opcode == ZEND_FAST_CALL) 135 | { 136 | use_new_var = 1; 137 | break; 138 | } 139 | else if (curr->opcode != ZEND_FREE && 140 | curr->opcode != ZEND_FE_FREE && 141 | curr->opcode != ZEND_VERIFY_RETURN_TYPE && 142 | curr->opcode != ZEND_DISCARD_EXCEPTION) 143 | { 144 | break; 145 | } 146 | } 147 | } 148 | if (use_new_var) 149 | { 150 | i = ++max; 151 | zend_bitset_incl(taken_T, i); 152 | } 153 | else 154 | { 155 | GET_AVAILABLE_T(); 156 | } 157 | map_T[currT] = i; 158 | zend_bitset_incl(valid_T, currT); 159 | } 160 | opline->op1.var = NUM_VAR(map_T[currT] + offset); 161 | } 162 | } 163 | 164 | if ((opline->op2_type & (IS_VAR | IS_TMP_VAR))) 165 | { 166 | currT = VAR_NUM(opline->op2.var) - offset; 167 | if (!zend_bitset_in(valid_T, currT)) 168 | { 169 | GET_AVAILABLE_T(); 170 | map_T[currT] = i; 171 | zend_bitset_incl(valid_T, currT); 172 | } 173 | opline->op2.var = NUM_VAR(map_T[currT] + offset); 174 | } 175 | 176 | if (opline->result_type & (IS_VAR | IS_TMP_VAR)) 177 | { 178 | currT = VAR_NUM(opline->result.var) - offset; 179 | if (zend_bitset_in(valid_T, currT)) 180 | { 181 | if (start_of_T[currT] == opline) 182 | { 183 | /* ZEND_FAST_CALL can not share temporary var with others 184 | * since the fast_var could also be set by ZEND_HANDLE_EXCEPTION 185 | * which could be ahead of it */ 186 | if (opline->opcode != ZEND_FAST_CALL) 187 | { 188 | zend_bitset_excl(taken_T, map_T[currT]); 189 | } 190 | } 191 | opline->result.var = NUM_VAR(map_T[currT] + offset); 192 | if (opline->opcode == ZEND_ROPE_INIT) 193 | { 194 | if (start_of_T[currT] == opline) 195 | { 196 | uint32_t num = ((opline->extended_value * sizeof(zend_string *)) + (sizeof(zval) - 1)) / sizeof(zval); 197 | while (num > 1) 198 | { 199 | num--; 200 | zend_bitset_excl(taken_T, map_T[currT] + num); 201 | } 202 | } 203 | } 204 | } 205 | else 206 | { 207 | /* Code which gets here is using a wrongly built opcode such as RECV() */ 208 | GET_AVAILABLE_T(); 209 | map_T[currT] = i; 210 | zend_bitset_incl(valid_T, currT); 211 | opline->result.var = NUM_VAR(i + offset); 212 | } 213 | } 214 | 215 | if (var_to_free >= 0) 216 | { 217 | zend_bitset_excl(taken_T, var_to_free); 218 | var_to_free = -1; 219 | } 220 | 221 | opline--; 222 | } 223 | 224 | if (op_array->live_range) 225 | { 226 | for (i = 0; i < op_array->last_live_range; i++) 227 | { 228 | op_array->live_range[i].var = 229 | NUM_VAR(map_T[VAR_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK) - offset] + offset) | 230 | (op_array->live_range[i].var & ZEND_LIVE_MASK); 231 | } 232 | } 233 | 234 | zend_arena_release(&ctx->arena, checkpoint); 235 | op_array->T = max + 1; 236 | } 237 | -------------------------------------------------------------------------------- /Optimizer/pass2.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | /* pass 2: 23 | * - convert non-numeric constants to numeric constants in numeric operators 24 | * - optimize constant conditional JMPs 25 | */ 26 | 27 | #include "php.h" 28 | #include "Optimizer/zend_optimizer.h" 29 | #include "Optimizer/zend_optimizer_internal.h" 30 | #include "zend_API.h" 31 | #include "zend_constants.h" 32 | #include "zend_execute.h" 33 | #include "zend_vm.h" 34 | 35 | void zend_optimizer_pass2(zend_op_array *op_array) 36 | { 37 | zend_op *opline; 38 | zend_op *end = op_array->opcodes + op_array->last; 39 | 40 | opline = op_array->opcodes; 41 | while (opline < end) 42 | { 43 | switch (opline->opcode) 44 | { 45 | case ZEND_ADD: 46 | case ZEND_SUB: 47 | case ZEND_MUL: 48 | case ZEND_DIV: 49 | case ZEND_POW: 50 | if (opline->op1_type == IS_CONST) 51 | { 52 | if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) 53 | { 54 | /* don't optimise if it should produce a runtime numeric string error */ 55 | if (is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0)) 56 | { 57 | convert_scalar_to_number(&ZEND_OP1_LITERAL(opline)); 58 | } 59 | } 60 | } 61 | /* break missing *intentionally* - the assign_op's may only optimize op2 */ 62 | case ZEND_ASSIGN_ADD: 63 | case ZEND_ASSIGN_SUB: 64 | case ZEND_ASSIGN_MUL: 65 | case ZEND_ASSIGN_DIV: 66 | case ZEND_ASSIGN_POW: 67 | if (opline->extended_value != 0) 68 | { 69 | /* object tristate op - don't attempt to optimize it! */ 70 | break; 71 | } 72 | if (opline->op2_type == IS_CONST) 73 | { 74 | if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) 75 | { 76 | /* don't optimise if it should produce a runtime numeric string error */ 77 | if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) 78 | { 79 | convert_scalar_to_number(&ZEND_OP2_LITERAL(opline)); 80 | } 81 | } 82 | } 83 | break; 84 | 85 | case ZEND_MOD: 86 | case ZEND_SL: 87 | case ZEND_SR: 88 | if (opline->op1_type == IS_CONST) 89 | { 90 | if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_LONG) 91 | { 92 | /* don't optimise if it should produce a runtime numeric string error */ 93 | if (!(Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && !is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0))) 94 | { 95 | convert_to_long(&ZEND_OP1_LITERAL(opline)); 96 | } 97 | } 98 | } 99 | /* break missing *intentionally - the assign_op's may only optimize op2 */ 100 | case ZEND_ASSIGN_MOD: 101 | case ZEND_ASSIGN_SL: 102 | case ZEND_ASSIGN_SR: 103 | if (opline->extended_value != 0) 104 | { 105 | /* object tristate op - don't attempt to optimize it! */ 106 | break; 107 | } 108 | if (opline->op2_type == IS_CONST) 109 | { 110 | if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) 111 | { 112 | /* don't optimise if it should produce a runtime numeric string error */ 113 | if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING && !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) 114 | { 115 | convert_to_long(&ZEND_OP2_LITERAL(opline)); 116 | } 117 | } 118 | } 119 | break; 120 | 121 | case ZEND_CONCAT: 122 | case ZEND_FAST_CONCAT: 123 | if (opline->op1_type == IS_CONST) 124 | { 125 | if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) 126 | { 127 | convert_to_string(&ZEND_OP1_LITERAL(opline)); 128 | } 129 | } 130 | /* break missing *intentionally - the assign_op's may only optimize op2 */ 131 | case ZEND_ASSIGN_CONCAT: 132 | if (opline->extended_value != 0) 133 | { 134 | /* object tristate op - don't attempt to optimize it! */ 135 | break; 136 | } 137 | if (opline->op2_type == IS_CONST) 138 | { 139 | if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) 140 | { 141 | convert_to_string(&ZEND_OP2_LITERAL(opline)); 142 | } 143 | } 144 | break; 145 | 146 | case ZEND_JMPZ_EX: 147 | case ZEND_JMPNZ_EX: 148 | /* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */ 149 | #if 0 150 | /* Disabled unsafe pattern: in conjunction with 151 | * ZEND_VM_SMART_BRANCH() this may improperly eliminate 152 | * assignment to Ti. 153 | */ 154 | if (opline->op1_type == IS_TMP_VAR && 155 | opline->result_type == IS_TMP_VAR && 156 | opline->op1.var == opline->result.var) { 157 | opline->opcode -= 3; 158 | SET_UNUSED(opline->result); 159 | } else 160 | #endif 161 | /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C) 162 | in case we know it wouldn't jump */ 163 | if (opline->op1_type == IS_CONST) 164 | { 165 | int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline)); 166 | if (opline->opcode == ZEND_JMPZ_EX) 167 | { 168 | should_jmp = !should_jmp; 169 | } 170 | if (!should_jmp) 171 | { 172 | opline->opcode = ZEND_QM_ASSIGN; 173 | SET_UNUSED(opline->op2); 174 | } 175 | } 176 | break; 177 | 178 | case ZEND_JMPZ: 179 | case ZEND_JMPNZ: 180 | if (opline->op1_type == IS_CONST) 181 | { 182 | int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline)); 183 | 184 | if (opline->opcode == ZEND_JMPZ) 185 | { 186 | should_jmp = !should_jmp; 187 | } 188 | literal_dtor(&ZEND_OP1_LITERAL(opline)); 189 | opline->op1_type = IS_UNUSED; 190 | if (should_jmp) 191 | { 192 | opline->opcode = ZEND_JMP; 193 | COPY_NODE(opline->op1, opline->op2); 194 | } 195 | else 196 | { 197 | MAKE_NOP(opline); 198 | } 199 | break; 200 | } 201 | if ((opline + 1)->opcode == ZEND_JMP) 202 | { 203 | /* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */ 204 | /* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */ 205 | if (ZEND_OP2_JMP_ADDR(opline) == ZEND_OP1_JMP_ADDR(opline + 1)) 206 | { 207 | /* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */ 208 | if (opline->op1_type == IS_CV) 209 | { 210 | opline->opcode = ZEND_CHECK_VAR; 211 | opline->op2.num = 0; 212 | } 213 | else if (opline->op1_type & (IS_TMP_VAR | IS_VAR)) 214 | { 215 | opline->opcode = ZEND_FREE; 216 | opline->op2.num = 0; 217 | } 218 | else 219 | { 220 | MAKE_NOP(opline); 221 | } 222 | } 223 | else 224 | { 225 | if (opline->opcode == ZEND_JMPZ) 226 | { 227 | opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP1_JMP_ADDR(opline + 1)); 228 | } 229 | else 230 | { 231 | opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP2_JMP_ADDR(opline)); 232 | ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(opline + 1)); 233 | } 234 | opline->opcode = ZEND_JMPZNZ; 235 | } 236 | } 237 | break; 238 | 239 | case ZEND_JMPZNZ: 240 | if (opline->op1_type == IS_CONST) 241 | { 242 | zend_op *target_opline; 243 | 244 | if (zend_is_true(&ZEND_OP1_LITERAL(opline))) 245 | { 246 | target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */ 247 | } 248 | else 249 | { 250 | target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */ 251 | } 252 | literal_dtor(&ZEND_OP1_LITERAL(opline)); 253 | ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline); 254 | opline->op1_type = IS_UNUSED; 255 | opline->opcode = ZEND_JMP; 256 | } 257 | break; 258 | } 259 | opline++; 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /zend_accelerator_hash.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #include "ZendAccelerator.h" 23 | #include "zend_accelerator_hash.h" 24 | #include "zend_hash.h" 25 | #include "zend_shared_alloc.h" 26 | 27 | /* Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */ 28 | static uint32_t prime_numbers[] = 29 | {5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793}; 30 | static uint32_t num_prime_numbers = sizeof(prime_numbers) / sizeof(uint32_t); 31 | 32 | void zend_accel_hash_clean(zend_accel_hash *accel_hash) 33 | { 34 | accel_hash->num_entries = 0; 35 | accel_hash->num_direct_entries = 0; 36 | memset(accel_hash->hash_table, 0, sizeof(zend_accel_hash_entry *) * accel_hash->max_num_entries); 37 | } 38 | 39 | void zend_accel_hash_init(zend_accel_hash *accel_hash, uint32_t hash_size) 40 | { 41 | uint32_t i; 42 | 43 | for (i = 0; i < num_prime_numbers; i++) 44 | { 45 | if (hash_size <= prime_numbers[i]) 46 | { 47 | hash_size = prime_numbers[i]; 48 | break; 49 | } 50 | } 51 | 52 | accel_hash->num_entries = 0; 53 | accel_hash->num_direct_entries = 0; 54 | accel_hash->max_num_entries = hash_size; 55 | 56 | /* set up hash pointers table */ 57 | accel_hash->hash_table = zend_shared_alloc(sizeof(zend_accel_hash_entry *) * accel_hash->max_num_entries); 58 | if (!accel_hash->hash_table) 59 | { 60 | zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); 61 | return; 62 | } 63 | 64 | /* set up hash values table */ 65 | accel_hash->hash_entries = zend_shared_alloc(sizeof(zend_accel_hash_entry) * accel_hash->max_num_entries); 66 | if (!accel_hash->hash_entries) 67 | { 68 | zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); 69 | return; 70 | } 71 | memset(accel_hash->hash_table, 0, sizeof(zend_accel_hash_entry *) * accel_hash->max_num_entries); 72 | } 73 | 74 | /* Returns NULL if hash is full 75 | * Returns pointer the actual hash entry on success 76 | * key needs to be already allocated as it is not copied 77 | */ 78 | zend_accel_hash_entry *zend_accel_hash_update(zend_accel_hash *accel_hash, char *key, uint32_t key_length, zend_bool indirect, void *data) 79 | { 80 | zend_ulong hash_value; 81 | zend_ulong index; 82 | zend_accel_hash_entry *entry; 83 | zend_accel_hash_entry *indirect_bucket = NULL; 84 | 85 | if (indirect) 86 | { 87 | indirect_bucket = (zend_accel_hash_entry *)data; 88 | while (indirect_bucket->indirect) 89 | { 90 | indirect_bucket = (zend_accel_hash_entry *)indirect_bucket->data; 91 | } 92 | } 93 | 94 | hash_value = zend_inline_hash_func(key, key_length); 95 | #ifndef ZEND_WIN32 96 | hash_value ^= ZCG(root_hash); 97 | #endif 98 | index = hash_value % accel_hash->max_num_entries; 99 | 100 | /* try to see if the element already exists in the hash */ 101 | entry = accel_hash->hash_table[index]; 102 | while (entry) 103 | { 104 | if (entry->hash_value == hash_value && entry->key_length == key_length && !memcmp(entry->key, key, key_length)) 105 | { 106 | 107 | if (entry->indirect) 108 | { 109 | if (indirect_bucket) 110 | { 111 | entry->data = indirect_bucket; 112 | } 113 | else 114 | { 115 | ((zend_accel_hash_entry *)entry->data)->data = data; 116 | } 117 | } 118 | else 119 | { 120 | if (indirect_bucket) 121 | { 122 | accel_hash->num_direct_entries--; 123 | entry->data = indirect_bucket; 124 | entry->indirect = 1; 125 | } 126 | else 127 | { 128 | entry->data = data; 129 | } 130 | } 131 | return entry; 132 | } 133 | entry = entry->next; 134 | } 135 | 136 | /* Does not exist, add a new entry */ 137 | if (accel_hash->num_entries == accel_hash->max_num_entries) 138 | { 139 | return NULL; 140 | } 141 | 142 | entry = &accel_hash->hash_entries[accel_hash->num_entries++]; 143 | if (indirect) 144 | { 145 | entry->data = indirect_bucket; 146 | entry->indirect = 1; 147 | } 148 | else 149 | { 150 | accel_hash->num_direct_entries++; 151 | entry->data = data; 152 | entry->indirect = 0; 153 | } 154 | entry->hash_value = hash_value; 155 | entry->key = key; 156 | entry->key_length = key_length; 157 | entry->next = accel_hash->hash_table[index]; 158 | accel_hash->hash_table[index] = entry; 159 | return entry; 160 | } 161 | 162 | static zend_always_inline void *zend_accel_hash_find_ex(zend_accel_hash *accel_hash, char *key, uint32_t key_length, zend_ulong hash_value, int data) 163 | { 164 | zend_ulong index; 165 | zend_accel_hash_entry *entry; 166 | 167 | #ifndef ZEND_WIN32 168 | hash_value ^= ZCG(root_hash); 169 | #endif 170 | index = hash_value % accel_hash->max_num_entries; 171 | 172 | entry = accel_hash->hash_table[index]; 173 | while (entry) 174 | { 175 | if (entry->hash_value == hash_value && entry->key_length == key_length && !memcmp(entry->key, key, key_length)) 176 | { 177 | if (entry->indirect) 178 | { 179 | if (data) 180 | { 181 | return ((zend_accel_hash_entry *)entry->data)->data; 182 | } 183 | else 184 | { 185 | return entry->data; 186 | } 187 | } 188 | else 189 | { 190 | if (data) 191 | { 192 | return entry->data; 193 | } 194 | else 195 | { 196 | return entry; 197 | } 198 | } 199 | } 200 | entry = entry->next; 201 | } 202 | return NULL; 203 | } 204 | 205 | /* Returns the data associated with key on success 206 | * Returns NULL if data doesn't exist 207 | */ 208 | void *zend_accel_hash_find(zend_accel_hash *accel_hash, zend_string *key) 209 | { 210 | return zend_accel_hash_find_ex( 211 | accel_hash, 212 | ZSTR_VAL(key), 213 | ZSTR_LEN(key), 214 | zend_string_hash_val(key), 215 | 1); 216 | } 217 | 218 | /* Returns the hash entry associated with key on success 219 | * Returns NULL if it doesn't exist 220 | */ 221 | zend_accel_hash_entry *zend_accel_hash_find_entry(zend_accel_hash *accel_hash, zend_string *key) 222 | { 223 | return (zend_accel_hash_entry *)zend_accel_hash_find_ex( 224 | accel_hash, 225 | ZSTR_VAL(key), 226 | ZSTR_LEN(key), 227 | zend_string_hash_val(key), 228 | 0); 229 | } 230 | 231 | /* Returns the data associated with key on success 232 | * Returns NULL if data doesn't exist 233 | */ 234 | void *zend_accel_hash_str_find(zend_accel_hash *accel_hash, char *key, uint32_t key_length) 235 | { 236 | return zend_accel_hash_find_ex( 237 | accel_hash, 238 | key, 239 | key_length, 240 | zend_inline_hash_func(key, key_length), 241 | 1); 242 | } 243 | 244 | /* Returns the hash entry associated with key on success 245 | * Returns NULL if it doesn't exist 246 | */ 247 | zend_accel_hash_entry *zend_accel_hash_str_find_entry(zend_accel_hash *accel_hash, char *key, uint32_t key_length) 248 | { 249 | return (zend_accel_hash_entry *)zend_accel_hash_find_ex( 250 | accel_hash, 251 | key, 252 | key_length, 253 | zend_inline_hash_func(key, key_length), 254 | 0); 255 | } 256 | 257 | int zend_accel_hash_unlink(zend_accel_hash *accel_hash, char *key, uint32_t key_length) 258 | { 259 | zend_ulong hash_value; 260 | zend_ulong index; 261 | zend_accel_hash_entry *entry, *last_entry = NULL; 262 | 263 | hash_value = zend_inline_hash_func(key, key_length); 264 | #ifndef ZEND_WIN32 265 | hash_value ^= ZCG(root_hash); 266 | #endif 267 | index = hash_value % accel_hash->max_num_entries; 268 | 269 | entry = accel_hash->hash_table[index]; 270 | while (entry) 271 | { 272 | if (entry->hash_value == hash_value && entry->key_length == key_length && !memcmp(entry->key, key, key_length)) 273 | { 274 | if (!entry->indirect) 275 | { 276 | accel_hash->num_direct_entries--; 277 | } 278 | if (last_entry) 279 | { 280 | last_entry->next = entry->next; 281 | } 282 | else 283 | { 284 | accel_hash->hash_table[index] = entry->next; 285 | } 286 | return SUCCESS; 287 | } 288 | last_entry = entry; 289 | entry = entry->next; 290 | } 291 | return FAILURE; 292 | } 293 | -------------------------------------------------------------------------------- /Optimizer/zend_dfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, DFG - Data Flow Graph | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Dmitry Stogov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #include "php.h" 20 | #include "zend_compile.h" 21 | #include "zend_dfg.h" 22 | 23 | int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg *dfg, uint32_t build_flags) /* {{{ */ 24 | { 25 | int set_size; 26 | zend_basic_block *blocks = cfg->blocks; 27 | int blocks_count = cfg->blocks_count; 28 | zend_bitset tmp, def, use, in, out; 29 | int k; 30 | uint32_t var_num; 31 | int j; 32 | 33 | set_size = dfg->size; 34 | tmp = dfg->tmp; 35 | def = dfg->def; 36 | use = dfg->use; 37 | in = dfg->in; 38 | out = dfg->out; 39 | 40 | /* Collect "def" and "use" sets */ 41 | for (j = 0; j < blocks_count; j++) { 42 | zend_op *opline, *end; 43 | if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) { 44 | continue; 45 | } 46 | 47 | opline = op_array->opcodes + blocks[j].start; 48 | end = opline + blocks[j].len; 49 | for (; opline < end; opline++) { 50 | if (opline->opcode != ZEND_OP_DATA) { 51 | zend_op *next = opline + 1; 52 | if (next < end && next->opcode == ZEND_OP_DATA) { 53 | if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { 54 | var_num = EX_VAR_TO_NUM(next->op1.var); 55 | if (!DFG_ISSET(def, set_size, j, var_num)) { 56 | DFG_SET(use, set_size, j, var_num); 57 | } 58 | } 59 | if (next->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { 60 | var_num = EX_VAR_TO_NUM(next->op2.var); 61 | if (!DFG_ISSET(def, set_size, j, var_num)) { 62 | DFG_SET(use, set_size, j, var_num); 63 | } 64 | } 65 | } 66 | if (opline->op1_type == IS_CV) { 67 | var_num = EX_VAR_TO_NUM(opline->op1.var); 68 | switch (opline->opcode) { 69 | case ZEND_ADD_ARRAY_ELEMENT: 70 | case ZEND_INIT_ARRAY: 71 | if ((build_flags & ZEND_SSA_RC_INFERENCE) 72 | || (opline->extended_value & ZEND_ARRAY_ELEMENT_REF)) { 73 | goto op1_def; 74 | } 75 | goto op1_use; 76 | case ZEND_FE_RESET_R: 77 | case ZEND_SEND_VAR: 78 | case ZEND_CAST: 79 | case ZEND_QM_ASSIGN: 80 | case ZEND_JMP_SET: 81 | case ZEND_COALESCE: 82 | if (build_flags & ZEND_SSA_RC_INFERENCE) { 83 | goto op1_def; 84 | } 85 | goto op1_use; 86 | case ZEND_YIELD: 87 | if ((build_flags & ZEND_SSA_RC_INFERENCE) 88 | || (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) { 89 | goto op1_def; 90 | } 91 | goto op1_use; 92 | case ZEND_UNSET_CV: 93 | case ZEND_ASSIGN: 94 | case ZEND_ASSIGN_REF: 95 | case ZEND_BIND_GLOBAL: 96 | case ZEND_BIND_STATIC: 97 | case ZEND_SEND_VAR_EX: 98 | case ZEND_SEND_REF: 99 | case ZEND_SEND_VAR_NO_REF: 100 | case ZEND_SEND_VAR_NO_REF_EX: 101 | case ZEND_FE_RESET_RW: 102 | case ZEND_ASSIGN_ADD: 103 | case ZEND_ASSIGN_SUB: 104 | case ZEND_ASSIGN_MUL: 105 | case ZEND_ASSIGN_DIV: 106 | case ZEND_ASSIGN_MOD: 107 | case ZEND_ASSIGN_SL: 108 | case ZEND_ASSIGN_SR: 109 | case ZEND_ASSIGN_CONCAT: 110 | case ZEND_ASSIGN_BW_OR: 111 | case ZEND_ASSIGN_BW_AND: 112 | case ZEND_ASSIGN_BW_XOR: 113 | case ZEND_ASSIGN_POW: 114 | case ZEND_PRE_INC: 115 | case ZEND_PRE_DEC: 116 | case ZEND_POST_INC: 117 | case ZEND_POST_DEC: 118 | case ZEND_ASSIGN_DIM: 119 | case ZEND_ASSIGN_OBJ: 120 | case ZEND_UNSET_DIM: 121 | case ZEND_UNSET_OBJ: 122 | case ZEND_FETCH_DIM_W: 123 | case ZEND_FETCH_DIM_RW: 124 | case ZEND_FETCH_DIM_FUNC_ARG: 125 | case ZEND_FETCH_DIM_UNSET: 126 | case ZEND_FETCH_OBJ_W: 127 | case ZEND_FETCH_OBJ_RW: 128 | case ZEND_FETCH_OBJ_FUNC_ARG: 129 | case ZEND_FETCH_OBJ_UNSET: 130 | case ZEND_VERIFY_RETURN_TYPE: 131 | op1_def: 132 | /* `def` always come along with dtor or separation, 133 | * thus the origin var info might be also `use`d in the feature(CG) */ 134 | DFG_SET(use, set_size, j, var_num); 135 | DFG_SET(def, set_size, j, var_num); 136 | break; 137 | default: 138 | op1_use: 139 | if (!DFG_ISSET(def, set_size, j, var_num)) { 140 | DFG_SET(use, set_size, j, var_num); 141 | } 142 | } 143 | } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { 144 | var_num = EX_VAR_TO_NUM(opline->op1.var); 145 | if (!DFG_ISSET(def, set_size, j, var_num)) { 146 | DFG_SET(use, set_size, j, var_num); 147 | } 148 | if (opline->opcode == ZEND_VERIFY_RETURN_TYPE) { 149 | DFG_SET(def, set_size, j, var_num); 150 | } 151 | } 152 | if (opline->op2_type == IS_CV) { 153 | var_num = EX_VAR_TO_NUM(opline->op2.var); 154 | switch (opline->opcode) { 155 | case ZEND_ASSIGN: 156 | if (build_flags & ZEND_SSA_RC_INFERENCE) { 157 | goto op2_def; 158 | } 159 | goto op2_use; 160 | case ZEND_BIND_LEXICAL: 161 | if ((build_flags & ZEND_SSA_RC_INFERENCE) || opline->extended_value) { 162 | goto op2_def; 163 | } 164 | goto op2_use; 165 | case ZEND_ASSIGN_REF: 166 | case ZEND_FE_FETCH_R: 167 | case ZEND_FE_FETCH_RW: 168 | op2_def: 169 | // FIXME: include into "use" too ...? 170 | DFG_SET(use, set_size, j, var_num); 171 | DFG_SET(def, set_size, j, var_num); 172 | break; 173 | default: 174 | op2_use: 175 | if (!DFG_ISSET(def, set_size, j, var_num)) { 176 | DFG_SET(use, set_size, j, var_num); 177 | } 178 | break; 179 | } 180 | } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) { 181 | var_num = EX_VAR_TO_NUM(opline->op2.var); 182 | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { 183 | DFG_SET(def, set_size, j, var_num); 184 | } else { 185 | if (!DFG_ISSET(def, set_size, j, var_num)) { 186 | DFG_SET(use, set_size, j, var_num); 187 | } 188 | } 189 | } 190 | if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { 191 | var_num = EX_VAR_TO_NUM(opline->result.var); 192 | if ((build_flags & ZEND_SSA_USE_CV_RESULTS) 193 | && opline->result_type == IS_CV) { 194 | DFG_SET(use, set_size, j, var_num); 195 | } 196 | DFG_SET(def, set_size, j, var_num); 197 | } 198 | } 199 | } 200 | } 201 | 202 | /* Calculate "in" and "out" sets */ 203 | { 204 | uint32_t worklist_len = zend_bitset_len(blocks_count); 205 | zend_bitset worklist; 206 | ALLOCA_FLAG(use_heap); 207 | worklist = ZEND_BITSET_ALLOCA(worklist_len, use_heap); 208 | memset(worklist, 0, worklist_len * ZEND_BITSET_ELM_SIZE); 209 | for (j = 0; j < blocks_count; j++) { 210 | zend_bitset_incl(worklist, j); 211 | } 212 | while (!zend_bitset_empty(worklist, worklist_len)) { 213 | /* We use the last block on the worklist, because predecessors tend to be located 214 | * before the succeeding block, so this converges faster. */ 215 | j = zend_bitset_last(worklist, worklist_len); 216 | zend_bitset_excl(worklist, j); 217 | 218 | if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) { 219 | continue; 220 | } 221 | if (blocks[j].successors_count != 0) { 222 | zend_bitset_copy(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[0]), set_size); 223 | for (k = 1; k < blocks[j].successors_count; k++) { 224 | zend_bitset_union(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[k]), set_size); 225 | } 226 | } else { 227 | zend_bitset_clear(DFG_BITSET(out, set_size, j), set_size); 228 | } 229 | zend_bitset_union_with_difference(tmp, DFG_BITSET(use, set_size, j), DFG_BITSET(out, set_size, j), DFG_BITSET(def, set_size, j), set_size); 230 | if (!zend_bitset_equal(DFG_BITSET(in, set_size, j), tmp, set_size)) { 231 | zend_bitset_copy(DFG_BITSET(in, set_size, j), tmp, set_size); 232 | 233 | /* Add predecessors of changed block to worklist */ 234 | { 235 | int *predecessors = &cfg->predecessors[blocks[j].predecessor_offset]; 236 | for (k = 0; k < blocks[j].predecessors_count; k++) { 237 | zend_bitset_incl(worklist, predecessors[k]); 238 | } 239 | } 240 | } 241 | } 242 | 243 | free_alloca(worklist, use_heap); 244 | } 245 | 246 | return SUCCESS; 247 | } 248 | /* }}} */ 249 | 250 | /* 251 | * Local variables: 252 | * tab-width: 4 253 | * c-basic-offset: 4 254 | * indent-tabs-mode: t 255 | * End: 256 | */ 257 | -------------------------------------------------------------------------------- /Optimizer/scdf.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, Sparse Conditional Data Flow Propagation Framework | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Nikita Popov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #include "ZendAccelerator.h" 20 | #include "Optimizer/zend_optimizer_internal.h" 21 | #include "Optimizer/scdf.h" 22 | 23 | /* This defines a generic framework for sparse conditional dataflow propagation. The algorithm is 24 | * based on "Sparse conditional constant propagation" by Wegman and Zadeck. We're using a 25 | * generalized implementation as described in chapter 8.3 of the SSA book. 26 | * 27 | * Every SSA variable is associated with an element on a finite-height lattice, those value can only 28 | * ever be lowered during the operation of the algorithm. If a value is lowered all instructions and 29 | * phis using that value need to be reconsidered (this is done by adding the variable to a 30 | * worklist). For phi functions the result is computed by applying the meet operation to the 31 | * operands. This continues until a fixed point is reached. 32 | * 33 | * The algorithm is control-flow sensitive: All blocks except the start block are initially assumed 34 | * to be unreachable. When considering a branch instruction, we determine the feasible successors 35 | * based on the current state of the variable lattice. If a new edge becomes feasible we either have 36 | * to mark the successor block executable and consider all instructions in it, or, if the target is 37 | * already executable, we only have to reconsider the phi functions (as we only consider phi 38 | * operands which are associated with a feasible edge). 39 | * 40 | * The generic framework requires the definition of three functions: 41 | * * visit_instr() should recompute the lattice values of all SSA variables defined by an 42 | * instruction. 43 | * * visit_phi() should recompute the lattice value of the SSA variable defined by the phi. While 44 | * doing this it should only consider operands for which scfg_is_edge_feasible() returns true. 45 | * * get_feasible_successors() should determine the feasible successors for a branch instruction. 46 | * Note that this callback only needs to handle conditional branches (with two successors). 47 | */ 48 | 49 | #if 0 50 | #define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) 51 | #else 52 | #define DEBUG_PRINT(...) 53 | #endif 54 | 55 | void scdf_mark_edge_feasible(scdf_ctx *scdf, int from, int to) { 56 | uint32_t edge = scdf_edge(&scdf->ssa->cfg, from, to); 57 | 58 | if (zend_bitset_in(scdf->feasible_edges, edge)) { 59 | /* We already handled this edge */ 60 | return; 61 | } 62 | 63 | DEBUG_PRINT("Marking edge %d->%d feasible\n", from, to); 64 | zend_bitset_incl(scdf->feasible_edges, edge); 65 | 66 | if (!zend_bitset_in(scdf->executable_blocks, to)) { 67 | if (!zend_bitset_in(scdf->block_worklist, to)) { 68 | DEBUG_PRINT("Adding block %d to worklist\n", to); 69 | } 70 | zend_bitset_incl(scdf->block_worklist, to); 71 | } else { 72 | /* Block is already executable, only a new edge became feasible. 73 | * Reevaluate phi nodes to account for changed source operands. */ 74 | zend_ssa_block *ssa_block = &scdf->ssa->blocks[to]; 75 | zend_ssa_phi *phi; 76 | for (phi = ssa_block->phis; phi; phi = phi->next) { 77 | zend_bitset_excl(scdf->phi_var_worklist, phi->ssa_var); 78 | scdf->handlers.visit_phi(scdf, phi); 79 | } 80 | } 81 | } 82 | 83 | void scdf_init(zend_optimizer_ctx *ctx, scdf_ctx *scdf, zend_op_array *op_array, zend_ssa *ssa) { 84 | scdf->op_array = op_array; 85 | scdf->ssa = ssa; 86 | 87 | scdf->instr_worklist_len = zend_bitset_len(op_array->last); 88 | scdf->phi_var_worklist_len = zend_bitset_len(ssa->vars_count); 89 | scdf->block_worklist_len = zend_bitset_len(ssa->cfg.blocks_count); 90 | 91 | scdf->instr_worklist = zend_arena_calloc(&ctx->arena, 92 | scdf->instr_worklist_len + scdf->phi_var_worklist_len + 2 * scdf->block_worklist_len + zend_bitset_len(ssa->cfg.edges_count), 93 | sizeof(zend_ulong)); 94 | 95 | scdf->phi_var_worklist = scdf->instr_worklist + scdf->instr_worklist_len; 96 | scdf->block_worklist = scdf->phi_var_worklist + scdf->phi_var_worklist_len; 97 | scdf->executable_blocks = scdf->block_worklist + scdf->block_worklist_len; 98 | scdf->feasible_edges = scdf->executable_blocks + scdf->block_worklist_len; 99 | 100 | zend_bitset_incl(scdf->block_worklist, 0); 101 | zend_bitset_incl(scdf->executable_blocks, 0); 102 | } 103 | 104 | void scdf_solve(scdf_ctx *scdf, const char *name) { 105 | zend_ssa *ssa = scdf->ssa; 106 | DEBUG_PRINT("Start SCDF solve (%s)\n", name); 107 | while (!zend_bitset_empty(scdf->instr_worklist, scdf->instr_worklist_len) 108 | || !zend_bitset_empty(scdf->phi_var_worklist, scdf->phi_var_worklist_len) 109 | || !zend_bitset_empty(scdf->block_worklist, scdf->block_worklist_len) 110 | ) { 111 | int i; 112 | while ((i = zend_bitset_pop_first(scdf->phi_var_worklist, scdf->phi_var_worklist_len)) >= 0) { 113 | zend_ssa_phi *phi = ssa->vars[i].definition_phi; 114 | ZEND_ASSERT(phi); 115 | if (zend_bitset_in(scdf->executable_blocks, phi->block)) { 116 | scdf->handlers.visit_phi(scdf, phi); 117 | } 118 | } 119 | 120 | while ((i = zend_bitset_pop_first(scdf->instr_worklist, scdf->instr_worklist_len)) >= 0) { 121 | int block_num = ssa->cfg.map[i]; 122 | if (zend_bitset_in(scdf->executable_blocks, block_num)) { 123 | zend_basic_block *block = &ssa->cfg.blocks[block_num]; 124 | zend_op *opline = &scdf->op_array->opcodes[i]; 125 | zend_ssa_op *ssa_op = &ssa->ops[i]; 126 | if (opline->opcode == ZEND_OP_DATA) { 127 | opline--; 128 | ssa_op--; 129 | } 130 | scdf->handlers.visit_instr(scdf, opline, ssa_op); 131 | if (i == block->start + block->len - 1) { 132 | if (block->successors_count == 1) { 133 | scdf_mark_edge_feasible(scdf, block_num, block->successors[0]); 134 | } else if (block->successors_count > 1) { 135 | scdf->handlers.mark_feasible_successors(scdf, block_num, block, opline, ssa_op); 136 | } 137 | } 138 | } 139 | } 140 | 141 | while ((i = zend_bitset_pop_first(scdf->block_worklist, scdf->block_worklist_len)) >= 0) { 142 | /* This block is now live. Interpret phis and instructions in it. */ 143 | zend_basic_block *block = &ssa->cfg.blocks[i]; 144 | zend_ssa_block *ssa_block = &ssa->blocks[i]; 145 | 146 | DEBUG_PRINT("Pop block %d from worklist\n", i); 147 | zend_bitset_incl(scdf->executable_blocks, i); 148 | 149 | { 150 | zend_ssa_phi *phi; 151 | for (phi = ssa_block->phis; phi; phi = phi->next) { 152 | zend_bitset_excl(scdf->phi_var_worklist, phi->ssa_var); 153 | scdf->handlers.visit_phi(scdf, phi); 154 | } 155 | } 156 | 157 | if (block->len == 0) { 158 | /* Zero length blocks don't have a last instruction that would normally do this */ 159 | scdf_mark_edge_feasible(scdf, i, block->successors[0]); 160 | } else { 161 | zend_op *opline; 162 | int j, end = block->start + block->len; 163 | for (j = block->start; j < end; j++) { 164 | opline = &scdf->op_array->opcodes[j]; 165 | zend_bitset_excl(scdf->instr_worklist, j); 166 | if (opline->opcode != ZEND_OP_DATA) { 167 | scdf->handlers.visit_instr(scdf, opline, &ssa->ops[j]); 168 | } 169 | } 170 | if (block->successors_count == 1) { 171 | scdf_mark_edge_feasible(scdf, i, block->successors[0]); 172 | } else if (block->successors_count > 1) { 173 | if (opline->opcode == ZEND_OP_DATA) { 174 | opline--; 175 | j--; 176 | } 177 | scdf->handlers.mark_feasible_successors(scdf, i, block, opline, &ssa->ops[j-1]); 178 | } 179 | } 180 | } 181 | } 182 | } 183 | 184 | /* If a live range starts in a reachable block and ends in an unreachable block, we should 185 | * not eliminate the latter. While it cannot be reached, the FREE opcode of the loop var 186 | * is necessary for the correctness of temporary compaction. */ 187 | static zend_bool kept_alive_by_live_range(scdf_ctx *scdf, uint32_t block) { 188 | uint32_t i; 189 | const zend_op_array *op_array = scdf->op_array; 190 | const zend_cfg *cfg = &scdf->ssa->cfg; 191 | for (i = 0; i < op_array->last_live_range; i++) { 192 | zend_live_range *live_range = &op_array->live_range[i]; 193 | uint32_t start_block = cfg->map[live_range->start]; 194 | uint32_t end_block = cfg->map[live_range->end]; 195 | 196 | if (end_block == block && start_block != block 197 | && zend_bitset_in(scdf->executable_blocks, start_block)) { 198 | return 1; 199 | } 200 | } 201 | return 0; 202 | } 203 | 204 | /* Removes unreachable blocks. This will remove both the instructions (and phis) in the 205 | * blocks, as well as remove them from the successor / predecessor lists and mark them 206 | * unreachable. Blocks already marked unreachable are not removed. */ 207 | int scdf_remove_unreachable_blocks(scdf_ctx *scdf) { 208 | zend_ssa *ssa = scdf->ssa; 209 | int i; 210 | int removed_ops = 0; 211 | 212 | for (i = 0; i < ssa->cfg.blocks_count; i++) { 213 | if (!zend_bitset_in(scdf->executable_blocks, i) 214 | && (ssa->cfg.blocks[i].flags & ZEND_BB_REACHABLE) 215 | && !kept_alive_by_live_range(scdf, i)) { 216 | removed_ops += ssa->cfg.blocks[i].len; 217 | zend_ssa_remove_block(scdf->op_array, ssa, i); 218 | } 219 | } 220 | return removed_ops; 221 | } 222 | -------------------------------------------------------------------------------- /Optimizer/optimize_func_calls.c: -------------------------------------------------------------------------------- 1 | /* 2 | Screw Opcode 3 | */ 4 | 5 | /* pass 4 6 | * - optimize INIT_FCALL_BY_NAME to DO_FCALL 7 | */ 8 | 9 | #include "php.h" 10 | #include "Optimizer/zend_optimizer.h" 11 | #include "Optimizer/zend_optimizer_internal.h" 12 | #include "zend_API.h" 13 | #include "zend_constants.h" 14 | #include "zend_execute.h" 15 | #include "zend_vm.h" 16 | 17 | #define ZEND_OP1_IS_CONST_STRING(opline) \ 18 | (opline->op1_type == IS_CONST && \ 19 | Z_TYPE(op_array->literals[(opline)->op1.constant]) == IS_STRING) 20 | #define ZEND_OP2_IS_CONST_STRING(opline) \ 21 | (opline->op2_type == IS_CONST && \ 22 | Z_TYPE(op_array->literals[(opline)->op2.constant]) == IS_STRING) 23 | 24 | typedef struct _optimizer_call_info 25 | { 26 | zend_function *func; 27 | zend_op *opline; 28 | zend_bool try_inline; 29 | } optimizer_call_info; 30 | 31 | static void zend_delete_call_instructions(zend_op *opline) 32 | { 33 | int call = 0; 34 | 35 | while (1) 36 | { 37 | switch (opline->opcode) 38 | { 39 | case ZEND_INIT_FCALL_BY_NAME: 40 | case ZEND_INIT_NS_FCALL_BY_NAME: 41 | case ZEND_INIT_STATIC_METHOD_CALL: 42 | case ZEND_INIT_METHOD_CALL: 43 | case ZEND_INIT_FCALL: 44 | if (call == 0) 45 | { 46 | MAKE_NOP(opline); 47 | return; 48 | } 49 | /* break missing intentionally */ 50 | case ZEND_NEW: 51 | case ZEND_INIT_DYNAMIC_CALL: 52 | case ZEND_INIT_USER_CALL: 53 | call--; 54 | break; 55 | case ZEND_DO_FCALL: 56 | case ZEND_DO_ICALL: 57 | case ZEND_DO_UCALL: 58 | case ZEND_DO_FCALL_BY_NAME: 59 | call++; 60 | break; 61 | case ZEND_SEND_VAL: 62 | case ZEND_SEND_VAR: 63 | if (call == 0) 64 | { 65 | if (opline->op1_type == IS_CONST) 66 | { 67 | MAKE_NOP(opline); 68 | } 69 | else if (opline->op1_type == IS_CV) 70 | { 71 | opline->opcode = ZEND_CHECK_VAR; 72 | opline->extended_value = 0; 73 | opline->result.var = 0; 74 | } 75 | else 76 | { 77 | opline->opcode = ZEND_FREE; 78 | opline->extended_value = 0; 79 | opline->result.var = 0; 80 | } 81 | } 82 | break; 83 | } 84 | opline--; 85 | } 86 | } 87 | 88 | static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_op *opline, zend_function *func) 89 | { 90 | if (func->type == ZEND_USER_FUNCTION && !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT | ZEND_ACC_HAS_TYPE_HINTS)) && fcall->extended_value >= func->op_array.required_num_args && func->op_array.opcodes[func->op_array.num_args].opcode == ZEND_RETURN) 91 | { 92 | 93 | zend_op *ret_opline = func->op_array.opcodes + func->op_array.num_args; 94 | 95 | if (ret_opline->op1_type == IS_CONST) 96 | { 97 | uint32_t i, num_args = func->op_array.num_args; 98 | num_args += (func->op_array.fn_flags & ZEND_ACC_VARIADIC) != 0; 99 | 100 | if (fcall->opcode == ZEND_INIT_METHOD_CALL && fcall->op1_type == IS_UNUSED) 101 | { 102 | /* TODO: we can't inlne methods, because $this may be used 103 | * not in object context ??? 104 | */ 105 | return; 106 | } 107 | 108 | for (i = 0; i < num_args; i++) 109 | { 110 | /* Don't inline functions with by-reference arguments. This would require 111 | * correct handling of INDIRECT arguments. */ 112 | if (func->op_array.arg_info[i].pass_by_reference) 113 | { 114 | return; 115 | } 116 | } 117 | 118 | if (fcall->extended_value < func->op_array.num_args) 119 | { 120 | /* don't inline funcions with named constants in default arguments */ 121 | i = fcall->extended_value; 122 | 123 | do 124 | { 125 | if (Z_CONSTANT_P(RT_CONSTANT(&func->op_array, func->op_array.opcodes[i].op2))) 126 | { 127 | return; 128 | } 129 | i++; 130 | } while (i < func->op_array.num_args); 131 | } 132 | 133 | if (RETURN_VALUE_USED(opline)) 134 | { 135 | zval zv; 136 | 137 | ZVAL_DUP(&zv, RT_CONSTANT(&func->op_array, ret_opline->op1)); 138 | opline->opcode = ZEND_QM_ASSIGN; 139 | opline->op1_type = IS_CONST; 140 | opline->op1.constant = zend_optimizer_add_literal(op_array, &zv); 141 | SET_UNUSED(opline->op2); 142 | } 143 | else 144 | { 145 | MAKE_NOP(opline); 146 | } 147 | 148 | zend_delete_call_instructions(opline - 1); 149 | } 150 | } 151 | } 152 | 153 | void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) 154 | { 155 | zend_op *opline = op_array->opcodes; 156 | zend_op *end = opline + op_array->last; 157 | int call = 0; 158 | void *checkpoint; 159 | optimizer_call_info *call_stack; 160 | 161 | if (op_array->last < 2) 162 | { 163 | return; 164 | } 165 | 166 | checkpoint = zend_arena_checkpoint(ctx->arena); 167 | call_stack = zend_arena_calloc(&ctx->arena, op_array->last / 2, sizeof(optimizer_call_info)); 168 | while (opline < end) 169 | { 170 | switch (opline->opcode) 171 | { 172 | case ZEND_INIT_FCALL_BY_NAME: 173 | case ZEND_INIT_NS_FCALL_BY_NAME: 174 | case ZEND_INIT_STATIC_METHOD_CALL: 175 | case ZEND_INIT_METHOD_CALL: 176 | case ZEND_INIT_FCALL: 177 | case ZEND_NEW: 178 | call_stack[call].func = zend_optimizer_get_called_func( 179 | ctx->script, op_array, opline, 0); 180 | call_stack[call].try_inline = opline->opcode != ZEND_NEW; 181 | /* break missing intentionally */ 182 | case ZEND_INIT_DYNAMIC_CALL: 183 | case ZEND_INIT_USER_CALL: 184 | call_stack[call].opline = opline; 185 | call++; 186 | break; 187 | case ZEND_DO_FCALL: 188 | case ZEND_DO_ICALL: 189 | case ZEND_DO_UCALL: 190 | case ZEND_DO_FCALL_BY_NAME: 191 | call--; 192 | if (call_stack[call].func && call_stack[call].opline) 193 | { 194 | zend_op *fcall = call_stack[call].opline; 195 | 196 | if (fcall->opcode == ZEND_INIT_FCALL) 197 | { 198 | /* nothing to do */ 199 | } 200 | else if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) 201 | { 202 | fcall->opcode = ZEND_INIT_FCALL; 203 | fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); 204 | Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); 205 | literal_dtor(&ZEND_OP2_LITERAL(fcall)); 206 | fcall->op2.constant = fcall->op2.constant + 1; 207 | opline->opcode = zend_get_call_op(fcall, call_stack[call].func); 208 | } 209 | else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) 210 | { 211 | fcall->opcode = ZEND_INIT_FCALL; 212 | fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); 213 | Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); 214 | literal_dtor(&op_array->literals[fcall->op2.constant]); 215 | literal_dtor(&op_array->literals[fcall->op2.constant + 2]); 216 | fcall->op2.constant = fcall->op2.constant + 1; 217 | opline->opcode = zend_get_call_op(fcall, call_stack[call].func); 218 | } 219 | else if (fcall->opcode == ZEND_INIT_STATIC_METHOD_CALL || fcall->opcode == ZEND_INIT_METHOD_CALL || fcall->opcode == ZEND_NEW) 220 | { 221 | /* We don't have specialized opcodes for this, do nothing */ 222 | } 223 | else 224 | { 225 | ZEND_ASSERT(0); 226 | } 227 | 228 | if ((ZEND_OPTIMIZER_PASS_16 & ctx->optimization_level) && call_stack[call].try_inline) 229 | { 230 | zend_try_inline_call(op_array, fcall, opline, call_stack[call].func); 231 | } 232 | } 233 | call_stack[call].func = NULL; 234 | call_stack[call].opline = NULL; 235 | call_stack[call].try_inline = 0; 236 | break; 237 | case ZEND_FETCH_FUNC_ARG: 238 | case ZEND_FETCH_STATIC_PROP_FUNC_ARG: 239 | case ZEND_FETCH_OBJ_FUNC_ARG: 240 | case ZEND_FETCH_DIM_FUNC_ARG: 241 | if (call_stack[call - 1].func) 242 | { 243 | if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, (opline->extended_value & ZEND_FETCH_ARG_MASK))) 244 | { 245 | opline->extended_value &= ZEND_FETCH_TYPE_MASK; 246 | if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) 247 | { 248 | opline->opcode -= 9; 249 | } 250 | else 251 | { 252 | opline->opcode = ZEND_FETCH_STATIC_PROP_W; 253 | } 254 | } 255 | else 256 | { 257 | if (opline->opcode == ZEND_FETCH_DIM_FUNC_ARG && opline->op2_type == IS_UNUSED) 258 | { 259 | /* FETCH_DIM_FUNC_ARG supports UNUSED op2, while FETCH_DIM_R does not. 260 | * Performing the replacement would create an invalid opcode. */ 261 | call_stack[call - 1].try_inline = 0; 262 | break; 263 | } 264 | 265 | opline->extended_value &= ZEND_FETCH_TYPE_MASK; 266 | if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) 267 | { 268 | opline->opcode -= 12; 269 | } 270 | else 271 | { 272 | opline->opcode = ZEND_FETCH_STATIC_PROP_R; 273 | } 274 | } 275 | } 276 | break; 277 | case ZEND_SEND_VAL_EX: 278 | if (call_stack[call - 1].func) 279 | { 280 | if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) 281 | { 282 | /* We won't convert it into_DO_FCALL to emit error at run-time */ 283 | call_stack[call - 1].opline = NULL; 284 | } 285 | else 286 | { 287 | opline->opcode = ZEND_SEND_VAL; 288 | } 289 | } 290 | break; 291 | case ZEND_SEND_VAR_EX: 292 | if (call_stack[call - 1].func) 293 | { 294 | if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) 295 | { 296 | opline->opcode = ZEND_SEND_REF; 297 | } 298 | else 299 | { 300 | opline->opcode = ZEND_SEND_VAR; 301 | } 302 | } 303 | break; 304 | case ZEND_SEND_VAR_NO_REF_EX: 305 | if (call_stack[call - 1].func) 306 | { 307 | if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) 308 | { 309 | opline->opcode = ZEND_SEND_VAR_NO_REF; 310 | } 311 | else if (ARG_MAY_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) 312 | { 313 | opline->opcode = ZEND_SEND_VAL; 314 | } 315 | else 316 | { 317 | opline->opcode = ZEND_SEND_VAR; 318 | } 319 | } 320 | break; 321 | case ZEND_SEND_UNPACK: 322 | case ZEND_SEND_USER: 323 | case ZEND_SEND_ARRAY: 324 | call_stack[call - 1].try_inline = 0; 325 | break; 326 | default: 327 | break; 328 | } 329 | opline++; 330 | } 331 | 332 | zend_arena_release(&ctx->arena, checkpoint); 333 | } 334 | -------------------------------------------------------------------------------- /Optimizer/zend_call_graph.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, Call Graph | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Dmitry Stogov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id:$ */ 20 | 21 | #include "php.h" 22 | #include "zend_compile.h" 23 | #include "zend_extensions.h" 24 | #include "Optimizer/zend_optimizer.h" 25 | #include "zend_optimizer_internal.h" 26 | #include "zend_inference.h" 27 | #include "zend_call_graph.h" 28 | #include "zend_func_info.h" 29 | #include "zend_inference.h" 30 | #include "zend_call_graph.h" 31 | 32 | typedef int (*zend_op_array_func_t)(zend_call_graph *call_graph, zend_op_array *op_array); 33 | 34 | static int zend_op_array_calc(zend_call_graph *call_graph, zend_op_array *op_array) 35 | { 36 | (void) op_array; 37 | 38 | call_graph->op_arrays_count++; 39 | return SUCCESS; 40 | } 41 | 42 | static int zend_op_array_collect(zend_call_graph *call_graph, zend_op_array *op_array) 43 | { 44 | zend_func_info *func_info = call_graph->func_infos + call_graph->op_arrays_count; 45 | 46 | ZEND_SET_FUNC_INFO(op_array, func_info); 47 | call_graph->op_arrays[call_graph->op_arrays_count] = op_array; 48 | func_info->num = call_graph->op_arrays_count; 49 | func_info->num_args = -1; 50 | func_info->return_value_used = -1; 51 | call_graph->op_arrays_count++; 52 | return SUCCESS; 53 | } 54 | 55 | static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *script, zend_op_array_func_t func) 56 | { 57 | zend_class_entry *ce; 58 | zend_op_array *op_array; 59 | 60 | if (func(call_graph, &script->main_op_array) != SUCCESS) { 61 | return FAILURE; 62 | } 63 | 64 | ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) { 65 | if (func(call_graph, op_array) != SUCCESS) { 66 | return FAILURE; 67 | } 68 | } ZEND_HASH_FOREACH_END(); 69 | 70 | ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { 71 | ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) { 72 | if (op_array->scope == ce) { 73 | if (func(call_graph, op_array) != SUCCESS) { 74 | return FAILURE; 75 | } 76 | } 77 | } ZEND_HASH_FOREACH_END(); 78 | } ZEND_HASH_FOREACH_END(); 79 | 80 | return SUCCESS; 81 | } 82 | 83 | int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info) 84 | { 85 | zend_op *opline = op_array->opcodes; 86 | zend_op *end = opline + op_array->last; 87 | zend_function *func; 88 | zend_call_info *call_info; 89 | int call = 0; 90 | zend_call_info **call_stack; 91 | ALLOCA_FLAG(use_heap); 92 | 93 | call_stack = do_alloca((op_array->last / 2) * sizeof(zend_call_info*), use_heap); 94 | call_info = NULL; 95 | while (opline != end) { 96 | switch (opline->opcode) { 97 | case ZEND_INIT_FCALL: 98 | case ZEND_INIT_METHOD_CALL: 99 | case ZEND_INIT_STATIC_METHOD_CALL: 100 | call_stack[call] = call_info; 101 | func = zend_optimizer_get_called_func( 102 | script, op_array, opline, (build_flags & ZEND_RT_CONSTANTS) != 0); 103 | if (func) { 104 | call_info = zend_arena_calloc(arena, 1, sizeof(zend_call_info) + (sizeof(zend_send_arg_info) * ((int)opline->extended_value - 1))); 105 | call_info->caller_op_array = op_array; 106 | call_info->caller_init_opline = opline; 107 | call_info->caller_call_opline = NULL; 108 | call_info->callee_func = func; 109 | call_info->num_args = opline->extended_value; 110 | call_info->next_callee = func_info->callee_info; 111 | func_info->callee_info = call_info; 112 | 113 | if (build_flags & ZEND_CALL_TREE) { 114 | call_info->next_caller = NULL; 115 | } else if (func->type == ZEND_INTERNAL_FUNCTION) { 116 | call_info->next_caller = NULL; 117 | } else { 118 | zend_func_info *callee_func_info = ZEND_FUNC_INFO(&func->op_array); 119 | if (callee_func_info) { 120 | call_info->next_caller = callee_func_info->caller_info; 121 | callee_func_info->caller_info = call_info; 122 | } else { 123 | call_info->next_caller = NULL; 124 | } 125 | } 126 | } else { 127 | call_info = NULL; 128 | } 129 | call++; 130 | break; 131 | case ZEND_INIT_FCALL_BY_NAME: 132 | case ZEND_INIT_NS_FCALL_BY_NAME: 133 | case ZEND_INIT_DYNAMIC_CALL: 134 | case ZEND_NEW: 135 | case ZEND_INIT_USER_CALL: 136 | call_stack[call] = call_info; 137 | call_info = NULL; 138 | call++; 139 | break; 140 | case ZEND_DO_FCALL: 141 | case ZEND_DO_ICALL: 142 | case ZEND_DO_UCALL: 143 | case ZEND_DO_FCALL_BY_NAME: 144 | func_info->flags |= ZEND_FUNC_HAS_CALLS; 145 | if (call_info) { 146 | call_info->caller_call_opline = opline; 147 | } 148 | call--; 149 | call_info = call_stack[call]; 150 | break; 151 | case ZEND_SEND_VAL: 152 | case ZEND_SEND_VAR: 153 | case ZEND_SEND_VAL_EX: 154 | case ZEND_SEND_VAR_EX: 155 | case ZEND_SEND_REF: 156 | case ZEND_SEND_VAR_NO_REF: 157 | case ZEND_SEND_VAR_NO_REF_EX: 158 | case ZEND_SEND_USER: 159 | if (call_info) { 160 | uint32_t num = opline->op2.num; 161 | 162 | if (num > 0) { 163 | num--; 164 | } 165 | call_info->arg_info[num].opline = opline; 166 | } 167 | break; 168 | case ZEND_SEND_ARRAY: 169 | case ZEND_SEND_UNPACK: 170 | /* TODO: set info about var_arg call ??? */ 171 | if (call_info) { 172 | call_info->num_args = -1; 173 | } 174 | break; 175 | } 176 | opline++; 177 | } 178 | free_alloca(call_stack, use_heap); 179 | return SUCCESS; 180 | } 181 | 182 | static int zend_is_indirectly_recursive(zend_op_array *root, zend_op_array *op_array, zend_bitset visited) 183 | { 184 | zend_func_info *func_info; 185 | zend_call_info *call_info; 186 | int ret = 0; 187 | 188 | if (op_array == root) { 189 | return 1; 190 | } 191 | 192 | func_info = ZEND_FUNC_INFO(op_array); 193 | if (zend_bitset_in(visited, func_info->num)) { 194 | return 0; 195 | } 196 | zend_bitset_incl(visited, func_info->num); 197 | call_info = func_info->caller_info; 198 | while (call_info) { 199 | if (zend_is_indirectly_recursive(root, call_info->caller_op_array, visited)) { 200 | call_info->recursive = 1; 201 | ret = 1; 202 | } 203 | call_info = call_info->next_caller; 204 | } 205 | return ret; 206 | } 207 | 208 | static void zend_analyze_recursion(zend_call_graph *call_graph) 209 | { 210 | zend_op_array *op_array; 211 | zend_func_info *func_info; 212 | zend_call_info *call_info; 213 | int i; 214 | int set_len = zend_bitset_len(call_graph->op_arrays_count); 215 | zend_bitset visited; 216 | ALLOCA_FLAG(use_heap); 217 | 218 | visited = ZEND_BITSET_ALLOCA(set_len, use_heap); 219 | for (i = 0; i < call_graph->op_arrays_count; i++) { 220 | op_array = call_graph->op_arrays[i]; 221 | func_info = call_graph->func_infos + i; 222 | call_info = func_info->caller_info; 223 | while (call_info) { 224 | if (call_info->caller_op_array == op_array) { 225 | call_info->recursive = 1; 226 | func_info->flags |= ZEND_FUNC_RECURSIVE | ZEND_FUNC_RECURSIVE_DIRECTLY; 227 | } else { 228 | memset(visited, 0, sizeof(zend_ulong) * set_len); 229 | if (zend_is_indirectly_recursive(op_array, call_info->caller_op_array, visited)) { 230 | call_info->recursive = 1; 231 | func_info->flags |= ZEND_FUNC_RECURSIVE | ZEND_FUNC_RECURSIVE_INDIRECTLY; 232 | } 233 | } 234 | call_info = call_info->next_caller; 235 | } 236 | } 237 | 238 | free_alloca(visited, use_heap); 239 | } 240 | 241 | static void zend_sort_op_arrays(zend_call_graph *call_graph) 242 | { 243 | (void) call_graph; 244 | 245 | // TODO: perform topological sort of cyclic call graph 246 | } 247 | 248 | int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_call_graph *call_graph) /* {{{ */ 249 | { 250 | int i; 251 | 252 | call_graph->op_arrays_count = 0; 253 | if (zend_foreach_op_array(call_graph, script, zend_op_array_calc) != SUCCESS) { 254 | return FAILURE; 255 | } 256 | call_graph->op_arrays = (zend_op_array**)zend_arena_calloc(arena, call_graph->op_arrays_count, sizeof(zend_op_array*)); 257 | call_graph->func_infos = (zend_func_info*)zend_arena_calloc(arena, call_graph->op_arrays_count, sizeof(zend_func_info)); 258 | call_graph->op_arrays_count = 0; 259 | if (zend_foreach_op_array(call_graph, script, zend_op_array_collect) != SUCCESS) { 260 | return FAILURE; 261 | } 262 | for (i = 0; i < call_graph->op_arrays_count; i++) { 263 | zend_analyze_calls(arena, script, build_flags, call_graph->op_arrays[i], call_graph->func_infos + i); 264 | } 265 | zend_analyze_recursion(call_graph); 266 | zend_sort_op_arrays(call_graph); 267 | 268 | return SUCCESS; 269 | } 270 | /* }}} */ 271 | 272 | zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array) /* {{{ */ 273 | { 274 | zend_call_info **map, *call; 275 | if (!info->callee_info) { 276 | /* Don't build call map if function contains no calls */ 277 | return NULL; 278 | } 279 | 280 | map = zend_arena_calloc(arena, sizeof(zend_call_info *), op_array->last); 281 | for (call = info->callee_info; call; call = call->next_callee) { 282 | int i; 283 | map[call->caller_init_opline - op_array->opcodes] = call; 284 | map[call->caller_call_opline - op_array->opcodes] = call; 285 | for (i = 0; i < call->num_args; i++) { 286 | if (call->arg_info[i].opline) { 287 | map[call->arg_info[i].opline - op_array->opcodes] = call; 288 | } 289 | } 290 | } 291 | return map; 292 | } 293 | /* }}} */ 294 | 295 | /* 296 | * Local variables: 297 | * tab-width: 4 298 | * c-basic-offset: 4 299 | * indent-tabs-mode: t 300 | * End: 301 | */ 302 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl 2 | dnl $Id$ 3 | dnl 4 | 5 | PHP_ARG_ENABLE(screwopcode, whether to enable ScrewOpcode support, 6 | [ --disable-screwopcode Disable ScrewOpcode support], yes) 7 | 8 | PHP_ARG_ENABLE(screwopcode-file, whether to enable file based caching, 9 | [ --disable-screwopcode-file Disable file based caching], yes, no) 10 | 11 | PHP_ARG_ENABLE(huge-code-pages, whether to enable copying PHP CODE pages into HUGE PAGES, 12 | [ --disable-huge-code-pages 13 | Disable copying PHP CODE pages into HUGE PAGES], yes, no) 14 | 15 | if test "$PHP_OPCACHE" != "no"; then 16 | 17 | if test "$PHP_OPCACHE_FILE" = "yes"; then 18 | AC_DEFINE(HAVE_OPCACHE_FILE_CACHE, 1, [Define to enable file based caching (experimental)]) 19 | fi 20 | 21 | if test "$PHP_HUGE_CODE_PAGES" = "yes"; then 22 | AC_DEFINE(HAVE_HUGE_CODE_PAGES, 1, [Define to enable copying PHP CODE pages into HUGE PAGES (experimental)]) 23 | fi 24 | 25 | AC_CHECK_FUNC(mprotect,[ 26 | AC_DEFINE(HAVE_MPROTECT, 1, [Define if you have mprotect() function]) 27 | ]) 28 | 29 | AC_CHECK_HEADERS([unistd.h sys/uio.h]) 30 | 31 | AC_MSG_CHECKING(for sysvipc shared memory support) 32 | AC_TRY_RUN([ 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | int main() { 41 | pid_t pid; 42 | int status; 43 | int ipc_id; 44 | char *shm; 45 | struct shmid_ds shmbuf; 46 | 47 | ipc_id = shmget(IPC_PRIVATE, 4096, (IPC_CREAT | SHM_R | SHM_W)); 48 | if (ipc_id == -1) { 49 | return 1; 50 | } 51 | 52 | shm = shmat(ipc_id, NULL, 0); 53 | if (shm == (void *)-1) { 54 | shmctl(ipc_id, IPC_RMID, NULL); 55 | return 2; 56 | } 57 | 58 | if (shmctl(ipc_id, IPC_STAT, &shmbuf) != 0) { 59 | shmdt(shm); 60 | shmctl(ipc_id, IPC_RMID, NULL); 61 | return 3; 62 | } 63 | 64 | shmbuf.shm_perm.uid = getuid(); 65 | shmbuf.shm_perm.gid = getgid(); 66 | shmbuf.shm_perm.mode = 0600; 67 | 68 | if (shmctl(ipc_id, IPC_SET, &shmbuf) != 0) { 69 | shmdt(shm); 70 | shmctl(ipc_id, IPC_RMID, NULL); 71 | return 4; 72 | } 73 | 74 | shmctl(ipc_id, IPC_RMID, NULL); 75 | 76 | strcpy(shm, "hello"); 77 | 78 | pid = fork(); 79 | if (pid < 0) { 80 | return 5; 81 | } else if (pid == 0) { 82 | strcpy(shm, "bye"); 83 | return 6; 84 | } 85 | if (wait(&status) != pid) { 86 | return 7; 87 | } 88 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { 89 | return 8; 90 | } 91 | if (strcmp(shm, "bye") != 0) { 92 | return 9; 93 | } 94 | return 0; 95 | } 96 | ],dnl 97 | AC_DEFINE(HAVE_SHM_IPC, 1, [Define if you have SysV IPC SHM support]) 98 | msg=yes,msg=no,msg=no) 99 | AC_MSG_RESULT([$msg]) 100 | 101 | AC_MSG_CHECKING(for mmap() using MAP_ANON shared memory support) 102 | AC_TRY_RUN([ 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | 109 | #ifndef MAP_ANON 110 | # ifdef MAP_ANONYMOUS 111 | # define MAP_ANON MAP_ANONYMOUS 112 | # endif 113 | #endif 114 | #ifndef MAP_FAILED 115 | # define MAP_FAILED ((void*)-1) 116 | #endif 117 | 118 | int main() { 119 | pid_t pid; 120 | int status; 121 | char *shm; 122 | 123 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); 124 | if (shm == MAP_FAILED) { 125 | return 1; 126 | } 127 | 128 | strcpy(shm, "hello"); 129 | 130 | pid = fork(); 131 | if (pid < 0) { 132 | return 5; 133 | } else if (pid == 0) { 134 | strcpy(shm, "bye"); 135 | return 6; 136 | } 137 | if (wait(&status) != pid) { 138 | return 7; 139 | } 140 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { 141 | return 8; 142 | } 143 | if (strcmp(shm, "bye") != 0) { 144 | return 9; 145 | } 146 | return 0; 147 | } 148 | ],dnl 149 | AC_DEFINE(HAVE_SHM_MMAP_ANON, 1, [Define if you have mmap(MAP_ANON) SHM support]) 150 | msg=yes,msg=no,msg=no) 151 | AC_MSG_RESULT([$msg]) 152 | 153 | AC_MSG_CHECKING(for mmap() using /dev/zero shared memory support) 154 | AC_TRY_RUN([ 155 | #include 156 | #include 157 | #include 158 | #include 159 | #include 160 | #include 161 | #include 162 | 163 | #ifndef MAP_FAILED 164 | # define MAP_FAILED ((void*)-1) 165 | #endif 166 | 167 | int main() { 168 | pid_t pid; 169 | int status; 170 | int fd; 171 | char *shm; 172 | 173 | fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR); 174 | if (fd == -1) { 175 | return 1; 176 | } 177 | 178 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 179 | if (shm == MAP_FAILED) { 180 | return 2; 181 | } 182 | 183 | strcpy(shm, "hello"); 184 | 185 | pid = fork(); 186 | if (pid < 0) { 187 | return 5; 188 | } else if (pid == 0) { 189 | strcpy(shm, "bye"); 190 | return 6; 191 | } 192 | if (wait(&status) != pid) { 193 | return 7; 194 | } 195 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { 196 | return 8; 197 | } 198 | if (strcmp(shm, "bye") != 0) { 199 | return 9; 200 | } 201 | return 0; 202 | } 203 | ],dnl 204 | AC_DEFINE(HAVE_SHM_MMAP_ZERO, 1, [Define if you have mmap("/dev/zero") SHM support]) 205 | msg=yes,msg=no,msg=no) 206 | AC_MSG_RESULT([$msg]) 207 | 208 | AC_MSG_CHECKING(for mmap() using shm_open() shared memory support) 209 | AC_TRY_RUN([ 210 | #include 211 | #include 212 | #include 213 | #include 214 | #include 215 | #include 216 | #include 217 | #include 218 | #include 219 | 220 | #ifndef MAP_FAILED 221 | # define MAP_FAILED ((void*)-1) 222 | #endif 223 | 224 | int main() { 225 | pid_t pid; 226 | int status; 227 | int fd; 228 | char *shm; 229 | char tmpname[4096]; 230 | 231 | sprintf(tmpname,"test.shm.%dXXXXXX", getpid()); 232 | if (mktemp(tmpname) == NULL) { 233 | return 1; 234 | } 235 | fd = shm_open(tmpname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 236 | if (fd == -1) { 237 | return 2; 238 | } 239 | if (ftruncate(fd, 4096) < 0) { 240 | close(fd); 241 | shm_unlink(tmpname); 242 | return 3; 243 | } 244 | 245 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 246 | if (shm == MAP_FAILED) { 247 | return 4; 248 | } 249 | shm_unlink(tmpname); 250 | close(fd); 251 | 252 | strcpy(shm, "hello"); 253 | 254 | pid = fork(); 255 | if (pid < 0) { 256 | return 5; 257 | } else if (pid == 0) { 258 | strcpy(shm, "bye"); 259 | return 6; 260 | } 261 | if (wait(&status) != pid) { 262 | return 7; 263 | } 264 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { 265 | return 8; 266 | } 267 | if (strcmp(shm, "bye") != 0) { 268 | return 9; 269 | } 270 | return 0; 271 | } 272 | ],dnl 273 | AC_DEFINE(HAVE_SHM_MMAP_POSIX, 1, [Define if you have POSIX mmap() SHM support]) 274 | msg=yes,msg=no,msg=no) 275 | AC_MSG_RESULT([$msg]) 276 | 277 | AC_MSG_CHECKING(for mmap() using regular file shared memory support) 278 | AC_TRY_RUN([ 279 | #include 280 | #include 281 | #include 282 | #include 283 | #include 284 | #include 285 | #include 286 | #include 287 | #include 288 | 289 | #ifndef MAP_FAILED 290 | # define MAP_FAILED ((void*)-1) 291 | #endif 292 | 293 | int main() { 294 | pid_t pid; 295 | int status; 296 | int fd; 297 | char *shm; 298 | char tmpname[4096]; 299 | 300 | sprintf(tmpname,"test.shm.%dXXXXXX", getpid()); 301 | if (mktemp(tmpname) == NULL) { 302 | return 1; 303 | } 304 | fd = open(tmpname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 305 | if (fd == -1) { 306 | return 2; 307 | } 308 | if (ftruncate(fd, 4096) < 0) { 309 | close(fd); 310 | unlink(tmpname); 311 | return 3; 312 | } 313 | 314 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 315 | if (shm == MAP_FAILED) { 316 | return 4; 317 | } 318 | unlink(tmpname); 319 | close(fd); 320 | 321 | strcpy(shm, "hello"); 322 | 323 | pid = fork(); 324 | if (pid < 0) { 325 | return 5; 326 | } else if (pid == 0) { 327 | strcpy(shm, "bye"); 328 | return 6; 329 | } 330 | if (wait(&status) != pid) { 331 | return 7; 332 | } 333 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { 334 | return 8; 335 | } 336 | if (strcmp(shm, "bye") != 0) { 337 | return 9; 338 | } 339 | return 0; 340 | } 341 | ],dnl 342 | AC_DEFINE(HAVE_SHM_MMAP_FILE, 1, [Define if you have mmap() SHM support]) 343 | msg=yes,msg=no,msg=no) 344 | AC_MSG_RESULT([$msg]) 345 | 346 | flock_type=unknown 347 | AC_MSG_CHECKING("whether flock struct is linux ordered") 348 | AC_TRY_RUN([ 349 | #include 350 | struct flock lock = { 1, 2, 3, 4, 5 }; 351 | int main() { 352 | if(lock.l_type == 1 && lock.l_whence == 2 && lock.l_start == 3 && lock.l_len == 4) { 353 | return 0; 354 | } 355 | return 1; 356 | } 357 | ], [ 358 | flock_type=linux 359 | AC_DEFINE([HAVE_FLOCK_LINUX], [], [Struct flock is Linux-type]) 360 | AC_MSG_RESULT("yes") 361 | ], AC_MSG_RESULT("no") ) 362 | 363 | AC_MSG_CHECKING("whether flock struct is BSD ordered") 364 | AC_TRY_RUN([ 365 | #include 366 | struct flock lock = { 1, 2, 3, 4, 5 }; 367 | int main() { 368 | if(lock.l_start == 1 && lock.l_len == 2 && lock.l_type == 4 && lock.l_whence == 5) { 369 | return 0; 370 | } 371 | return 1; 372 | } 373 | ], [ 374 | flock_type=bsd 375 | AC_DEFINE([HAVE_FLOCK_BSD], [], [Struct flock is BSD-type]) 376 | AC_MSG_RESULT("yes") 377 | ], AC_MSG_RESULT("no") ) 378 | 379 | if test "$flock_type" = "unknown"; then 380 | AC_MSG_ERROR([Don't know how to define struct flock on this system[,] set --enable-screwopcode=no]) 381 | fi 382 | 383 | PHP_NEW_EXTENSION(screwopcode, 384 | ZendAccelerator.c \ 385 | zend_accelerator_blacklist.c \ 386 | zend_accelerator_debug.c \ 387 | zend_accelerator_hash.c \ 388 | zend_accelerator_module.c \ 389 | zend_persist.c \ 390 | zend_persist_calc.c \ 391 | zend_file_cache.c \ 392 | zend_shared_alloc.c \ 393 | zend_accelerator_util_funcs.c \ 394 | shared_alloc_shm.c \ 395 | shared_alloc_mmap.c \ 396 | shared_alloc_posix.c \ 397 | Optimizer/zend_optimizer.c \ 398 | Optimizer/pass1_5.c \ 399 | Optimizer/pass2.c \ 400 | Optimizer/pass3.c \ 401 | Optimizer/optimize_func_calls.c \ 402 | Optimizer/block_pass.c \ 403 | Optimizer/optimize_temp_vars_5.c \ 404 | Optimizer/nop_removal.c \ 405 | Optimizer/compact_literals.c \ 406 | Optimizer/zend_cfg.c \ 407 | Optimizer/zend_dfg.c \ 408 | Optimizer/dfa_pass.c \ 409 | Optimizer/zend_ssa.c \ 410 | Optimizer/zend_inference.c \ 411 | Optimizer/zend_func_info.c \ 412 | Optimizer/zend_call_graph.c \ 413 | Optimizer/sccp.c \ 414 | Optimizer/scdf.c \ 415 | Optimizer/dce.c \ 416 | Optimizer/compact_vars.c \ 417 | Optimizer/zend_dump.c, 418 | shared,,-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1,,yes) 419 | 420 | PHP_ADD_BUILD_DIR([$ext_builddir/Optimizer], 1) 421 | PHP_ADD_EXTENSION_DEP(screwopcode, pcre) 422 | fi 423 | -------------------------------------------------------------------------------- /zend_accelerator_blacklist.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #include "main/php.h" 23 | #include "main/fopen_wrappers.h" 24 | #include "ZendAccelerator.h" 25 | #include "zend_accelerator_blacklist.h" 26 | 27 | #ifdef ZEND_WIN32 28 | #define REGEX_MODE (REG_EXTENDED | REG_NOSUB | REG_ICASE) 29 | #else 30 | #define REGEX_MODE (REG_EXTENDED | REG_NOSUB) 31 | #endif 32 | 33 | #ifdef HAVE_GLOB 34 | #ifdef PHP_WIN32 35 | #include "win32/glob.h" 36 | #else 37 | #include 38 | #endif 39 | #endif 40 | 41 | #include "ext/pcre/php_pcre.h" 42 | 43 | #define ZEND_BLACKLIST_BLOCK_SIZE 32 44 | 45 | struct _zend_regexp_list 46 | { 47 | pcre *re; 48 | zend_regexp_list *next; 49 | }; 50 | 51 | zend_blacklist accel_blacklist; 52 | 53 | void zend_accel_blacklist_init(zend_blacklist *blacklist) 54 | { 55 | blacklist->pos = 0; 56 | blacklist->size = ZEND_BLACKLIST_BLOCK_SIZE; 57 | 58 | if (blacklist->entries != NULL) 59 | { 60 | zend_accel_blacklist_shutdown(blacklist); 61 | } 62 | 63 | blacklist->entries = (zend_blacklist_entry *)calloc(sizeof(zend_blacklist_entry), blacklist->size); 64 | if (!blacklist->entries) 65 | { 66 | zend_accel_error(ACCEL_LOG_FATAL, "Blacklist initialization: no memory\n"); 67 | return; 68 | } 69 | blacklist->regexp_list = NULL; 70 | } 71 | 72 | static void blacklist_report_regexp_error(const char *pcre_error, int pcre_error_offset) 73 | { 74 | zend_accel_error(ACCEL_LOG_ERROR, "Blacklist compilation failed (offset: %d), %s\n", pcre_error_offset, pcre_error); 75 | } 76 | 77 | static void zend_accel_blacklist_update_regexp(zend_blacklist *blacklist) 78 | { 79 | const char *pcre_error; 80 | int i, pcre_error_offset; 81 | zend_regexp_list **regexp_list_it, *it; 82 | char regexp[12 * 1024], *p, *end, *c, *backtrack = NULL; 83 | 84 | if (blacklist->pos == 0) 85 | { 86 | /* we have no blacklist to talk about */ 87 | return; 88 | } 89 | 90 | regexp_list_it = &(blacklist->regexp_list); 91 | 92 | regexp[0] = '^'; 93 | regexp[1] = '('; 94 | p = regexp + 2; 95 | end = regexp + sizeof(regexp) - sizeof("[^\\\\]*)\0"); 96 | 97 | for (i = 0; i < blacklist->pos;) 98 | { 99 | c = blacklist->entries[i].path; 100 | if (p + blacklist->entries[i].path_length < end) 101 | { 102 | while (*c && p < end) 103 | { 104 | switch (*c) 105 | { 106 | case '?': 107 | c++; 108 | #ifdef ZEND_WIN32 109 | p[0] = '['; /* * => [^\\] on Win32 */ 110 | p[1] = '^'; 111 | p[2] = '\\'; 112 | p[3] = '\\'; 113 | p[4] = ']'; 114 | p += 5; 115 | #else 116 | p[0] = '['; /* * => [^/] on *nix */ 117 | p[1] = '^'; 118 | p[2] = '/'; 119 | p[3] = ']'; 120 | p += 4; 121 | #endif 122 | break; 123 | case '*': 124 | c++; 125 | if (*c == '*') 126 | { 127 | c++; 128 | p[0] = '.'; /* ** => .* */ 129 | p[1] = '*'; 130 | p += 2; 131 | } 132 | else 133 | { 134 | #ifdef ZEND_WIN32 135 | p[0] = '['; /* * => [^\\]* on Win32 */ 136 | p[1] = '^'; 137 | p[2] = '\\'; 138 | p[3] = '\\'; 139 | p[4] = ']'; 140 | p[5] = '*'; 141 | p += 6; 142 | #else 143 | p[0] = '['; /* * => [^/]* on *nix */ 144 | p[1] = '^'; 145 | p[2] = '/'; 146 | p[3] = ']'; 147 | p[4] = '*'; 148 | p += 5; 149 | #endif 150 | } 151 | break; 152 | case '^': 153 | case '.': 154 | case '[': 155 | case ']': 156 | case '$': 157 | case '(': 158 | case ')': 159 | case '|': 160 | case '+': 161 | case '{': 162 | case '}': 163 | case '\\': 164 | *p++ = '\\'; 165 | /* break missing intentionally */ 166 | default: 167 | *p++ = *c++; 168 | } 169 | } 170 | } 171 | 172 | if (*c || i == blacklist->pos - 1) 173 | { 174 | if (*c) 175 | { 176 | if (!backtrack) 177 | { 178 | zend_accel_error(ACCEL_LOG_ERROR, "Too long blacklist entry\n"); 179 | } 180 | p = backtrack; 181 | } 182 | else 183 | { 184 | i++; 185 | } 186 | *p++ = ')'; 187 | *p++ = '\0'; 188 | 189 | it = (zend_regexp_list *)malloc(sizeof(zend_regexp_list)); 190 | if (!it) 191 | { 192 | zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n"); 193 | return; 194 | } 195 | it->next = NULL; 196 | 197 | if ((it->re = pcre_compile(regexp, PCRE_NO_AUTO_CAPTURE, &pcre_error, &pcre_error_offset, 0)) == NULL) 198 | { 199 | free(it); 200 | blacklist_report_regexp_error(pcre_error, pcre_error_offset); 201 | return; 202 | } 203 | /* prepare for the next iteration */ 204 | p = regexp + 2; 205 | *regexp_list_it = it; 206 | regexp_list_it = &it->next; 207 | } 208 | else 209 | { 210 | backtrack = p; 211 | *p++ = '|'; 212 | i++; 213 | } 214 | } 215 | } 216 | 217 | void zend_accel_blacklist_shutdown(zend_blacklist *blacklist) 218 | { 219 | zend_blacklist_entry *p = blacklist->entries, *end = blacklist->entries + blacklist->pos; 220 | 221 | while (p < end) 222 | { 223 | free(p->path); 224 | p++; 225 | } 226 | free(blacklist->entries); 227 | blacklist->entries = NULL; 228 | if (blacklist->regexp_list) 229 | { 230 | zend_regexp_list *temp, *it = blacklist->regexp_list; 231 | while (it) 232 | { 233 | pcre_free(it->re); 234 | temp = it; 235 | it = it->next; 236 | free(temp); 237 | } 238 | } 239 | } 240 | 241 | static inline void zend_accel_blacklist_allocate(zend_blacklist *blacklist) 242 | { 243 | if (blacklist->pos == blacklist->size) 244 | { 245 | blacklist->size += ZEND_BLACKLIST_BLOCK_SIZE; 246 | blacklist->entries = (zend_blacklist_entry *)realloc(blacklist->entries, sizeof(zend_blacklist_entry) * blacklist->size); 247 | } 248 | } 249 | 250 | #ifdef HAVE_GLOB 251 | static void zend_accel_blacklist_loadone(zend_blacklist *blacklist, char *filename) 252 | #else 253 | void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename) 254 | #endif 255 | { 256 | char buf[MAXPATHLEN + 1], real_path[MAXPATHLEN + 1], *blacklist_path = NULL; 257 | FILE *fp; 258 | int path_length, blacklist_path_length; 259 | 260 | if ((fp = fopen(filename, "r")) == NULL) 261 | { 262 | zend_accel_error(ACCEL_LOG_WARNING, "Cannot load blacklist file: %s\n", filename); 263 | return; 264 | } 265 | 266 | zend_accel_error(ACCEL_LOG_DEBUG, "Loading blacklist file: '%s'", filename); 267 | 268 | if (VCWD_REALPATH(filename, buf)) 269 | { 270 | blacklist_path_length = zend_dirname(buf, strlen(buf)); 271 | blacklist_path = zend_strndup(buf, blacklist_path_length); 272 | } 273 | 274 | memset(buf, 0, sizeof(buf)); 275 | memset(real_path, 0, sizeof(real_path)); 276 | 277 | while (fgets(buf, MAXPATHLEN, fp) != NULL) 278 | { 279 | char *path_dup, *pbuf; 280 | path_length = strlen(buf); 281 | if (path_length > 0 && buf[path_length - 1] == '\n') 282 | { 283 | buf[--path_length] = 0; 284 | if (path_length > 0 && buf[path_length - 1] == '\r') 285 | { 286 | buf[--path_length] = 0; 287 | } 288 | } 289 | 290 | /* Strip ctrl-m prefix */ 291 | pbuf = &buf[0]; 292 | while (*pbuf == '\r') 293 | { 294 | *pbuf++ = 0; 295 | path_length--; 296 | } 297 | 298 | /* strip \" */ 299 | if (pbuf[0] == '\"' && pbuf[path_length - 1] == '\"') 300 | { 301 | *pbuf++ = 0; 302 | path_length -= 2; 303 | } 304 | 305 | if (path_length == 0) 306 | { 307 | continue; 308 | } 309 | 310 | /* skip comments */ 311 | if (pbuf[0] == ';') 312 | { 313 | continue; 314 | } 315 | 316 | path_dup = zend_strndup(pbuf, path_length); 317 | if (blacklist_path) 318 | { 319 | expand_filepath_ex(path_dup, real_path, blacklist_path, blacklist_path_length); 320 | } 321 | else 322 | { 323 | expand_filepath(path_dup, real_path); 324 | } 325 | path_length = strlen(real_path); 326 | 327 | free(path_dup); 328 | 329 | zend_accel_blacklist_allocate(blacklist); 330 | blacklist->entries[blacklist->pos].path_length = path_length; 331 | blacklist->entries[blacklist->pos].path = (char *)malloc(path_length + 1); 332 | if (!blacklist->entries[blacklist->pos].path) 333 | { 334 | zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n"); 335 | fclose(fp); 336 | return; 337 | } 338 | blacklist->entries[blacklist->pos].id = blacklist->pos; 339 | memcpy(blacklist->entries[blacklist->pos].path, real_path, path_length + 1); 340 | blacklist->pos++; 341 | } 342 | fclose(fp); 343 | if (blacklist_path) 344 | { 345 | free(blacklist_path); 346 | } 347 | zend_accel_blacklist_update_regexp(blacklist); 348 | } 349 | 350 | #ifdef HAVE_GLOB 351 | void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename) 352 | { 353 | glob_t globbuf; 354 | int ret; 355 | unsigned int i; 356 | 357 | memset(&globbuf, 0, sizeof(glob_t)); 358 | 359 | ret = glob(filename, 0, NULL, &globbuf); 360 | #ifdef GLOB_NOMATCH 361 | if (ret == GLOB_NOMATCH || !globbuf.gl_pathc) 362 | { 363 | #else 364 | if (!globbuf.gl_pathc) 365 | { 366 | #endif 367 | zend_accel_error(ACCEL_LOG_WARNING, "No blacklist file found matching: %s\n", filename); 368 | } 369 | else 370 | { 371 | for (i = 0; i < globbuf.gl_pathc; i++) 372 | { 373 | zend_accel_blacklist_loadone(blacklist, globbuf.gl_pathv[i]); 374 | } 375 | globfree(&globbuf); 376 | } 377 | } 378 | #endif 379 | 380 | zend_bool zend_accel_blacklist_is_blacklisted(zend_blacklist *blacklist, char *verify_path) 381 | { 382 | int ret = 0; 383 | zend_regexp_list *regexp_list_it = blacklist->regexp_list; 384 | 385 | if (regexp_list_it == NULL) 386 | { 387 | return 0; 388 | } 389 | while (regexp_list_it != NULL) 390 | { 391 | if (pcre_exec(regexp_list_it->re, NULL, verify_path, strlen(verify_path), 0, 0, NULL, 0) >= 0) 392 | { 393 | ret = 1; 394 | break; 395 | } 396 | regexp_list_it = regexp_list_it->next; 397 | } 398 | return ret; 399 | } 400 | 401 | void zend_accel_blacklist_apply(zend_blacklist *blacklist, blacklist_apply_func_arg_t func, void *argument) 402 | { 403 | int i; 404 | 405 | for (i = 0; i < blacklist->pos; i++) 406 | { 407 | func(&blacklist->entries[i], argument); 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /ZendAccelerator.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | ScrewOpcode | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Andi Gutmans | 16 | | Zeev Suraski | 17 | | Stanislav Malyshev | 18 | | Dmitry Stogov | 19 | +----------------------------------------------------------------------+ 20 | */ 21 | 22 | #ifndef ZEND_ACCELERATOR_H 23 | #define ZEND_ACCELERATOR_H 24 | 25 | #ifdef HAVE_CONFIG_H 26 | #include 27 | #endif 28 | 29 | #define ACCELERATOR_PRODUCT_NAME "ScrewOpcode" 30 | /* 2 - added Profiler support, on 20010712 */ 31 | /* 3 - added support for Optimizer's encoded-only-files mode */ 32 | /* 4 - works with the new Optimizer, that supports the file format with licenses */ 33 | /* 5 - API 4 didn't really work with the license-enabled file format. v5 does. */ 34 | /* 6 - Monitor was removed from ZendPlatform.so, to a module of its own */ 35 | /* 7 - Optimizer was embedded into Accelerator */ 36 | /* 8 - Standalone Open Source ScrewOpcode */ 37 | #define ACCELERATOR_API_NO 8 38 | 39 | #if ZEND_WIN32 40 | #include "zend_config.w32.h" 41 | #else 42 | #include "zend_config.h" 43 | #include 44 | #include 45 | #endif 46 | 47 | #if HAVE_UNISTD_H 48 | #include "unistd.h" 49 | #endif 50 | 51 | #include "zend_extensions.h" 52 | #include "zend_compile.h" 53 | 54 | #include "Optimizer/zend_optimizer.h" 55 | #include "zend_accelerator_hash.h" 56 | #include "zend_accelerator_debug.h" 57 | 58 | #ifndef PHPAPI 59 | #ifdef ZEND_WIN32 60 | #define PHPAPI __declspec(dllimport) 61 | #else 62 | #define PHPAPI 63 | #endif 64 | #endif 65 | 66 | #ifndef ZEND_EXT_API 67 | #if WIN32 | WINNT 68 | #define ZEND_EXT_API __declspec(dllexport) 69 | #elif defined(__GNUC__) && __GNUC__ >= 4 70 | #define ZEND_EXT_API __attribute__((visibility("default"))) 71 | #else 72 | #define ZEND_EXT_API 73 | #endif 74 | #endif 75 | 76 | #ifdef ZEND_WIN32 77 | #ifndef MAXPATHLEN 78 | #include "win32/ioutil.h" 79 | #define MAXPATHLEN PHP_WIN32_IOUTIL_MAXPATHLEN 80 | #endif 81 | #include 82 | #else 83 | #ifndef MAXPATHLEN 84 | #define MAXPATHLEN 4096 85 | #endif 86 | #include 87 | #endif 88 | 89 | /*** file locking ***/ 90 | #ifndef ZEND_WIN32 91 | extern int lock_file; 92 | 93 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || (defined(__APPLE__) && defined(__MACH__) /* Darwin */) || defined(__OpenBSD__) || defined(__NetBSD__) 94 | #define FLOCK_STRUCTURE(name, type, whence, start, len) \ 95 | struct flock name = {start, len, -1, type, whence} 96 | #elif defined(__svr4__) 97 | #define FLOCK_STRUCTURE(name, type, whence, start, len) \ 98 | struct flock name = {type, whence, start, len} 99 | #elif defined(__linux__) || defined(__hpux) || defined(__GNU__) 100 | #define FLOCK_STRUCTURE(name, type, whence, start, len) \ 101 | struct flock name = {type, whence, start, len, 0} 102 | #elif defined(_AIX) 103 | #if defined(_LARGE_FILES) || defined(__64BIT__) 104 | #define FLOCK_STRUCTURE(name, type, whence, start, len) \ 105 | struct flock name = {type, whence, 0, 0, 0, start, len} 106 | #else 107 | #define FLOCK_STRUCTURE(name, type, whence, start, len) \ 108 | struct flock name = {type, whence, start, len} 109 | #endif 110 | #elif defined(HAVE_FLOCK_BSD) 111 | #define FLOCK_STRUCTURE(name, type, whence, start, len) \ 112 | struct flock name = {start, len, -1, type, whence} 113 | #elif defined(HAVE_FLOCK_LINUX) 114 | #define FLOCK_STRUCTURE(name, type, whence, start, len) \ 115 | struct flock name = {type, whence, start, len} 116 | #else 117 | #error "Don't know how to define struct flock" 118 | #endif 119 | #endif 120 | 121 | #if defined(HAVE_OPCACHE_FILE_CACHE) && defined(ZEND_WIN32) 122 | #define ENABLE_FILE_CACHE_FALLBACK 1 123 | #else 124 | #define ENABLE_FILE_CACHE_FALLBACK 0 125 | #endif 126 | 127 | #if ZEND_WIN32 128 | typedef unsigned __int64 accel_time_t; 129 | #else 130 | typedef time_t accel_time_t; 131 | #endif 132 | 133 | typedef enum _zend_accel_restart_reason 134 | { 135 | ACCEL_RESTART_OOM, /* restart because of out of memory */ 136 | ACCEL_RESTART_HASH, /* restart because of hash overflow */ 137 | ACCEL_RESTART_USER /* restart scheduled by screwopcode_reset() */ 138 | } zend_accel_restart_reason; 139 | 140 | typedef struct _zend_persistent_script 141 | { 142 | zend_script script; 143 | zend_long compiler_halt_offset; /* position of __HALT_COMPILER or -1 */ 144 | int ping_auto_globals_mask; /* which autoglobals are used by the script */ 145 | accel_time_t timestamp; /* the script modification time */ 146 | zend_bool corrupted; 147 | zend_bool is_phar; 148 | 149 | void *mem; /* shared memory area used by script structures */ 150 | size_t size; /* size of used shared memory */ 151 | void *arena_mem; /* part that should be copied into process */ 152 | size_t arena_size; 153 | 154 | /* All entries that shouldn't be counted in the ADLER32 155 | * checksum must be declared in this struct 156 | */ 157 | struct zend_persistent_script_dynamic_members 158 | { 159 | time_t last_used; 160 | #ifdef ZEND_WIN32 161 | LONGLONG hits; 162 | #else 163 | zend_ulong hits; 164 | #endif 165 | unsigned int memory_consumption; 166 | unsigned int checksum; 167 | time_t revalidate; 168 | } dynamic_members; 169 | } zend_persistent_script; 170 | 171 | typedef struct _zend_accel_directives 172 | { 173 | zend_long memory_consumption; 174 | zend_long max_accelerated_files; 175 | double max_wasted_percentage; 176 | char *user_blacklist_filename; 177 | zend_long consistency_checks; 178 | zend_long force_restart_timeout; 179 | zend_bool use_cwd; 180 | zend_bool ignore_dups; 181 | zend_bool validate_timestamps; 182 | zend_bool revalidate_path; 183 | zend_bool save_comments; 184 | zend_bool protect_memory; 185 | zend_bool file_override_enabled; 186 | zend_bool inherited_hack; 187 | zend_bool enable_cli; 188 | zend_bool validate_permission; 189 | #ifndef ZEND_WIN32 190 | zend_bool validate_root; 191 | #endif 192 | zend_ulong revalidate_freq; 193 | zend_ulong file_update_protection; 194 | char *error_log; 195 | #ifdef ZEND_WIN32 196 | char *mmap_base; 197 | #endif 198 | char *memory_model; 199 | zend_long log_verbosity_level; 200 | 201 | zend_long optimization_level; 202 | zend_long opt_debug_level; 203 | zend_long max_file_size; 204 | zend_long interned_strings_buffer; 205 | char *restrict_api; 206 | #ifndef ZEND_WIN32 207 | char *lockfile_path; 208 | #endif 209 | #ifdef HAVE_OPCACHE_FILE_CACHE 210 | char *file_cache; 211 | zend_bool file_cache_only; 212 | zend_bool file_cache_consistency_checks; 213 | #endif 214 | #if ENABLE_FILE_CACHE_FALLBACK 215 | zend_bool file_cache_fallback; 216 | #endif 217 | #ifdef HAVE_HUGE_CODE_PAGES 218 | zend_bool huge_code_pages; 219 | #endif 220 | } zend_accel_directives; 221 | 222 | typedef struct _zend_accel_globals 223 | { 224 | /* copy of CG(function_table) used for compilation scripts into cache */ 225 | /* initially it contains only internal functions */ 226 | HashTable function_table; 227 | int internal_functions_count; 228 | int counted; /* the process uses shared memory */ 229 | zend_bool enabled; 230 | zend_bool locked; /* thread obtained exclusive lock */ 231 | HashTable bind_hash; /* prototype and zval lookup table */ 232 | zend_accel_directives accel_directives; 233 | zend_string *cwd; /* current working directory or NULL */ 234 | zend_string *include_path; /* current value of "include_path" directive */ 235 | char include_path_key[32]; /* key of current "include_path" */ 236 | char cwd_key[32]; /* key of current working directory */ 237 | int include_path_key_len; 238 | int include_path_check; 239 | int cwd_key_len; 240 | int cwd_check; 241 | int auto_globals_mask; 242 | time_t request_time; 243 | time_t last_restart_time; /* used to synchronize SHM and in-process caches */ 244 | char system_id[32]; 245 | HashTable xlat_table; 246 | #ifndef ZEND_WIN32 247 | zend_ulong root_hash; 248 | #endif 249 | /* preallocated shared-memory block to save current script */ 250 | void *mem; 251 | void *arena_mem; 252 | zend_persistent_script *current_persistent_script; 253 | /* cache to save hash lookup on the same INCLUDE opcode */ 254 | const zend_op *cache_opline; 255 | zend_persistent_script *cache_persistent_script; 256 | /* preallocated buffer for keys */ 257 | int key_len; 258 | char key[MAXPATHLEN * 8]; 259 | } zend_accel_globals; 260 | 261 | typedef struct _zend_accel_shared_globals 262 | { 263 | /* Cache Data Structures */ 264 | zend_ulong hits; 265 | zend_ulong misses; 266 | zend_ulong blacklist_misses; 267 | zend_ulong oom_restarts; /* number of restarts because of out of memory */ 268 | zend_ulong hash_restarts; /* number of restarts because of hash overflow */ 269 | zend_ulong manual_restarts; /* number of restarts scheduled by screwopcode_reset() */ 270 | zend_accel_hash hash; /* hash table for cached scripts */ 271 | 272 | /* Directives & Maintenance */ 273 | time_t start_time; 274 | time_t last_restart_time; 275 | time_t force_restart_time; 276 | zend_bool accelerator_enabled; 277 | zend_bool restart_pending; 278 | zend_accel_restart_reason restart_reason; 279 | zend_bool cache_status_before_restart; 280 | #ifdef ZEND_WIN32 281 | LONGLONG mem_usage; 282 | LONGLONG restart_in; 283 | #endif 284 | zend_bool restart_in_progress; 285 | /* Interned Strings Support */ 286 | char *interned_strings_start; 287 | char *interned_strings_top; 288 | char *interned_strings_end; 289 | char *interned_strings_saved_top; 290 | HashTable interned_strings; 291 | /* uninitialized HashTable Support */ 292 | uint32_t uninitialized_bucket[-HT_MIN_MASK]; 293 | } zend_accel_shared_globals; 294 | 295 | extern zend_bool accel_startup_ok; 296 | #ifdef HAVE_OPCACHE_FILE_CACHE 297 | extern zend_bool file_cache_only; 298 | #endif 299 | #if ENABLE_FILE_CACHE_FALLBACK 300 | extern zend_bool fallback_process; 301 | #endif 302 | 303 | extern zend_accel_shared_globals *accel_shared_globals; 304 | #define ZCSG(element) (accel_shared_globals->element) 305 | 306 | #ifdef ZTS 307 | #define ZCG(v) ZEND_TSRMG(accel_globals_id, zend_accel_globals *, v) 308 | extern int accel_globals_id; 309 | #ifdef COMPILE_DL_OPCACHE 310 | ZEND_TSRMLS_CACHE_EXTERN() 311 | #endif 312 | #else 313 | #define ZCG(v) (accel_globals.v) 314 | extern zend_accel_globals accel_globals; 315 | #endif 316 | 317 | extern char *zps_api_failure_reason; 318 | 319 | void accel_shutdown(void); 320 | int accel_post_deactivate(void); 321 | void zend_accel_schedule_restart(zend_accel_restart_reason reason); 322 | void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason); 323 | accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size); 324 | int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle); 325 | int validate_timestamp_and_record_ex(zend_persistent_script *persistent_script, zend_file_handle *file_handle); 326 | int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force); 327 | int accelerator_shm_read_lock(void); 328 | void accelerator_shm_read_unlock(void); 329 | 330 | char *accel_make_persistent_key(const char *path, int path_length, int *key_len); 331 | zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type); 332 | 333 | #define IS_ACCEL_INTERNED(str) \ 334 | ((char *)(str) >= ZCSG(interned_strings_start) && (char *)(str) < ZCSG(interned_strings_end)) 335 | 336 | zend_string *accel_new_interned_string(zend_string *str); 337 | 338 | #endif /* ZEND_ACCELERATOR_H */ 339 | -------------------------------------------------------------------------------- /Optimizer/zend_ssa.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Zend Engine, SSA - Static Single Assignment Form | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1998-2018 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Dmitry Stogov | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef ZEND_SSA_H 20 | #define ZEND_SSA_H 21 | 22 | #include "zend_optimizer.h" 23 | #include "zend_cfg.h" 24 | 25 | typedef struct _zend_ssa_range { 26 | zend_long min; 27 | zend_long max; 28 | zend_bool underflow; 29 | zend_bool overflow; 30 | } zend_ssa_range; 31 | 32 | typedef enum _zend_ssa_negative_lat { 33 | NEG_NONE = 0, 34 | NEG_INIT = 1, 35 | NEG_INVARIANT = 2, 36 | NEG_USE_LT = 3, 37 | NEG_USE_GT = 4, 38 | NEG_UNKNOWN = 5 39 | } zend_ssa_negative_lat; 40 | 41 | /* Special kind of SSA Phi function used in eSSA */ 42 | typedef struct _zend_ssa_range_constraint { 43 | zend_ssa_range range; /* simple range constraint */ 44 | int min_var; 45 | int max_var; 46 | int min_ssa_var; /* ((min_var>0) ? MIN(ssa_var) : 0) + range.min */ 47 | int max_ssa_var; /* ((max_var>0) ? MAX(ssa_var) : 0) + range.max */ 48 | zend_ssa_negative_lat negative; 49 | } zend_ssa_range_constraint; 50 | 51 | typedef struct _zend_ssa_type_constraint { 52 | uint32_t type_mask; /* Type mask to intersect with */ 53 | zend_class_entry *ce; /* Class entry for instanceof constraints */ 54 | } zend_ssa_type_constraint; 55 | 56 | typedef union _zend_ssa_pi_constraint { 57 | zend_ssa_range_constraint range; 58 | zend_ssa_type_constraint type; 59 | } zend_ssa_pi_constraint; 60 | 61 | /* SSA Phi - ssa_var = Phi(source0, source1, ...sourceN) */ 62 | typedef struct _zend_ssa_phi zend_ssa_phi; 63 | struct _zend_ssa_phi { 64 | zend_ssa_phi *next; /* next Phi in the same BB */ 65 | int pi; /* if >= 0 this is actually a e-SSA Pi */ 66 | zend_ssa_pi_constraint constraint; /* e-SSA Pi constraint */ 67 | int var; /* Original CV, VAR or TMP variable index */ 68 | int ssa_var; /* SSA variable index */ 69 | int block; /* current BB index */ 70 | int visited : 1; /* flag to avoid recursive processing */ 71 | int has_range_constraint : 1; 72 | zend_ssa_phi **use_chains; 73 | zend_ssa_phi *sym_use_chain; 74 | int *sources; /* Array of SSA IDs that produce this var. 75 | As many as this block has 76 | predecessors. */ 77 | }; 78 | 79 | typedef struct _zend_ssa_block { 80 | zend_ssa_phi *phis; 81 | } zend_ssa_block; 82 | 83 | typedef struct _zend_ssa_op { 84 | int op1_use; 85 | int op2_use; 86 | int result_use; 87 | int op1_def; 88 | int op2_def; 89 | int result_def; 90 | int op1_use_chain; 91 | int op2_use_chain; 92 | int res_use_chain; 93 | } zend_ssa_op; 94 | 95 | typedef enum _zend_ssa_alias_kind { 96 | NO_ALIAS, 97 | SYMTABLE_ALIAS, 98 | PHP_ERRORMSG_ALIAS, 99 | HTTP_RESPONSE_HEADER_ALIAS 100 | } zend_ssa_alias_kind; 101 | 102 | typedef struct _zend_ssa_var { 103 | int var; /* original var number; op.var for CVs and following numbers for VARs and TMP_VARs */ 104 | int scc; /* strongly connected component */ 105 | int definition; /* opcode that defines this value */ 106 | zend_ssa_phi *definition_phi; /* phi that defines this value */ 107 | int use_chain; /* uses of this value, linked through opN_use_chain */ 108 | zend_ssa_phi *phi_use_chain; /* uses of this value in Phi, linked through use_chain */ 109 | zend_ssa_phi *sym_use_chain; /* uses of this value in Pi constaints */ 110 | unsigned int no_val : 1; /* value doesn't mater (used as op1 in ZEND_ASSIGN) */ 111 | unsigned int scc_entry : 1; 112 | unsigned int alias : 2; /* value may be changed indirectly */ 113 | } zend_ssa_var; 114 | 115 | typedef struct _zend_ssa_var_info { 116 | uint32_t type; /* inferred type (see zend_inference.h) */ 117 | zend_ssa_range range; 118 | zend_class_entry *ce; 119 | unsigned int has_range : 1; 120 | unsigned int is_instanceof : 1; /* 0 - class == "ce", 1 - may be child of "ce" */ 121 | unsigned int recursive : 1; 122 | unsigned int use_as_double : 1; 123 | } zend_ssa_var_info; 124 | 125 | typedef struct _zend_ssa { 126 | zend_cfg cfg; /* control flow graph */ 127 | int rt_constants; /* run-time or compile-time */ 128 | int vars_count; /* number of SSA variables */ 129 | zend_ssa_block *blocks; /* array of SSA blocks */ 130 | zend_ssa_op *ops; /* array of SSA instructions */ 131 | zend_ssa_var *vars; /* use/def chain of SSA variables */ 132 | int sccs; /* number of SCCs */ 133 | zend_ssa_var_info *var_info; 134 | } zend_ssa; 135 | 136 | BEGIN_EXTERN_C() 137 | 138 | int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags); 139 | int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa); 140 | int zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var); 141 | 142 | void zend_ssa_remove_predecessor(zend_ssa *ssa, int from, int to); 143 | void zend_ssa_remove_instr(zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op); 144 | void zend_ssa_remove_phi(zend_ssa *ssa, zend_ssa_phi *phi); 145 | void zend_ssa_remove_uses_of_var(zend_ssa *ssa, int var_num); 146 | void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int b); 147 | void zend_ssa_rename_var_uses(zend_ssa *ssa, int old_var, int new_var, zend_bool update_types); 148 | 149 | static zend_always_inline void _zend_ssa_remove_def(zend_ssa_var *var) 150 | { 151 | ZEND_ASSERT(var->definition >= 0); 152 | ZEND_ASSERT(var->use_chain < 0); 153 | ZEND_ASSERT(!var->phi_use_chain); 154 | var->definition = -1; 155 | } 156 | 157 | static zend_always_inline void zend_ssa_remove_result_def(zend_ssa *ssa, zend_ssa_op *ssa_op) 158 | { 159 | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; 160 | _zend_ssa_remove_def(var); 161 | ssa_op->result_def = -1; 162 | } 163 | 164 | static zend_always_inline void zend_ssa_remove_op1_def(zend_ssa *ssa, zend_ssa_op *ssa_op) 165 | { 166 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; 167 | _zend_ssa_remove_def(var); 168 | ssa_op->op1_def = -1; 169 | } 170 | 171 | static zend_always_inline void zend_ssa_remove_op2_def(zend_ssa *ssa, zend_ssa_op *ssa_op) 172 | { 173 | zend_ssa_var *var = &ssa->vars[ssa_op->op2_def]; 174 | _zend_ssa_remove_def(var); 175 | ssa_op->op2_def = -1; 176 | } 177 | 178 | END_EXTERN_C() 179 | 180 | static zend_always_inline int zend_ssa_next_use(const zend_ssa_op *ssa_op, int var, int use) 181 | { 182 | ssa_op += use; 183 | if (ssa_op->op1_use == var) { 184 | return ssa_op->op1_use_chain; 185 | } else if (ssa_op->op2_use == var) { 186 | return ssa_op->op2_use_chain; 187 | } else { 188 | return ssa_op->res_use_chain; 189 | } 190 | } 191 | 192 | static zend_always_inline zend_ssa_phi* zend_ssa_next_use_phi(const zend_ssa *ssa, int var, const zend_ssa_phi *p) 193 | { 194 | if (p->pi >= 0) { 195 | return p->use_chains[0]; 196 | } else { 197 | int j; 198 | for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { 199 | if (p->sources[j] == var) { 200 | return p->use_chains[j]; 201 | } 202 | } 203 | } 204 | return NULL; 205 | } 206 | 207 | static zend_always_inline zend_bool zend_ssa_is_no_val_use(const zend_op *opline, const zend_ssa_op *ssa_op, int var) 208 | { 209 | if (opline->opcode == ZEND_ASSIGN || opline->opcode == ZEND_UNSET_CV) { 210 | return ssa_op->op1_use == var && ssa_op->op2_use != var; 211 | } 212 | if (opline->opcode == ZEND_FE_FETCH_R) { 213 | return ssa_op->op2_use == var && ssa_op->op1_use != var; 214 | } 215 | if (ssa_op->result_use == var && opline->opcode != ZEND_ADD_ARRAY_ELEMENT) { 216 | return ssa_op->op1_use != var && ssa_op->op2_use != var; 217 | } 218 | return 0; 219 | } 220 | 221 | static zend_always_inline void zend_ssa_rename_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op) { 222 | /* Rename def to use if possible. Mark variable as not defined otherwise. */ 223 | if (ssa_op->op1_def >= 0) { 224 | if (ssa_op->op1_use >= 0) { 225 | zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, ssa_op->op1_use, 1); 226 | } 227 | ssa->vars[ssa_op->op1_def].definition = -1; 228 | ssa_op->op1_def = -1; 229 | } 230 | if (ssa_op->op2_def >= 0) { 231 | if (ssa_op->op2_use >= 0) { 232 | zend_ssa_rename_var_uses(ssa, ssa_op->op2_def, ssa_op->op2_use, 1); 233 | } 234 | ssa->vars[ssa_op->op2_def].definition = -1; 235 | ssa_op->op2_def = -1; 236 | } 237 | if (ssa_op->result_def >= 0) { 238 | if (ssa_op->result_use >= 0) { 239 | zend_ssa_rename_var_uses(ssa, ssa_op->result_def, ssa_op->result_use, 1); 240 | } 241 | ssa->vars[ssa_op->result_def].definition = -1; 242 | ssa_op->result_def = -1; 243 | } 244 | } 245 | 246 | #define NUM_PHI_SOURCES(phi) \ 247 | ((phi)->pi >= 0 ? 1 : (ssa->cfg.blocks[(phi)->block].predecessors_count)) 248 | 249 | /* FOREACH_USE and FOREACH_PHI_USE explicitly support "continue" 250 | * and changing the use chain of the current element */ 251 | #define FOREACH_USE(var, use) do { \ 252 | int _var_num = (var) - ssa->vars, next; \ 253 | for (use = (var)->use_chain; use >= 0; use = next) { \ 254 | next = zend_ssa_next_use(ssa->ops, _var_num, use); 255 | #define FOREACH_USE_END() \ 256 | } \ 257 | } while (0) 258 | 259 | #define FOREACH_PHI_USE(var, phi) do { \ 260 | int _var_num = (var) - ssa->vars; \ 261 | zend_ssa_phi *next_phi; \ 262 | for (phi = (var)->phi_use_chain; phi; phi = next_phi) { \ 263 | next_phi = zend_ssa_next_use_phi(ssa, _var_num, phi); 264 | #define FOREACH_PHI_USE_END() \ 265 | } \ 266 | } while (0) 267 | 268 | #define FOREACH_PHI_SOURCE(phi, source) do { \ 269 | zend_ssa_phi *_phi = (phi); \ 270 | int _i, _end = NUM_PHI_SOURCES(phi); \ 271 | for (_i = 0; _i < _end; _i++) { \ 272 | ZEND_ASSERT(_phi->sources[_i] >= 0); \ 273 | source = _phi->sources[_i]; 274 | #define FOREACH_PHI_SOURCE_END() \ 275 | } \ 276 | } while (0) 277 | 278 | #define FOREACH_PHI(phi) do { \ 279 | int _i; \ 280 | for (_i = 0; _i < ssa->cfg.blocks_count; _i++) { \ 281 | phi = ssa->blocks[_i].phis; \ 282 | for (; phi; phi = phi->next) { 283 | #define FOREACH_PHI_END() \ 284 | } \ 285 | } \ 286 | } while (0) 287 | 288 | #define FOREACH_BLOCK(block) do { \ 289 | int _i; \ 290 | for (_i = 0; _i < ssa->cfg.blocks_count; _i++) { \ 291 | (block) = &ssa->cfg.blocks[_i]; \ 292 | if (!((block)->flags & ZEND_BB_REACHABLE)) { \ 293 | continue; \ 294 | } 295 | #define FOREACH_BLOCK_END() \ 296 | } \ 297 | } while (0) 298 | 299 | /* Does not support "break" */ 300 | #define FOREACH_INSTR_NUM(i) do { \ 301 | zend_basic_block *_block; \ 302 | FOREACH_BLOCK(_block) { \ 303 | uint32_t _end = _block->start + _block->len; \ 304 | for ((i) = _block->start; (i) < _end; (i)++) { 305 | #define FOREACH_INSTR_NUM_END() \ 306 | } \ 307 | } FOREACH_BLOCK_END(); \ 308 | } while (0) 309 | 310 | #endif /* ZEND_SSA_H */ 311 | 312 | /* 313 | * Local variables: 314 | * tab-width: 4 315 | * c-basic-offset: 4 316 | * indent-tabs-mode: t 317 | * End: 318 | */ 319 | --------------------------------------------------------------------------------